what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Indexed Blind SQL Injection

Indexed Blind SQL Injection
Posted Dec 3, 2011
Authored by gamma95

Whitepaper called Indexed Blind SQL Injection. Time based blind SQL attacks suffer from low bit/request ratios. Each request produces only one valuable bit of information. This paper describes a tweak that produces higher yield at the expense of a longer runtime. Along the way, some issues and notes of applicability are also discussed.

tags | paper, sql injection
SHA-256 | 84e74daa46ea6185f1c1f4ee9764bc2315f2a4cf39e46f8dfcea99039a5ecb21

Indexed Blind SQL Injection

Change Mirror Download
Indexed blind SQL injection

:Author: gamma95 <gamma95 [at] gmail> 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.


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,6,7,8,9,.'));
1 row in set (10.00 sec)
# index 10, value '5'

We can also sprinkle invalid characters in between valid characters to manually adjust amount of sleeping time.

Picking an acceptable domain

The set of possible values should be carefully picked to match the value that one expects. Wide domain (more values) has a better chance of catching the input, but it requires a longer sleep time on average. Narrow domain (less values) has slimmer chance to catch the input, but it generally finishes faster on average.

Some web frameworks enforce a maximum execution time. A query that takes more than, say, 30 seconds will be prime target for an early termination (and possibly logging). Therefore, picking out an acceptable domain is not only an optimization but sometimes a necessity.

Using other functions

``find_in_set`` is only one of the string search functions that MySQL supports. One can also use other functions such as ``instr``, ``locate``, and ``position``.

Sleeping in ``WHERE`` clause

Most of the time, the injection point is in a ``WHERE`` clause. Because the ``WHERE`` clause is tested against all candidate rows, we better make sure that there is only **one** candidate. We can do that by making sure the table scan produces one row. Otherwise, our sleep measure will be multiplied up by the number of candidates.


create table test (a int primary key, b char(16));
insert into test values(1, 'abcd');
insert into test values(2, 'zyxw');

select count(*) from test;
| count(*) |
| 2 |
# we have 2 rows in table test

select * from test where sleep(locate(mid(@@version, 1, 1), '0123456789.'));
Empty set (12.00 sec)
# here we sleep for 12 seconds because all (2) rows are tested

select * from test where a=1 and sleep(locate(mid(@@version, 1, 1), '0123456789.'));
Empty set (6.00 sec)
# here we sleep for 6 seconds because only one row is tested


This paper described a small tweak to the well-known time based SQL injection technique. The principle behind the increase in bit/request ratio is encoding more information in the query execution time. This is done with index based array search functions such as ``find_in_set``. The desirably smaller number of requests comes at the expense of generally longer execution time.

This paper also discussed about some technical concerns that one must pay close attention to when employing the technique. Minute aspects such as table scan, applicable value domain, network latency, and amount of sleep time are at the top list to watch out for.


Thanks go to Nam Nguyen for his early review and support.

Login or Register to add favorites

File Archive:

July 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    27 Files
  • 2
    Jul 2nd
    10 Files
  • 3
    Jul 3rd
    35 Files
  • 4
    Jul 4th
    27 Files
  • 5
    Jul 5th
    18 Files
  • 6
    Jul 6th
    0 Files
  • 7
    Jul 7th
    0 Files
  • 8
    Jul 8th
    28 Files
  • 9
    Jul 9th
    44 Files
  • 10
    Jul 10th
    24 Files
  • 11
    Jul 11th
    25 Files
  • 12
    Jul 12th
    11 Files
  • 13
    Jul 13th
    0 Files
  • 14
    Jul 14th
    0 Files
  • 15
    Jul 15th
    28 Files
  • 16
    Jul 16th
    6 Files
  • 17
    Jul 17th
    0 Files
  • 18
    Jul 18th
    0 Files
  • 19
    Jul 19th
    0 Files
  • 20
    Jul 20th
    0 Files
  • 21
    Jul 21st
    0 Files
  • 22
    Jul 22nd
    0 Files
  • 23
    Jul 23rd
    0 Files
  • 24
    Jul 24th
    0 Files
  • 25
    Jul 25th
    0 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags


packet storm

© 2022 Packet Storm. All rights reserved.

Security Services
Hosting By