
Analisi tecnica e proof-of-concept per CVE-2024-45200, un buffer overflow basato su stack nella libreria di rete P2P Pia di Mario Kart 8 Deluxe, che consente il crash remoto e un potenziale RCE su Nintendo Switch.
Informazioni e Proof-of-Concept per la vulnerabilità di buffer overflow basato su stack "KartLANPwn" di Mario Kart 8 Deluxe
Scritto da Chad Hyatt
| CVE | CVE-2024-45200 |
| CVSS 3.1 | Indeterminato (Nintendo.. sostiene che sia un 4.3/10) |
| Taglia pagata | $512 |
| Report H1 | #2611669 |
| Scoperta | 2 luglio 2024 |
| Risolta | 11 settembre 2024 (v3.0.3) |
| Divulgata | 29 settembre 2024 |
KartLANPwn è una vulnerabilità nell'uso errato della libreria di rete P2P Pia da parte di Mario Kart 8 Deluxe, in cui implementazioni individuali di "CopyAppData" vengono talvolta chiamate con un outBufSize maggiore del buffer out stesso. Questo può portare potenzialmente all'esecuzione remota di codice (RCE) a livello utente sulle console dei peer se abbinato a una fuga di informazioni. KartLANPwn influisce sull'uso delle implementazioni di Pia per il multiplayer LAN/LDN e il multiplayer online NEX.
Questa vulnerabilità colpisce tutte le versioni di Mario Kart 8 Deluxe fino alla v3.0.1 inclusa (v3.0.2 per Cina/Tencent), ed è stata specificamente dimostrata tramite la funzione "LAN Play" sulla versione retail v3.0.1 di MK8DX.
Dal 11/09/2024, Nintendo ha distribuito una correzione per KartLANPwn insieme alla v3.0.3 per tutte le regioni, esclusa la Cina. Dal 27/09/2024, la v3.0.3 è stata rilasciata anche per la Cina. Abbiamo divulgato queste informazioni in sicurezza dopo aver ricevuto il permesso da Nintendo.
La libreria di rete proprietaria Pia è utilizzata dai giochi first-party per Nintendo Switch con supporto multiplayer locale o online per fornire implementazioni netcode peer-to-peer per LAN/LDN (multigiocatore locale) e il protocollo NEX, utilizzato per il multiplayer online.
A scopo dimostrativo, ci concentreremo specificamente sul protocollo LAN di Pia. La console dell'host della stanza apre un socket UDP di "scoperta" su :30000 su un indirizzo broadcast locale (255.255.255.255) e le altre console sulla stessa rete devono pubblicizzare "richieste di navigazione" (browse requests) dal proprio socket (anche su :30000) al router per inoltrarle ad altri dispositivi sulla stessa rete.
L'host della stanza (il nostro 'server') risponde con un pacchetto iniziale di "risposta di navigazione" (browse reply) che dovrebbe contenere informazioni sulla stanza (il nome visualizzato dell'host, dati Mii, numero di giocatori, ecc.). All'interno del pacchetto browse-reply, la lunghezza dei dati dell'applicazione da copiare nel buffer out può essere controllata con un valore fino a 150, anche se out è largo solo 128 byte. Ciò consente di riempire eccessivamente i valori nello stack frame (in questo caso specifico, per un pop {r4-r8, pc})
Almeno nel caso della versione di Pia utilizzata da MK8DX, per ciò su cui ci concentriamo, i pacchetti di risposta di navigazione per LAN sono costruiti come segue:
(Tutti i tipi int sono codificati come big-endian)
| Index | Pseudo-Type | Descrizione |
|---|---|---|
| 0 | u8 | Tipo di pacchetto (0x1) |
| 1 | u32 | Dimensione del corpo delle informazioni della sessione (1266 nel nostro caso) |
| 5 | (42 bytes) | Campi vari delle informazioni della sessione, irrilevanti per noi |
| 47 | (0x180 bytes) | Inizio dello spazio per i dati dell'applicazione |
| 431 | u32 | Lunghezza dei dati dell'applicazione |
Il resto delle informazioni della sessione segue, ma non è importante per creare un pacchetto per KartLANPwn
LAN_CopyAppData"Per scopi dimostrativi, di seguito è riportato uno pseudocodice approssimativo dell'implementazione LAN di "CopyAppData". Sebbene non ci sia nulla di intrinsecamente sbagliato in questa funzione da sola, un uso errato (nel caso di MK8DX) può consentire la sovrascrittura dello stack frame da parte dei nostri dati applicativi in packet.
(funzione situata a +0xA0F8C0 in main per MK8DX v3.0.1)
void LAN_CopyAppData(int* r0, int packet, int out, uint outBufSize) {
int u1 = 68612;
if (out != NULL) {
// La lunghezza effettiva da leggere dal buffer `packet` all'inizio dei nostri
// dati applicativi (che il nostro 'server' controlla)
uint appDataLength = *(uint *)(packet + 432);
// In alcuni casi, outBufSize è inserito come un numero maggiore dei limiti del
// buffer `out`, il che consente un buffer overflow dello stack (nel nostro caso specifico, `*out`
// è lungo 128 byte, e outBufSize è 150!)
if (appDataLength <= outBufSize) {
memcpy(out, packet + 48, outBufSize); // packet[47], inizio dei dati applicativi
u1 = 0;
}
*r0 = u1;
return;
}
*r0 = 68615;
return;
}
Vedi kartlanpwn-poc.py
Abbiamo fornito un semplice script PoC scritto in Python, che agisce come un falso host della stanza che risponde ai peer con un pacchetto "browse-reply" appositamente creato che farà crashare il processo del gioco quando aprirai il menu "LAN Play" in MK8DX da una console sulla stessa rete del computer che esegue lo script.
Scarica il zip del repository direttamente da GitHub, oppure clona usando git:
git clone https://github.com/latte-soft/kartlanpwn.git && cd kartlanpwn
python3 kartlanpwn-poc.py
Vedi la dimostrazione video (YouTube):
E per voi nerd dell'ARM, ecco uno screenshot da GDB del segfault risultante dal processo:
