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:
-
i giocatori reali non possono partecipare al match ospitato dal
server in quanto quest'ultimo è pieno
-
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)
-
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:
-
Il server usa una challenge key (un numero a 32bit) che è usato per
identificare la partita corrente (quindi, nuovo partita = nuova key).
-
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).
-
Useremo il protocollo UDP e la porta di destinazione (server) è
quella di default, ossia la 27015.
Ed ora si inizia a "giocare":
-
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.
-
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
-
Ora dobbiamo richiedere la challenge key per la partita corrente:
Da: client
A: server
Dati: XXXXgetchallenge
-
Il server ci invierà proprio le informazioni richieste:
Da: server
A: client
Dati: XXXXA00000000 916706044 1
La challenge key è 916706044.
-
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".
-
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.
-
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!