OverTheWire Natas Walkthrough (Levels 6-10)

In our previous post, we covered levels 0-5 of OverTheWire’s Natas wargame, which is a great introduction to web security.

This write-up is meant to be for beginners, with lots of links to other resources in case you aren’t familiar with a given tool or concept.

What is Natas?

Natas is an online hacking game meant to help you learn and practice security concepts.

OverTheWire is a website with a number of “war games”, which are online hacking games that allow you to practice security concepts. If you are looking for a beginner introduction to web security (albeit an older tech stack), then Natas is a great place to start.

Natas is hosted on different subdomains following the pattern of http://natas<level#>.natas.labs.overthewire.org. As you progress through the levels, you’ll need to increment the level number in the URL in order to view the correct level.

Each level requires the levels below it to be solved, so you will need the level 6 flag found in level 5 to begin this walkthrough. As before, make sure you keep notes and write down the passwords as you find them!

Level 6 ➔ 7

Head to http://natas6.natas.labs.overthewire.org/ and login with username natas6 and the password shown in level 5. The webpage looks like this:

If we click View Sourcecode, we are taken do a different URL (http://natas6.natas.labs.overthewire.org/index-source.html). The source looks like:

If we tried View Page Source on the original index page, we would not be able to see the same output. This is because the webpage includes PHP. Normally, PHP embedded in a webpage will be executed by the server, meaning that we only see the output, not the code/logic that created that output.

Luckily for us, the original PHP source is provided. We want to focus on this part:

To summarize, it:

  • Includes a file includes/secret.inc
  • Checks if the key “submit” exists in the array of (HTTP) POSTed content
  • Checks if the value associated with the URL-encoded variable “secret” matches the value taken from includes/secret.inc
  • If it matches, grant access and share the password.
  • If not, tell us “Wrong secret”

In previous levels, there were files just strewn across the file system, which we found by browsing directories with directory listing enabled, and also looking at robots.txt.

A good developer shouldn’t include secrets and other sensitive files in places that are publicly accessible. But that doesn’t mean it doesn’t happen.

Let’s try navigating to the includes/secret.inc file to see if we get lucky.

… yup!

If we revisit the PHP code, the logic looks like this. Note that // denotes the start of a comment in PHP code.

<?
    // Get secret value "FOEIUWGHFEEUHOFUOIU" from includes/secret.inc
    include "includes/secret.inc";

    // if data was submitted in a POST request
    if(array_key_exists("submit", $_POST)) {

        // and if user value equals "FOEIUWGHFEEUHOFUOIU"
        if("FOEIUWGHFEEUHOFUOIU" == $_POST['secret']) {

            // show the password for the next level
            print "Access granted. The password for natas7 is <censored>";
        } else {
            // otherwise, say their answer is wrong
            print "Wrong secret";
        }
    }
?>

Natas Level 6 Solution

Going back to the main page, let’s submit “FOEIUWGHFEEUHOFUOIU” as our secret:

And, access is granted:

If we view this as a curl request, we can see that the data included in the POST request has a secret key and value and a submit key and value.

curl 'http://natas6.natas.labs.overthewire.org/' \
  -H 'Authorization: Basic bmF0YXM2OmFHb1k0cTJEYzZNZ0RxNG9MNFl0b0t0eUFnOVBlSGEx' \
  --data-raw 'secret=FOEIUWGHFEEUHOFUOIU&submit=Submit' 

Takeaway: check for secret files (manually in the case of a CTF, with dirb or a similar tool otherwise) and use source code to your advantage.

Level 7 ➔ 8

Level 7 (http://natas7.natas.labs.overthewire.org/) looks like this:

If we click on About, the web server will append /index.php?page=about to the end of the URL (likewise with home).

If we view the page source, we see this comment in both pages:

If we were to try to visit /etc/natas_webpass/natas8 directly (like we did with the secrets file in the previous level), we get a Not Found response:

How we do load in a page that’s outside of the publicly available web server directory?

This level is a demonstration of a LFI (local file inclusion) vulnerability where the ?page=<value> query string is not being sanitized. This means that a user can provide any location on the filesystem to view those files.

If replace <value> with something made-up (such as http://natas7.natas.labs.overthewire.org/index.php?page=somethingelse), we get an error message:

Error messages are frequently useful for getting a working exploit. You can see that the web server tried (and failed) to open our made-up filename “somethingelse”, and also told us the file path.

From here, we can either use an absolute file path (ex: /etc/passwd) or a relative file path (../../../../etc/passwd)

Natas Level 7 Solution

Let’s use the absolute file path option, and navigate to http://natas7.natas.labs.overthewire.org/index.php?page=/etc/natas_webpass/natas8. This will include the flag file and display it to us

Takeaway: look for opportunities to test for LFI vulnerabilities (when pages are loaded in dynamically).

Level 8 ➔ 9

Open up http://natas8.natas.labs.overthewire.org/ and provide the natas8 username and password (from the last level). Here’s what the level looks like:

Similar to level 6, we have a PHP source file provided to us. Here’s the relevant bit:

The final comparison function is the same structure as level 6, where a “secret” value from our input is compared to the real password:

if(array_key_exists("submit", $_POST)) {
    if(encodeSecret($_POST['secret']) == $encodedSecret) {
        print "Access granted. The password for natas9 is <censored>";
    } else {
        print "Wrong secret";
    }
}
?>

Let’s dig into $encodedSecret next. Looks like they decided to no longer store their passwords in plaintext (smart!). We can still figure the password out though.

First off, the value of $encodedSecret is 3d3d516343746d4d6d6c315669563362.

Then, there’s an encodedSecret function that looks like this:

function encodeSecret($secret) {
    return bin2hex(strrev(base64_encode($secret)));
}

This function will take our input, encode (modify) it, and then compare it to 3d3d516343746d4d6d6c315669563362.

There are three parts to it:

  1. Base64 encode the secret using base64_encode()
  2. Reverse that string using strrev()
  3. Convert that to hexadecimal using bin2hex()

If that’s a string gets encoded, we need to do the opposite to decode it by doing hex2bin(), then strrev(), then base64_decode().

We can do this in PHP, by using an online compiler if you don’t have an easy way to run PHP code locally:

But this doesn’t actually have to be PHP-specific. We can use a tool like CyberChef to abstract the steps we identified away from the actual PHP implementation of those functions. Here’s a link to the CyberChef “recipe” shown below.

Natas Level 8 Solution

Both approaches give us the value “oubWYf2kBq”. If we provide this as the secret key, we get the flag:

Takeaway: write out any reverse engineering steps to understand what is happening in the code. Then use a tool of your choice to find the original value–it doesn’t necessarily to use the original language.

Level 9 ➔ 10

Level 9 starts at http://natas9.natas.labs.overthewire.org/, where we see this view:

If we enter in a search value, we get part of a dictionary list.

We can also enter .* to get all results back.

Once again, we are given the source code for the page:

The important part is

passthru("grep -i $key dictionary.txt");

If we start a Google search for php passthru, we get some interesting suggestions:

If we browse some of the results for php passthru injection, or just the PHP documentation page for passthru, we’ll know that passthru “execute[s] an external program and display[s] raw output”.

The problem with using passthru here is that we can input whatever we want, and the program will execute it.

Our input is the equivalent of

grep -i <absolutely anything we want right here> dictionary.txt

If you have familiarity with Linux command line functionality, you probably know that you can execute commands one after the other using syntax like ; or && between commands.

If we enter in ; ls; the overall command will look like this:

grep -i; ls; dictionary.txt

An equivalent set of commands, written out on separate lines, looks like:

grep -i
ls
dictionary.txt

The first and last commands aren’t valid, but if we try ; ls;, we see that the ls command gets executed just fine:

Natas Level 9 Solution

From there, it took a bit of guessing to figure out where the file was. I decided to try the pattern from level 8 and cat the contents of /etc/natas_webpass/natas9 using the input string ; cat /etc/natas_webpass/natas9;

And there’s our flag!

Takeaway: check for the ability to inject commands or other places where user input is being trusted. If you’re a developer, do not blindly trust user input!

Level 10 ➔ 11

Level 10 (http://natas10.natas.labs.overthewire.org/) continues the theme from the last level. However, they’ve added some filtering. 🙁

If we look at the source code, it’s very similar to what we had before, with the addition of a regex (/[;|&]/) that checks for ;, |, and &.

In short, our previous approach won’t work anymore.

To figure out what to do instead, I read a number of posts about command injection without special characters. These largely focused on how to bypass filters that block specific words/commands, and also how to input whitespaces, if those are filtered out.

There are a number of clever ways to bypass filtering, including base64 encoding something and then decoding it using $(echo <base64 string> | base64 -d) but this involves a banned character (|).

Speaking of whitespaces, we’re able to put in spaces with no issue, so we don’t have to use any of those tricks. It took me a minute to realize, hey, if we don’t have to work to get spaces into our input, that means there’s options I haven’t investigated.

As it turns out, grep supports searching through a whole list of files, and since we can enter in text and spaces, we can use command injection to put another file name ahead of dictionary.txt, like this:

passthru("grep -i <search_value, space, other filename> dictionary.txt");

Natas Level 10 Solution

If we follow the pattern from earlier levels, and look in /etc/natas_webpass/natasX, we can enter in a value of .* as our search value (to accept all strings), then a space, then /etc/natas_webpass/natas10.

Altogether, our input looks like: .* /etc/natas_webpass/natas10.

And that gets us the flag!

Takeaway: always read the man page of the command you’re trying to use!