[Full-disclosure] Indexed blind SQL injection
=== Indexed blind SQL injection === :Author: gamma95 and his minions :Date: December 03, 2011 Time based blind SQL attack suffers from low bit/request ratio. Each request produces only one valuable bit of information. This paper describes a tweak that produces higher yield at the expense of longer runtime. Along the way, some issues and notes of applicability are also discussed. Background ++ Time based blind SQL injection attack is probably the most well-known technique in the planet. The method works by analyzing the time difference in various queries. Because query execution time is a side effect of a query, no visible output is required for this method to succeed. For example, a query could request that the DBMS to sleep for 10 seconds if the first character of the username is ``A``. Usually, time based technique go hand in hand with binary search. Instead of asking if the first character is ``1``, then ``2``, then ``3``, it could partition the possible values into two ranges (say from ``0`` to ``4`` and ``5`` to ``9``) and ask if the first character is less than ``5``. Depending on the result, it picks out the more likely range and repeats the process until there is only one possible value. This effectively puts a logarithmic bound on number of requests to the DBMS. In other words, each request gives us one bit of information. Increasing the usable bit/request ratio +++ Due to low bit/request ratio, an attack attempt usually leaves behind too many requests in access log. This is undesirable. A better approach could be to encode the correct value into query execution time itself. For example, if we know the value is a number from 0 to 9, we could ask DBMS to sleep for that many seconds straight. In this case, one request carries more than 3 bits of usable information. This is the principal idea behind our tweak. Indexed time based attack + To encode more bits into the execution time, we must work with variable numeric delay values. Therefore, we need two things: + A measurable delay interval. Too short the interval and network latency could negatively affect our measurement. Too long the delay will also waste our time. + And its mapping to target values. A delay of one second could mean character ``A`` or it could also mean some other value, depending on the possible domain. These necessitate an array-like index search. Say, if our domain is ten (character) values from ``0`` to ``9``, then we can easily combine them into an array like shown below. :: 1 2 3 4 5 6 7 8 9 10 (index) | | | | | | | | | | v v v v v v v v v v +---+---+---+---+---+---+---+---+---+---+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | (value) +---+---+---+---+---+---+---+---+---+---+ Given a random character, we can tell in one request if it is in this set, and if it is, what specific character it actually is. The way to do that is by delaying query time by the index of the character. If the input character is not in the set, there will be no delay. If it is, its index is determinable from the sleep time. An example ++ Suppose we are trying to grab version information from a **MySQL** server. Possible characters include 0-9 and period. Observe the execution time. :: select sleep(find_in_set(mid(@@version, 1, 1), '0,1,2,3,4,5,6,7,8,9,.')); 1 row in set (6.04 sec) # index 6, value '5' 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) # index 11, value '.' select sleep(find_in_set(mid(@@version, 3, 1), '0,1,2,3,4,5,6,7,8,9,.')); 1 row in set (2.00 sec) # index 2, value '1' ... Each request gives us exactly one character (not bit). Notes of applicability ++ Adjusting sleep time Faster sleep time is easily achievable by multiplying the index with some factor smaller than 1. For example, we can sleep half the time as before:: select sleep(0.5 * find_in_set(mid(@@version, 1, 1), '0,1,2,3,4,5,6,7,8,9,.')); 1 row in set (3.00 sec) # index 6, value '5' Similarly, longer sleep time can use factors greater than 1. Guarding against network latency Time based attack generally works best in a fast and reliable networked environment. Small jitters in latency could skew the measurements and affect end result. However, this technique we are describing here could be modified to support network latency. The idea is that since sleeping time is a calculated number, we could add to it a fixed amount of time for latency, or prepend some invalid characters (such as ``a`` when the domain is 0-9) in the domain set. :: select sleep(find_in_set(mid(@@version, 1, 1), 'a,a,a,a,0,1,2,3,4,5
Re: [Full-disclosure] Indexed blind SQL injection
Hm... What's new? http://websec.ca/blog/view/optimized_blind_sql_injection_data_retrieval http://qwazar.ru/?p=26 [Google translate it] https://rdot.org/forum/showthread.php?p=15425 [Google translate it] On Sat, 3 Dec 2011 08:49:37 -0800, Nam Nguyen wrote: > === > Indexed blind SQL injection > === > > :Author: gamma95 and his minions > :Date: December 03, 2011 > > > Time based blind SQL attack suffers from low bit/request ratio. Each > request produces only one valuable bit of information. This paper > describes a tweak that produces higher yield at the expense of longer > runtime. Along the way, some issues and notes of applicability are > also discussed. > > > Background > ++ > > Time based blind SQL injection attack is probably the most well-known > technique in the planet. The method works by analyzing the time > difference in various queries. Because query execution time is a side > effect of a query, no visible output is required for this method to > succeed. For example, a query could request that the DBMS to sleep > for > 10 seconds if the first character of the username is ``A``. > > Usually, time based technique go hand in hand with binary search. > Instead of asking if the first character is ``1``, then ``2``, then > ``3``, it could partition the possible values into two ranges (say > from ``0`` to ``4`` and ``5`` to ``9``) and ask if the first > character > is less than ``5``. Depending on the result, it picks out the more > likely range and repeats the process until there is only one possible > value. This effectively puts a logarithmic bound on number of > requests > to the DBMS. > > In other words, each request gives us one bit of information. > > > Increasing the usable bit/request ratio > +++ > > Due to low bit/request ratio, an attack attempt usually leaves behind > too many requests in access log. This is undesirable. > > A better approach could be to encode the correct value into query > execution time itself. For example, if we know the value is a number > from 0 to 9, we could ask DBMS to sleep for that many seconds > straight. In this case, one request carries more than 3 bits of > usable > information. > > This is the principal idea behind our tweak. > > > Indexed time based attack > + > > To encode more bits into the execution time, we must work with > variable numeric delay values. Therefore, we need two things: > > + A measurable delay interval. Too short the interval and network > latency could negatively affect our measurement. Too long the delay > will also waste our time. > > + And its mapping to target values. A delay of one second could > mean character ``A`` or it could also mean some other value, > depending > on the possible domain. > > These necessitate an array-like index search. Say, if our domain is > ten (character) values from ``0`` to ``9``, then we can easily > combine > them into an array like shown below. > > :: > >1 2 3 4 5 6 7 8 9 10 (index) >| | | | | | | | | | >v v v v v v v v v v > +---+---+---+---+---+---+---+---+---+---+ > | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | (value) > +---+---+---+---+---+---+---+---+---+---+ > > Given a random character, we can tell in one request if it is in this > set, and if it is, what specific character it actually is. The way to > do that is by delaying query time by the index of the character. If > the input character is not in the set, there will be no delay. If it > is, its index is determinable from the sleep time. > > > An example > ++ > > Suppose we are trying to grab version information from a **MySQL** > server. Possible characters include 0-9 and period. Observe the > execution time. > > :: > > select sleep(find_in_set(mid(@@version, 1, 1), > '0,1,2,3,4,5,6,7,8,9,.')); > 1 row in set (6.04 sec) > # index 6, value '5' > > 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) > # index 11, value '.' > > select sleep(find_in_set(mid(@@version, 3, 1), > '0,1,2,3,4,5,6,7,8,9,.')); > 1 row in set (2.00 sec) > # index 2, value '1' > > ... > > Each request gives us exactly one character (not bit). > > > Notes of applicability > ++ > > Adjusting sleep time > > > Faster sleep time is easily achievable by multiplying the index with > some factor smaller than 1. For example, we can sleep half the time > as > before:: > > select sleep(0.5 * find_in_set(mid(@@version, 1, 1), > '0,1,2,3,4,5,6,7,8,9,.')); > 1 row in set (3.00 sec) > # index 6, value '5' > > Similarly, longer sleep time can use factors greater than 1. > > Guarding against network latency > > > Time based attack generally works best in a fast and reliable > network