Nytro Posted May 13, 2011 Report Posted May 13, 2011 Optimized Blind MySQL Injection Data RetrievalPosted on March 31, 2011 by Roberto SalgadoI 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 information_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 tableSELECT MID(table_name,1,1) FROM information_schema.tables LIMIT 1It 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. 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 information_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)); Sursa: Optimized Blind MySQL Injection Data Retrieval Quote