Articoli Manifesto Tools Links Canali Libri Contatti ?
Sicurezza

Un'introduzione al fake players bug

Abstract
Il fake players bug consiste nel poter riempire i server dei vari giochi online (Quake 3 ed Half-Life ad esempio) con giocatori inesistenti (virtuali) in modo che una volta pieno il server non permetta ai veri giocatori di partecipare alla partita.
Data di stesura: 26/10/2003
Data di pubblicazione: 15/03/2004
Ultima modifica: 04/04/2006
di Luigi Auriemma Discuti sul forum   Stampa

Introduzione

Prima di tutto questo bug è specifico per i videogiochi e quasi tutti i giochi con supporto multiplayer attualmente esistenti sono vulnerabili; non c'è molto da dire a riguardo comunque se non si è dei giocatori probabilmente questo documento risulterà abbastanza interessante (o almeno spero!).

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 è il motivo per cui esiste il multiplayer!

Proprio i giocatori sono il maggior problema dei giochi in quanto ogni server può 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).
Ciò significa che un attacker può riempire un server di gioco con un numero a sua scelta di giocatori inesistenti (spesso un giocatore viene "emulato" da non più di uno o due pacchetti di dati inviati dall'attacker) ed il server, dopo aver raggiunto il numero massimo di giocatori consentiti, non accetterà più nessuno.

L'effetto è un Denial of Service (DoS) dove i giocatori reali non possono usare il servizio offerto dal server semplicemente perché non c'è più 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 è usato per inviare dati ed informazioni per permettere ai giocatori di entrare, permettere 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 così via).
Quindi abbiamo giochi come Half-Life, Quake 3 e Unreal Tournament che sono vulnerabili al Fake players bug.

Quali giochi NON sono vulnerabili

...praticamente tutti i giochi che usano un server centralizzato ove è 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 è proprio quello di raccogliere il più alto numero di persone: più persone = più guadagni!) ed esiste un processo di autenticazione e la presenza di un unico giocatore identificato univocamente (ogni giocatore è 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 perché l'uso di pacchetti è più semplice e veloce da gestire rispetto alle connessioni TCP.
Comunque l'uso dell'UDP non è la vera causa del fake players bug ma è una cosa positiva per chi lancia l'attacco proprio perchè:
  • non ha bisogno di molte risorse sulla sua macchina
  • l'exploit può essere scritto facilmente senza troppo impegno
  • in alcuni casi è persino possibile usare pacchetti "spoofati" (lo spoofing - indirizzo di IP del sorgente falso - può essere facilmente evitato inserendo challenge keys basate su IP:porta sorgente o far sì che il client debba rispondere o replicare ai dati inviati dal server)
Comunque la causa primaria è 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 è pieno
  2. i giochi che usano un multiplayer in stile "lobby" (ingresso) subiscono un DoS peggiore in quanto il match non potrà 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 è sotto l'attacco dei fake players perché tali "giocatori" non si dichiareranno pronti ed anche se l'amministratore del server li caccerà, 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 avrà problemi usando questo tipo di attacco.
Il problema primario è la banda in ricezione (download), infatti ogni volta che un giocatore è accettato, il server (spesso) inizia a trasmettere una gran quantità di dati al client. Ma ciò non toglie che l'attacco possa essere lanciato anche da connessioni lenti come modems in dialup.

I pacchetti che l'attacker riceve sono generalmente pacchetti keep-alive (ossia per sapere se il client è ancora online o no, proprio come il ping) ed anche dati di gioco.

Esempio pratico

Il seguente è 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 ciò non è importante).
Il fake players bug in questione è 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 è 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).
    Ciò significa che ogni giocatore dallo stesso indirizzo IP deve usare una porta sorgente differente o non verrà accettato (questa è una nota un po' inutile perché quasi tutti i videogiochi in multiplayer usano tale metodo).
  3. Useremo il protocollo UDP e la porta di destinazione (server) è quella di default, ossia la 27015.
Ed ora si inizia a "giocare":
  1. Abbiamo bisogno di alcune informazioni utili per lanciare l'attacco, e più precisamente:
    • il numero di protocollo richiesto
    • se dobbiamo inviare una password o no
    • se il server è già pieno
    Da:   client
    A:    server
    Dati: XXXXinfostring
          |   |
          |   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
    Nota: XXXX viene usato per rappresentare una sequenza di 4 bytes aventi valore 255, corrispondenti ad un intero con valore 0xffffffff.
  2. Il server ci invia le informazioni che abbiamo richiesto:
    Da:  server
    A:   client
    Dati (in esadecimale):
                                  ff ff ff ff 69 6e             XXXXin
    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 è:
    \protocol\46
    Il protocollo da usare è 46 (è 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 è pieno quindi possiamo lanciare l'attacco senza problemi. Se il server è 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: XXXXgetchallenge
  4. Il server ci invierà proprio le informazioni richieste:
    Da:   server
    A:    client
    Dati: XXXXA00000000 916706044 1
    La challenge key è 916706044.
  5. Ora lanciamo il vero attacco.
    Un pacchetto "connect" (il comando usato per entrare) è come il seguente:
    Da:  client
    A:   server
    Dati (in esadecimale):
                                  ff ff ff ff 63 6f             XXXXco
    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'attacco è 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!
    password
    Anche se il parametro non è nel dump usato per l'esempio, esso è usato quando vogliamo partecipare ad un server protetto da password.
    Se la password è ciao, aggiungeremo "\password\ciao".
  6. Conferma dal server
    Da:   server
    A:    client
    Dati: XXXXB 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 è pieno, ci verrà inviato il seguente pacchetto:
    Da:   server
    A:    client
    Dati: XXXX9Server is full
I giocatori falsi che vengono generati, in realtà 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 è il primo Unreal di EpicGames.
È incredibilimente divertente vedere i nuovi giocatori falsi creati dall'attacker che appaiono proprio in testa a quelli apparsi precedentemente finendo quindi con l'ucciderli!

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 spoofing da parte dell'attacker)
  • usare timeouts più brevi e permettere agli amministratori dei server di poter "bannare" in modo più flessibile basandosi magari su determinati schemi.
    Per esempio: l'attacker aggiunge con successo un giocatore falso al server, dopodiché tale "giocatore" và in timeout dopo un certo numero di secondi o minuti e l'attacker dovrà 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 và a colpire tutti i giocatori che sono dietro lo stesso IP dell'attacker via NAT, ossia quando più 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 è la migliore soluzione implementata attualmente sui giochi odierni
  • l'uso del TCP per il login iniziale è un po' più sicuro dell'UDP in quanto l'attacker deve usare un numero leggermente maggiore di risorse e si evita lo spoofing (già evitabile in altri modi)
  • altri...???
L'unica soluzione efficace che ho visto sugli attuali giochi è l'uso di cd-key univoche controllate da un server centralizzato.
Questo metodo naturalmente non è applicabile nelle partite multiplayer in LAN ove quindi sarà sempre possibile lanciare un fake players DoS, ma se non altro viene limitato il problema sui servers Internet.

Una cd-key univoca può essere facilmente "bannata" se chi la usa è l'autore di un attacco fake players proprio perché 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 può essere soggetto di attacchi DoS cosicché se è irraggiungibile non esiste più 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 ciò è 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 cosicché un attacker che vuole lanciare un fake players DoS deve prima spendere tempo "reversando" (gerg. per "reverse engeneering") l'algoritmo usato per codificare i dati oppure trovare altri metodi alternativi.
Fortunatamente (per l'attacker) spesso non c'è 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 è successo con Tribes 1).

Conclusioni

Gli sviluppatori di videogiochi dovrebbero prestare più attenzione e spendere più tempo quando scrivono il protocollo di rete dei loro giochi e dovrebbero fare più 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!

Informazioni sull'autore

Luigi Auriemma, classe 80, vive in provincia di Milano. Appassionato di computers e "cacciatore di bugs" in qualsiasi applicazione soprattutto quando è annoiato. Sostenitore di tutto ciò che sia libero, dal software Open Source alla "Full Disclosure". Il suo sito web è http://aluigi.altervista.org/.

È possibile consultare l'elenco degli articoli scritti da Luigi Auriemma.

Altri articoli sul tema Sicurezza.

Discuti sul forum   Stampa

Cosa ne pensi di questo articolo?

Discussioni

Questo articolo o l'argomento ti ha interessato? Parliamone.