
Informationen und PoC zur ENLBufferPwn-Schwachstelle
| CVE: | CVE-2022-47949 |
| CVSS v3.1: | 9.8/10 (Kritisch) |
| Autoren: | PabloMK7, Rambo6Glaz, Fishguy6564 |
| Gemeldet: | 8. August 2021 (Mario Kart 7) 14. April 2022 (für die betroffenen WiiU- und Switch-Spiele) |
| Offengelegt: | 22. Dezember 2022 |
ENLBufferPwn ist eine Sicherheitslücke im gemeinsamen Netzwerkcode mehrerer Erstanbieter-Nintendo-Spiele seit dem Nintendo 3DS, die es einem Angreifer ermöglicht, durch eine Online-Spielesitzung mit dem Opfer Code aus der Ferne auf der Konsole des Opfers auszuführen (Remote Code Execution). Sie wurde im Laufe des Jahres 2021 von mehreren Personen unabhängig voneinander entdeckt und Nintendo in den Jahren 2021 und 2022 gemeldet. Seit der ersten Meldung hat Nintendo die Sicherheitslücke in vielen betroffenen Spielen behoben. Die Informationen in diesem Repository wurden nach Erhalt der Erlaubnis von Nintendo sicher offengelegt.
Die Sicherheitslücke erreicht eine Bewertung von 9.8/10 (Kritisch) im CVSS-3.1-Rechner.
Hier ist eine Liste von Spielen, von denen bekannt ist, dass sie die Sicherheitslücke zu einem bestimmten Zeitpunkt hatten (alle aufgeführten Switch- und 3DS-Spiele haben Updates erhalten, die die Sicherheitslücke beheben, sodass sie nicht mehr betroffen sind):
Die ENLBufferPwn-Sicherheitslücke nutzt einen Pufferüberlauf in der C++-Klasse NetworkBuffer aus, die in der Netzwerkbibliothek enl (Net in Mario Kart 7) enthalten ist und von vielen Erstanbieter-Nintendo-Spielen verwendet wird. Diese Klasse enthält zwei Methoden, Add und Set, die einen Netzwerkpuffer mit Daten von anderen Spielern füllen. Keine dieser Methoden prüft jedoch, ob die Eingabedaten tatsächlich in den Netzwerkpuffer passen. Da die Eingabedaten kontrollierbar sind, kann ein Pufferüberlauf auf einer entfernten Konsole ausgelöst werden, indem man einfach eine Online-Spielesitzung mit dem Angreifer führt. Wenn es richtig gemacht wird, bemerkt das Opfer möglicherweise nicht einmal, dass eine Sicherheitslücke auf seiner Konsole ausgenutzt wurde. Die Folgen dieses Pufferüberlaufs variieren je nach Spiel, von einfachen, harmlosen Änderungen am Speicher des Spiels (wie dem wiederholten Öffnen und Schließen des Home-Menüs auf dem 3DS) bis hin zu schwerwiegenderen Aktionen wie der vollständigen Übernahme der Konsole, wie unten gezeigt.
Der Rest des Berichts konzentriert sich auf Mario Kart 7, da es aufgrund der fehlenden Sicherheitsmaßnahmen (z. B. ASLR) des 3DS der schwerwiegendste Fall der Sicherheitslücke ist. Es könnte jedoch möglich sein, ASLR bei Switch-Spielen zu umgehen, indem man den NetworkBuffer kapert, der zum Zurücksenden von Daten an den Angreifer verwendet wird (und ihn so dazu bringt, Pointer auf den Heap und Code preiszugeben).
Im folgenden Video wird ein schwerwiegender Fall der Sicherheitslücke in Mario Kart 7 gezeigt, bei dem eine von einem Angreifer kontrollierte Konsole (linke Seite) eine nicht modifizierte Konsole (rechte Seite) vollständig übernimmt. Die einzige Interaktion des Benutzers besteht darin, einer Online-Spielesitzung mit dem Angreifer beizutreten, in diesem Fall über die Funktion „Communities“ (beachte, dass eine „Community“ verwendet wurde, um die Sicherheitslücke sicher und isoliert zu testen und keine anderen Benutzer zu beeinträchtigen, die in öffentlichen Lobbys spielen). Die Übernahme erfolgt durch das Kopieren einer ROP-Payload auf die entfernte Konsole und deren anschließende Ausführung. Diese ROP-Payload nutzt dann weitere Sicherheitslücken im Betriebssystem aus, um Privilegien zu erweitern und die volle Kontrolle zu erlangen. Im Video wird die entfernte Konsole gezwungen, einen CFW-Installer (SafeB9SInstaller) auszuführen. Mit denselben Techniken wäre es theoretisch möglich, Konto- oder Kreditkarteninformationen zu stehlen oder unerlaubte Audio-/Videoaufnahmen mit dem eingebauten Mikrofon/den Kameras der Konsole zu machen.
Wie bereits erwähnt, rührt die Sicherheitslücke von einem Versehen in zwei Methoden der Klasse NetworkBuffer her. Hier ist eine Implementierung der Klasse und der Methoden 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;
}
Wie du sehen kannst, prüfen weder Set noch Add, ob der eingehende newDataSize in die Puffergröße (dataSize) passt. Da diese NetworkBuffer-Klasse als generischer Container zum Austausch von Daten zwischen Spielern online verwendet wird, können der Inhalt von newData und der Wert von newDataSize von einem Angreifer kontrolliert werden, und ein Pufferüberlauf kann durchgeführt werden.
Ein weiteres Detail der Netzwerkbibliothek ist, dass sie asynchron ist, sodass Spiele andere Operationen ausführen können, während Daten in den Puffer gefüllt werden. Um dies zu erreichen, wird eine Doppelpuffer-Technik verwendet. Auf diese Weise kann das Spiel auf bereits empfangene Daten in einem NetworkBuffer zugreifen, während gleichzeitig neue Daten empfangen werden. Nachdem der zweite NetworkBuffer gefüllt ist, werden die Puffer getauscht und der Zyklus wiederholt sich.
Für diesen PoC wird der doppelte NetworkBuffer, der zum Empfangen von Mii-Daten verwendet wird (bufferType = 9), ausgenutzt. Aufgrund der Reihenfolge der Heap-Zuweisung kommt es dazu, dass das NetworkBuffer-Objekt und sein Inhalt nebeneinander platziert werden. Außerdem sind beide Puffer des Doppelpuffers im Speicher zusammenhängend. Das folgende Diagramm zeigt, wie der Speicher nach der Pufferzuweisung aussieht:
