####################################################################### Luigi Auriemma Applicazione: Alien Arena 2006 Gold Edition http://red.planetarena.org Versioni: <= 5.00 Piattaforme: Windows e Linux Bugs: A] safe_cprintf server format string B] Cmd_Say_f server buffer-overflow C] Com_sprintf crash Exploitation: A] remoto, contro server (in-game) B] remoto, contro server (in-game) C] remoto, contro clients e server (in-game) Data: 07 Mar 2006 Autore: Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org ####################################################################### 1) Introduzione 2) Bugs 3) The Code 4) Fix ####################################################################### =============== 1) Introduzione =============== Alien Arena 2006 GE e' l'ultima release della serie CodeRED, un gioco open source sviluppato su una versione ottimizzata (CRX engine) del motore GPL di Quake II. Il gioco supporta il multiplayer sia via LAN che Internet. ####################################################################### ======= 2) Bugs ======= Tutti i bugs necessitano di essere sfruttati in-game quindi l'IP dell'attacker non deve essere bannato e lui deve conoscere la parola chiave se il server e' protetto da password. Non ho trovato altri modi per sfruttare tali bugs "esternamente". ------------------------------------ A] safe_cprintf server format string ------------------------------------ La funzione safe_cprintf() usata dal server per inviare messaggi ai clients e' affetta da una vulnerabilita' di tipo format string che puo' permettere ad un attacker di eseguire codice malevolo. Dopo aver costruito la stringa di output la funzione la passa come se fosse una stringa di formato (esattamente come un doppio sprintf) a gi.cprintf() -> "void PF_cprintf (edict_t *ent, int level, char *fmt, ...)". Da games/acesrc/acebot_cmds.c: void safe_cprintf (edict_t *ent, int printlevel, char *fmt, ...) { char bigbuffer[0x10000]; va_list argptr; int len; if (ent && (!ent->inuse || ent->is_bot)) return; va_start (argptr,fmt); len = vsprintf (bigbuffer,fmt,argptr); va_end (argptr); gi.cprintf(ent, printlevel, bigbuffer); } ----------------------------------- B] Cmd_Say_f server buffer-overflow ----------------------------------- La funzione Cmd_Say_f e' usata dal server per gestire i messaggi di testo ricevuti dai clients. Cmd_Say_f utilizza un buffer di 2048 bytes ove viene messo il nickname del giocatore che ha inviato il messaggio usando la funzione sicura (abbastanza sicura) Com_sprintf() seguita da strcat() per aggiungere il messaggio ricevuto. Queste istruzioni permettono ad un attacker di sfruttare il risultante buffer-overflow per eseguire codice malevolo. Da source/game/g_cmds.c: void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0) { int i, j; edict_t *other; char *p; char text[2048]; gclient_t *cl; if (gi.argc () < 2 && !arg0) return; if ((!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || (!ctf->value)) team = false; if (team) Com_sprintf (text, sizeof(text), "(%s): ", ent->client->pers.netname); else Com_sprintf (text, sizeof(text), "%s: ", ent->client->pers.netname); if (arg0) { strcat (text, gi.argv(0)); strcat (text, " "); strcat (text, gi.args()); } else { p = gi.args(); if (*p == '"') { p++; p[strlen(p)-1] = 0; } strcat(text, p); } ... -------------------- C] Com_sprintf crash -------------------- La funzione Com_sprintf() e' un rimpiazzamento customizzato di snprintf() ed e' usato svariate volte nel codice. L'unico problema di tale funzione (bigbuffer e' abbastanza grande quindi non rappresenta un rischio) e' causato dalla chiamata finale a strncpy() che non e' seguita da un'istruzione per delimitare dest con un NULL byte. Spesso, a seconda dal sistema/compilatore, questa mancanza porta ad un crash. Nei miei tests e' stato possibile crashare i clients precompilati per Windows senza problemi attraverso una skin di circa 110 caratteri (MAX_OSPATH e' 128). Infatti uno dei modi migliori per sfruttare questo bug e' proprio utilizzando un giocatore con un lungo nome della skin, arma o modello in modo che qualsiasi client che e' od entrera' nel server mentre l'attacker sta giocando sara' crashato immediatamente. In questo caso possiamo vedere tutto cio' nella funzione CL_LoadClientinfo() che si trova in client/cl_parse.c. Da source/game/q_shared.c: void Com_sprintf (char *dest, int size, char *fmt, ...) { int len; va_list argptr; char bigbuffer[0x10000]; va_start (argptr,fmt); len = vsprintf (bigbuffer,fmt,argptr); va_end (argptr); if (len >= size) Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); strncpy (dest, bigbuffer, size-1); } ####################################################################### =========== 3) The Code =========== http://aluigi.org/poc/aa2k6x.zip ####################################################################### ====== 4) Fix ====== No fix. Gli sviluppatori rilascieranno una patch nei prossimi mesi. #######################################################################