Optimized Blind MySQL Injection Data Retrieval

Optimized Blind MySQL Injection Data Retrieval

Posted on March 31, 2011 by Roberto Salgado

I recently came across a paper titled Faster Blind MySQL Injection Using Bit Shifting by Jelmer de Hen describing a technique that allows the retrieval of data from a MySQL database in only 8 requests per character using bit shifting; this is a slight improvement from the traditional Bisection method. This got me thinking on how information could be extracted from the database in even less amount of requests and after a few hours of fooling around, this is what I came up with.

AND (SELECT @a:=MID(BIN(FIND_IN_SET(MID(table_name,1,1), 'a,b,c,d,e,f
,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,0,1,2,3,4,5,6,7,8,9,_,!,@,#,
$,%,^,&,*,(,),-,+,=,\,,.,",\',~,`,\\,|,{,},[,],:,;, ,')),1,1) FROM in
formation_schema.tables LIMIT 1)=@a AND IF(@a!='',@a,SLEEP(5));

A quick explanation of how this query works and what it does:
It starts off with your basic blind injection, selecting only 1 character at a time from the table

SELECT MID(table_name,1,1) FROM information_schema.tables LIMIT 1

It then uses FIND_IN_SET(), to look for the position of the extracted character in the list. So for example, say the table is CHARACTER_SET, MID("CHARACTER_SET",1,1) = 'C', therefore the returned value for FIND_IN_SET('C', 'a,b,c') would be 3 (case insensitive). We then proceed to use BIN() to convert it to binary, BIN(3) = 11. Now that we've reduced the character to two possibilities, 1 or 0, we only have to check if the result is 1, if not we can assume it's 0. So BIN(3) = 11 would take 3 requests: Is the first digit 1? Yes. Is the second digit 1? Yes. Is the third digit 1? No, there is no third digit, so it triggers the SLEEP() function.

Now we know that CAST(b'11' AS DEC) is 3 and that's the equivalent of 'c' on the list, all in 3 requests! Say your list contained 45 elements, BIN(45) = 101101, still only making the total amount of requests 7 for characters in later position on the list. I'm sure this could be optimized and greatly improved, possibly by removing the need for FIND_IN_SET() and using a more effective function. One idea would be to split the list in two requests, this way you can ensure the length of the binary doesn't grow too big.

Amount of requests per method for "CHARACTER_SET"

Downside:
Query can be a bit longer than normal.
Requires SLEEP() to know when you've reached the end of the binary.

Another possible solution that doesn't require SLEEP(), but would require two different pages (test.php?id=0, test.php?id=1) could be done with something like this:

IF((@a:=MID(BIN(FIND_IN_SET(MID((SELECT table_name FROM info
rmation_schema.tables LIMIT 1),1,1),'a,b,c,d,e,f,g,h,i,j,k,l,
m,n,o,p,q,r,s,t,u,v,w,x,y,z,0,1,2,3,4,5,6,7,8,9,_,!,@,#,$,%,^,&,
*,(,),-,+,=,\,,.,",\',~,`,\\,|,{,},[,],:,;, ')),1,1))!='',@a,0/0);

UPDATE:
Two things I just thought I should point out: This technique doesn't necessarily require FIND_IN_SET(). There are plenty of other similar functions that could be substituted in its place (locate, position, instr, field) just to name a few. Secondly, the use of quotations can be avoided. For example, FIND_IN_SET(0x33, CONCAT_WS(0x2C,0x31,0x32,0x33));


Latest Blog Entries

Panoptic
An overview of Panoptic, an open source penetration testing tool that automates the process of search and retrieval of common log and config files through LFI vulnerabilities.

Special discount code for "Nmap 6: Network Exploration and Security Auditing Cookbook"
PacktPub created a special discount code for our friends from HackerHalted

Mac2WepKey HHG5xx for iPhone
The famous app to obtain the default WiFi passwords for Huawei routers is now available for the iPhone iOS 5.

Latest News

Oct 01, 2013
Websec at DerbyCon 2013
A summary of Websec's participation at DerbyCon 2013 in Louisville, Kentucky.

Sep 16, 2013
Websec's participation at Black Hat, CSI and XCon
Websec is grateful to have been able to participate in the month of August at great conferences such as Black Hat, CSI and XCon.