
Informazioni e PoC sulla vulnerabilità ENLBufferPwn
| CVE: | CVE-2022-47949 |
| CVSS v3.1: | 9.8/10 (Critica) |
| Autori: | PabloMK7, Rambo6Glaz, Fishguy6564 |
| Segnalato: | 8 agosto 2021 (Mario Kart 7) 14 aprile 2022 (per i giochi WiiU e Switch interessati) |
| Divulgato: | 22 dicembre 2022 |
ENLBufferPwn è una vulnerabilità nel codice di rete comune di diversi giochi Nintendo first-party a partire dal Nintendo 3DS che consente a un attaccante di eseguire codice da remoto sulla console della vittima semplicemente giocando una partita online con la vittima (esecuzione remota di codice). È stata scoperta in modo indipendente da più persone durante il 2021 e segnalata a Nintendo nel corso del 2021 e del 2022. Dalla segnalazione iniziale, Nintendo ha corretto la vulnerabilità in molti giochi vulnerabili. Le informazioni in questo repository sono state divulgate in modo sicuro dopo aver ottenuto il permesso da Nintendo.
La vulnerabilità ha ottenuto un punteggio di 9.8/10 (Critica) nel calcolatore CVSS 3.1.
Ecco un elenco di giochi noti per aver avuto la vulnerabilità a un certo punto (tutti i giochi Switch e 3DS elencati hanno ricevuto aggiornamenti che correggono la vulnerabilità, quindi non sono più interessati):
La vulnerabilità ENLBufferPwn sfrutta un buffer overflow nella classe C++ NetworkBuffer presente nella libreria di rete enl (Net in Mario Kart 7) usata da molti giochi Nintendo first-party. Questa classe contiene due metodi, Add e Set, che riempiono un buffer di rete con i dati provenienti dagli altri giocatori. Tuttavia, nessuno di questi metodi verifica che i dati di input rientrino effettivamente nel buffer di rete. Poiché i dati di input sono controllabili, un buffer overflow può essere innescato su una console remota semplicemente avviando una sessione di gioco online con l'attaccante. Se eseguito correttamente, la vittima potrebbe anche non accorgersi che una vulnerabilità è stata innescata sulla propria console. Le conseguenze di questo buffer overflow variano a seconda del gioco, da semplici modifiche inoffensive alla memoria del gioco (come aprire e chiudere ripetutamente il menu home sul 3DS) ad azioni più gravi come prendere il pieno controllo della console, come mostrato di seguito.
Il resto del rapporto si concentrerà su Mario Kart 7, poiché, a causa della mancanza di misure di sicurezza (come l'ASLR, per esempio) del 3DS, è il caso più grave della vulnerabilità. Tuttavia, potrebbe essere possibile aggirare l'ASLR sui giochi Switch dirottando il NetworkBuffer usato per inviare dati all'attaccante (e facendo sì che riveli puntatori all'heap e al codice).
Il seguente video mostra un caso grave della vulnerabilità in Mario Kart 7, in cui una console controllata da un attaccante (lato sinistro) prende completamente il controllo di una console non modificata (lato destro). L'unica interazione dell'utente è unirsi a una sessione di gioco online con l'attaccante, in questo caso utilizzando la funzione "communities" (si noti che è stata usata una "community" per testare in sicurezza la vulnerabilità in modo isolato e non coinvolgere altri utenti che giocavano in lobby pubbliche). La presa di controllo viene effettuata copiando un payload ROP sulla console remota ed eseguendolo. Questo payload ROP sfrutta poi altre vulnerabilità del sistema operativo per elevare i privilegi e ottenere il controllo totale. Nel video, la console remota viene costretta a eseguire un installer CFW (SafeB9SInstaller). Usando le stesse tecniche, sarebbe teoricamente possibile rubare informazioni di account/carte di credito o effettuare registrazioni audio/video non autorizzate usando il microfono/le fotocamere integrate della console.
Come affermato in precedenza, la vulnerabilità deriva da una svista in due metodi della classe NetworkBuffer. Ecco un'implementazione della classe e dei metodi in C++:
class NetworkBuffer
{
public:
u8 bufferType;
u8* dataPtr;
u32 dataSize;
u32 currentSize;
void Set(u8* newData, u32 newDataSize);
void Add(u8* newData, u32 newDataSize);
}
void NetworkBuffer::Set(u8* newData, u32 newDataSize)
{
memcpy(this->dataPtr, newData, newDataSize);
this->currentSize = newDataSize;
}
void NetworkBuffer::Add(u8* newData, u32 newDataSize)
{
memcpy(this->dataPtr + this->currentSize, newData, newDataSize);
this->currentSize += newDataSize;
}
Come puoi vedere, né Set né Add verificano che il newDataSize in arrivo rientri nella dimensione del buffer (dataSize). Poiché questa classe NetworkBuffer è usata come contenitore generico per lo scambio di dati tra i giocatori online, il contenuto di newData e il valore di newDataSize possono essere controllati da un attaccante, permettendo di eseguire un buffer overflow.
Un altro dettaglio della libreria di rete è che è asincrona, così i giochi possono svolgere altre operazioni mentre i dati vengono inseriti nel buffer. Per ottenere questo risultato, viene usata una tecnica a doppio buffer. In questo modo, il gioco può accedere ai dati già ricevuti in un NetworkBuffer nello stesso momento in cui vengono ricevuti nuovi dati. Dopo che il secondo NetworkBuffer è stato riempito, i buffer vengono scambiati e il ciclo si ripete.
Per questo PoC, verrà sfruttato il doppio NetworkBuffer usato per ricevere i dati Mii (bufferType = 9). A causa dell'ordine di allocazione dell'heap, capita che l'oggetto NetworkBuffer e i suoi contenuti siano posizionati uno accanto all'altro. Inoltre, entrambi i buffer del doppio buffer sono contigui in memoria. Il seguente diagramma rappresenta come appare la memoria dopo l'allocazione del buffer:
