
Technische Analyse und Proof-of-Concept für CVE-2024-45200, einen Stack-basierten Pufferüberlauf in der Pia-P2P-Netzwerkbibliothek von Mario Kart 8 Deluxe, der einen Remote-Absturz und potenzielle RCE auf der Nintendo Switch ermöglicht.
Informationen & Proof-of-Concept für die auf einem Stack-basierten Pufferüberlauf beruhende Sicherheitslücke „KartLANPwn“ in Mario Kart 8 Deluxe
Geschrieben von Chad Hyatt
| CVE | CVE-2024-45200 |
| CVSS 3.1 | Unbestimmt (Nintendo.. gibt an, es sei eine 4.3/10) |
| Ausgezahlte Prämie | $512 |
| H1-Bericht | #2611669 |
| Entdeckt | 2. Juli 2024 |
| Behoben | 11. Sept. 2024 (v3.0.3) |
| Offengelegt | 29. Sept. 2024 |
KartLANPwn ist eine Sicherheitslücke in Mario Kart 8 Deluxe, die auf der fehlerhaften Verwendung der P2P-Netzwerkbibliothek Pia beruht. Dabei werden einzelne Implementierungen von "CopyAppData" manchmal mit einer outBufSize aufgerufen, die größer ist als der out-Puffer selbst. In Kombination mit einem Informationsleck kann dies potenziell zu Remote-Codeausführung (RCE) im Benutzermodus auf den Konsolen anderer Spieler führen. KartLANPwn betrifft die Verwendung der Pia-Implementierungen für den LAN/LDN-Mehrspielermodus und den NEX-Online-Mehrspielermodus.
Diese Sicherheitslücke betrifft alle Versionen von Mario Kart 8 Deluxe bis einschließlich v3.0.1 (v3.0.2 für China/Tencent) und wurde speziell über die Funktion „LAN Play“ in der Einzelhandelsversion v3.0.1 von MK8DX demonstriert.
Mit Stand vom 11.09.2024 hat Nintendo einen Fix für KartLANPwn zusammen mit v3.0.3 für alle Regionen außer China bereitgestellt. Mit Stand vom 27.09.2024 wurde v3.0.3 nun auch für China veröffentlicht. Wir haben diese Informationen nach Erhalt der Erlaubnis von Nintendo sicher offengelegt.
Die proprietäre Netzwerkbibliothek Pia wird von Nintendo-eigenen Switch-Spielen mit Unterstützung für lokalen oder Online-Mehrspielermodus verwendet, um Peer-to-Peer-Netcode-Implementierungen für LAN/LDN (lokaler Mehrspielermodus) und das für den Online-Mehrspielermodus verwendete NEX-Protokoll bereitzustellen.
Zu Demonstrationszwecken konzentrieren wir uns speziell auf das LAN-Protokoll von Pia. Die Konsole des Raumhosts öffnet einen UDP-„Discovery“-Socket an :30000 auf einer lokalen Broadcast-Adresse (255.255.255.255), und andere Konsolen im selben Netzwerk sollen über ihren eigenen Socket (ebenfalls auf :30000) „Browse Requests“ an den Router senden, damit dieser sie an andere Geräte im selben Netzwerk weiterleitet.
Der Raumhost (unser 'Server') sendet eine erste „Browse Reply“ zurück, die Informationen über den Raum enthalten soll (Anzeigename des Hosts, Mii-Daten, Anzahl der Spieler usw.). Innerhalb des Browse-Reply-Pakets kann die Länge der in den out-Puffer zu kopierenden Anwendungsdaten mit einem Wert von bis zu 150 gesteuert werden, obwohl out nur 128 Bytes breit ist. Dadurch können Werte auf dem Stack-Frame überlaufen (in diesem speziellen Fall für ein pop {r4-r8, pc}).
Zumindest bei der Pia-Version, die MK8DX verwendet, werden die Browse-Reply-Pakete für LAN wie folgt konstruiert:
(Alle Integer-Typen sind als Big-Endian codiert)
| Index | Pseudo-Typ | Beschreibung |
|---|---|---|
| 0 | u8 | Pakettyp (0x1) |
| 1 | u32 | Größe des Session-Info-Bodys (1266 in unserem Fall) |
| 5 | (42 bytes) | Verschiedene Session-Info-Felder, für uns irrelevant |
| 47 | (0x180 bytes) | Beginn des Bereichs für Anwendungsdaten |
| 431 | u32 | Länge der Anwendungsdaten |
Der Rest der Sitzungsinformationen folgt, ist jedoch für das Erstellen eines Pakets für KartLANPwn unwichtig.
LAN_CopyAppData"-PseudocodeZu Demonstrationszwecken folgt hier ein grober Pseudocode aus der LAN-Implementierung von "CopyAppData". Obwohl an dieser Funktion allein nichts grundsätzlich falsch ist, kann eine falsche Verwendung (im Fall von MK8DX) dazu führen, dass der Stack-Frame durch unsere eingegebenen Anwendungsdaten in packet überschrieben wird.
(Funktion befindet sich unter +0xA0F8C0 in main für MK8DX v3.0.1)
void LAN_CopyAppData(int* r0, int packet, int out, uint outBufSize) {
int u1 = 68612;
if (out != NULL) {
// The actual length to read from the `packet` buffer at the start of our
// application data (which our 'server' controls)
uint appDataLength = *(uint *)(packet + 432);
// In some cases, outBufSize is input as a larger number than the bounds of the
// `out` buffer, which allows a stack buffer overflow (in our specific case, `*out`
// is 128 bytes long, and outBufSize is 150!)
if (appDataLength <= outBufSize) {
memcpy(out, packet + 48, outBufSize); // packet[47], start of application data
u1 = 0;
}
*r0 = u1;
return;
}
*r0 = 68615;
return;
}
Siehe kartlanpwn-poc.py
Wir haben ein einfaches, in Python geschriebenes PoC-Skript bereitgestellt, das als gefälschter Raumhost fungiert und auf die Konsolen anderer Spieler mit einem speziell präparierten „Browse-Reply"-Paket antwortet. Dieses lässt den Prozess des Spiels abstürzen, wenn du das Menü „LAN Play" in MK8DX von einer Konsole aus öffnest, die sich im selben Netzwerk wie der Computer mit dem ausgeführten Skript befindet.
Lade entweder das ZIP-Archiv des Repos direkt von GitHub herunter oder klone es mit git:
git clone https://github.com/latte-soft/kartlanpwn.git && cd kartlanpwn
python3 kartlanpwn-poc.py
Siehe Videodemonstration (YouTube):
Und für euch ARM-Nerds: Hier ist ein Screenshot von GDB des resultierenden Segfaults des Prozesses:

Es hat nur ein paar Tage gedauert, um die Details des Bugs selbst herauszufinden, aber den Überlauf tatsächlich auszunutzen? Das ist nochmal eine ganz andere Geschichte. Der Usermode des Nintendo-Switch-Kernels versteht keinen Spaß; er ist extrem streng in jeder Ecke, in der er es sein kann. Wir haben viele Stunden damit verbracht, verschiedene Ideen und Ansätze auszutauschen und zu manipulieren, letztlich ohne Erfolg für echte (beliebige) Codeausführung. In unserem speziellen Fall schien nicht einmal zuverlässiges ROP wirklich machbar, da so ziemlich alle netzwerkbezogenen Funktionen klassenbasiert waren und wir außerdem nur direkten Schreibzugriff auf r4-r8 hatten. (*_this mein Geliebter) Außerdem ist es ohne ein vorheriges Informationsleck nicht allzu machbar, einfach ein mov r4, r0 oder Ähnliches zu überspringen, um den _this-Zeiger zu kontrollieren. Lustige Sache!
Was den Report betrifft, war diesmal tatsächlich alles ein relativ reibungsloser Prozess mit dem Nintendo-Triage von der Meldung bis zur Offenlegung. Auch wenn die ausgezahlte Prämie von $512 weit weniger war, als ich erwartet hatte (sind sie das nicht immer?), ist alles besser, als wenn die „Nintendo-Ninjas" vor meiner Tür stehen..
Nintendo hat mit Sicherheit sozusagen aus den einfacheren Zeiten der Wii, des 3DS und sogar der Wii U ihre Lektion gelernt. Sie haben ihre Hausaufgaben gemacht; eine erfolgreiche Ausnutzung jeglicher Art über Denial-of-Service-Abstürze im Usermode hinaus ist auf der Switch fast unmöglich. ASLR, erzwungene No-eXecute-Seiten (man kann nicht direkt in ausführbare Speicherseiten schreiben, Spiele müssen für JIT ein dediziertes Sysmodule verwenden!), die Unfähigkeit zu ROP, neben anderen Problemfeldern. (wartet nur, bis die Modding-Szene diese Worte in kürzester Zeit widerlegt..) Andererseits habe ich in den letzten Monaten in sehr kurzer Zeit eine Menge über eine völlig neue Plattform und Architektur gelernt (für mich jedenfalls), ganz zu schweigen von den tollen Leuten, mit denen ich bei KartLANPwn zusammenarbeiten durfte! (Danke Pablo und fishguy 😄)
| Datum | Info |
|---|---|
| 2024/07/18 | Report über HackerOne an Nintendo eingereicht |
| 2024/07/31 | Report intern triagiert |
| 2024/09/11 | Fix zusammen mit Mario Kart 8 Deluxe v3.0.3 für alle Regionen außer China veröffentlicht |
| 2024/09/12 | Prämie von Nintendo ausgezahlt |
| 2024/09/12 | Andere Forscher fanden ziemlich schnell heraus im Bindiff für v3.0.3, dass der Fix für "a security flaw in the game's netcode" gedacht war |
| 2024/09/27 | Mario Kart 8 Deluxe v3.0.3 für die chinesische Region veröffentlicht |
| 2024/09/29 | Nintendo erteilte die Freigabe zur Offenlegung, dieses Repository wurde öffentlich gemacht |
| 2024/09/30 | CVE-2024-45200 vom NVD veröffentlicht |
KartLANPwn © 2024 ist unter CC BY 4.0 lizenziert.
Eine Kopie dieser Lizenz findest du unter https://creativecommons.org/licenses/by/4.0/