####################################################################### Luigi Auriemma Applicazione: Conquest http://www.radscan.com/conquest.html Versioni: <= 8.2a (svn 691) Piattaforme: *nix e Windows Bugs: A] buffer-overflow in metaGetServerList() B] memory corruption through SP_CLIENTSTAT Exploitation: locale e remoto, contro il client Date: 07 Mar 2007 Author: Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org ####################################################################### 1) Introduzione 2) Bugs 3) The Code 4) Fix ####################################################################### =============== 1) Introduzione =============== Conquest e' un gioco multi-player che puo' essere definito come il predecessore di Netrek (http://www.netrek.org). Da notare che su alcune distribuzioni (come Debian) i binari di conquest sono marcati setgid per il gruppo conquest. ####################################################################### ======= 2) Bugs ======= ----------------------------------------- A] buffer-overflow in metaGetServerList() ----------------------------------------- Il client di Conquest ha un opzione (-m) per interrogare il metaserver conquest.radscan.com sul quale sono visibili i server che sono online al momento ma il programma permette anche l'uso di metaserver alternativi specificati dall'utente. La funzione che legge i dati ricevuti dal metaserver e' vulnerabile ad un buffer-overflow che avviene durante l'immagazzinamento dei dati di ogni singolo server in un buffer (buf) di 1024 bytes. Il miglior modo per sfruttare questo bug e' per gli utenti locali che vogliono escalare i propri privilegi guadagnando il gruppo conquest. Allo stesso tempo esiste anche un altro buffer-overflow che riguarda il buffer statico servers limitato a 1000 (META_MAXSERVERS) servers massimi, ad ogni modo non sembra possibile sfruttare questo secondo bug per eseguire codice. da meta.c: int metaGetServerList(char *remotehost, metaSRec_t **srvlist) { static metaSRec_t servers[META_MAXSERVERS]; ... char buf[1024]; /* server buffer */ ... off = 0; while (read(s, &c, 1) > 0) { if (c != '\n') { buf[off++] = c; } else { /* we got one */ buf[off] = 0; /* convert to a metaSRec_t */ if (str2srec(&servers[nums], buf)) nums++; ... ------------------------------------------ B] memory corruption through SP_CLIENTSTAT ------------------------------------------ SP_CLIENTSTAT e' un tipo di pacchetto usato dal server per inviare alcune informazioni riguardo le navi e gli utenti. In questo pacchetto si trovano due numeri che non sono controllati correttamente dal client: - unum: 16 bit, usato per la struttura Users - snum: 8 bit, usato per la struttura Ships Entrambe le strutture si trovano nel buffer cBasePtr allocato all'avvio con 262144 (SIZEOF_COMMONBLOCK) bytes di memoria: Users all'offset 388 dove ogni elemento ha una grandezza di 264 bytes (totale 132000) e Ships all'offset 141040 con 1124 bytes per elemento (totale 23604). In entrambi i casi e' possibile scrivere uno o piu' bytes in alcune zone di memoria al di fuori delle strutture originali e persino del buffer cBasePtr, ma comunque penso che l'esecuzione di codice sia praticamente impossibile... Quelle che seguono sono le funzioni usate per gestire il pacchetto SP_CLIENTSTAT e dove e' facilmente visibile la scrittura del valore scstat->team inviato dal server: case SP_CLIENTSTAT: scstat = (spClientStat_t *)buf; Context.snum = scstat->snum; Context.unum = (int)ntohs(scstat->unum); Ships[Context.snum].team = scstat->team; clientFlags = scstat->flags; break; ####################################################################### =========== 3) The Code =========== A] - lanciare un metaserver fasullo che invii piu' di 1024 caratteri: perl -e 'print "a"x1200' | nc -l -p 1700 -v -v -n - lanciare il client specificando il metaserver alternativo: conquest -m -M 127.0.0.1 - interrompere il nostro metaserver, conquest dovrebbere essere crashato durante il tentativo di eseguire codice all'offset 0x61616161 B] - prendere il sorgente del server, modificare il valore di scstat.snum o scstat.unum nella funzione sendClientStat che si trova in server.c dando loro dei valori come 0xff (per snum) o htons(0xffff) (per unum) in base a quale dei due bug si voglia testare: scstat.type = SP_CLIENTSTAT; scstat.flags = flags; - scstat.snum = snum; + scstat.snum = 0xff; scstat.team = team; scstat.unum = htons(unum); scstat.esystem = esystem; - compilare il nuovo server, lanciarlo ed entrare con un client che crashera' subito dopo il login ####################################################################### ====== 4) Fix ====== SVN 693 #######################################################################