Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
ds3-nrssr-rce — Dokumentation und Proof-of-Concept-Code für CVE-2022-24125 und CVE-2022-24126. | Kitploit
Tools/GitHubGitHub/tremwil/ds3-nrssr-rce
Exploit-FrameworksSchwachstellenanalyseExploitationReverse EngineeringShellcodePenetrationstestsLernen & BildungRed TeamingShellcode-GenerierungPayload-EntwicklungBinary-Exploitation
16986vor 4 JahrenVon Kitploit geprüft
GitHub
tremwil/ds3-nrssr-rce

ds3-nrssr-rce

Dokumentation und Proof-of-Concept-Code für CVE-2022-24125 und CVE-2022-24126.

Repository anzeigen

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Update: Dark Souls III 1.15.1

Ein neues Spielupdate, 1.15.1, wurde am 25.08.2022 für Dark Souls III veröffentlicht, zusammen mit der Wiederherstellung der Onlinedienste. Dieses Update korrigierte sowohl CVE-2022-24125 als auch CVE-2022-24126, zusammen mit einer Vielzahl anderer potenzieller Sicherheitslücken im P2P-Netzwerk des Spiels (OOB-Lese-/Schreibzugriffe). Darüber hinaus wurden alle bekannten Exploits behoben, die es erlaubten, die Speicherstände anderer Spieler zu manipulieren. Viele übliche kleine Cheats (z. B. „Fluchmesser“), die beim Online-Multiplayer häufig auftraten, wurden ebenfalls gepatcht.

ds3-nrssr-rce

Dieses Repository enthält Proof-of-Concept-Code und Dokumentation für den jüngsten RCE-Exploit, der FROM-SOFTWARE-Spiele betrifft, CVE-2022-24126. Obwohl theoretisch auch in anderen Spielen möglich, liegt der Fokus auf Dark Souls III, da meine Forschung an diesem Spiel durchgeführt wurde. Derzeit existiert Proof-of-Concept-Code nur für Dark Souls III, die Schwachstelle wurde jedoch in den folgenden Spielen bestätigt:

  • Dark Souls 1 PTDE (Credit: LukeYui)
  • Dark Souls Remastered (Credit: metal-crow)
  • Dark Souls 2 (einschließlich Scholar) (Credit: LukeYui)
  • Dark Souls 3 (bis 1.15.0) (Credit: tremwil)

Der anfällige Code ist auch in Sekiro vorhanden (Credit: LukeYui), obwohl es keine Möglichkeit gibt, ihn auszulösen. Das Vorhandensein in Demon's Souls wurde nicht bestätigt, ist aber sehr wahrscheinlich. Der geschlossene Netzwerktest war zwar betroffen, die Veröffentlichungsversion von Elden Ring jedoch nicht. Tatsächlich wurde eine ganze Reihe von Netzwerkabstürzen, Out-of-Bounds-Lese-/Schreibzugriffen und Exploits, die es Spielern erlaubten, die Spieldaten anderer zu modifizieren und die in Dark Souls III vorhanden waren, in Elden Ring gepatcht. Kudos an für die Zusammenstellung dieser Liste und an FROM SOFTWARE für das schnelle Handeln! Ich bin froh zu sagen, dass

LukeYui
Elden Ring unbestritten der sicherste FROM-SOFTWARE-Titel ist, was das Ausmaß des Schadens betrifft, den Hacker anrichten können.

Missverständnisse ausräumen

Entgegen der landläufigen Meinung handelt es sich hierbei NICHT um einen Peer-to-Peer-Netzwerk-Exploit. Er hängt mit dem Matchmaking-Server zusammen und ist daher viel schwerwiegender, da man aufgrund einer weiteren Matchmaking-Server-Schwachstelle (CVE-2022-24125) keine Multiplayer-Aktivitäten durchführen muss, um angreifbar zu sein.

In Dark Souls III hätte ein böswilliger Angreifer, der dies ausnutzt, innerhalb von Sekunden zuverlässig eine Payload von bis zu 1,3 MiB1 Shellcode auf jedem Online-Spieler-Rechner ausführen können.

Da das Spiel in den Monaten vor der Serverabschaltung durchschnittlich etwa 20.000 gleichzeitige Spieler hatte, war dies eindeutig ein Problem, das sofort behoben werden musste, insbesondere angesichts der Möglichkeit, dass es in Elden Ring vorhanden sein könnte. Da FROM SOFTWARE über 40 Tage nach meinem ersten Bericht mit Proof-of-Concept-Videos und detaillierter Exploit-Dokumentation (auf der ein großer Teil dieser Readme basiert) noch nicht reagiert hatte, beschloss ich, die Existenz des Exploits auf harmlose Weise öffentlich zu demonstrieren, in der Hoffnung, die Aufmerksamkeit zu erhöhen, damit er von den Entwicklern behoben wird – und es hat funktioniert.

Inhaltsverzeichnis

  • Zusammenfassung des Exploits (CVE-2022-24126)
  • Verteilungsvektoren (CVE-2022-24125)
  • Die allgemeine Exploitationstaktik für alle Spiele
    • Fehler #1: Keine Grenzüberprüfung im Eintragslisten-Parser
    • Fehler #2: Pufferüberlauf im NRSessionSearchResult-Parser
    • Vorbereitung der ROP-Kette
  • Dark Souls III Proof-of-Concept-Code
    • Ausführen des PoC-Codes
    • Angriffsvektor
    • Virtuelle Aufruf-Umleitungskette
    • Zusätzliche Informationen

Zusammenfassung des Exploits (CVE-2022-24126)

Eine unzureichende Grenzüberprüfung eines Stack-Puffers und des Datenfeldgrößenfelds während der Verarbeitung von NRSessionSearchResult-Matchmaking-Daten erlaubt einem Angreifer die Ausführung beliebigen Codes. Der Stack-Overflow erlaubt es, die unteren zwei Bytes der vftable_ptr des DLMemoryInputStream-Objekts zu überschreiben, das intern vom Stream-Reader verwendet wird, und die Ausführung auf sorgfältig ausgewählten benachbarten Code umzuleiten. Eine clevere Ausnutzung der Struktur des DLMemoryInputStream-Objekts und des Datenfeldgrößenfelds ermöglicht dann eine beliebige Code-Umleitung, wobei RCX auf die Adresse unseres Pakets zeigt. Von dort aus kann eine Reihe von Code-Umleitungen über virtuelle Aufrufe mit unterschiedlichen Offsets (die nun auf die Adressen springen, die wir in den Paketpuffer geschrieben haben) verwendet werden, um die Ausführung beliebigen Codes zu erreichen.

Verteilungsvektoren (CVE-2022-24125)

Die Verteilungsvektoren machen diesen speziellen RCE besonders schwerwiegend (abgesehen davon, dass es sich bereits um einen RCE handelt). Der Exploit wird durch Matchmaking-Push-Anfragen mit NRSessionSearchResult-Informationen übertragen. Das bedeutet, dass der Angreifer jeden angreifen kann, der seiner Online-Sitzung beitritt. Insbesondere für DS3:

  • Beschwörungen (PushRequestSummonSign)
  • Eindringlinge der Dunklen Geister (PushRequestAllowBreakInTarget)
  • Spieler, die über einen Bund beitreten (PushRequestVisit)
  • Arenakämpfer (PushRequestAcceptQuickMatch)

Das ist bereits ziemlich schlimm, aber das wahre Potenzial wird durch die RequestSendMessageToPlayers-Anfrage freigesetzt:

root@kitploit:~
message RequestSendMessageToPlayers { 
    repeated uint32 player_ids = 1; 
    required bytes push_message = 2;
}

Der Host verwendet diese Anfrage, um die Push-Nachricht PushRequestAllowBreakInTarget direkt an Eindringlinge zu senden, damit diese Spawn-Koordinaten erhalten und ihrer P2P-Sitzung beitreten können. Das ist alles. Das ist die einzige Art, wie diese Anfrage vom Spiel verwendet wird.

Dennoch erlaubt sie jedem Client, beliebige Push-Nachrichten an Hunderttausende bestimmter Spieler zu senden.

Ich kann nicht genug betonen, wie gefährlich das ist. Im Grunde kann jeder Spieler den Matchmaking-Server imitieren. Indem der Angreifer diese Anfrage verwendet, um den Exploit über eine PushRequestVisit zu versenden, kann jeder Online-Spieler gezielt angegriffen werden, solange seine Spieler-ID bekannt ist. Der Angreifer kann den Exploit auch sehr schnell an die gesamte Online-Spielerbasis senden, indem er mehrere Anfragen sendet, die jeweils einen großen Teil möglicher Spieler-IDs enthalten.

Die allgemeine Exploitationstaktik für alle Spiele

Während sich der RCE nicht genau auf jedes Spiel übertragen lässt, ist die Kernidee des Exploits, die dem Angreifer eine beliebige Code-Umleitung ermöglicht, dieselbe. Wenn dies erreicht werden kann, ist es sehr wahrscheinlich, dass eine spielspezifische virtuelle Aufrufkette oder ROP-Kette gefunden werden kann. Dieser „erste Schritt“ nutzt die folgenden Schwachstellen:

Fehler #1: Keine Grenzüberprüfung im Eintragslisten-Parser

Matchmaking-Push-Anfragen, die Sitzungsbeitrittsinformationen enthalten, speichern diese Informationen in einem benutzerdefinierten Binärformat, das aus einer Kette von längenbegrenzten Dateneinträgen besteht. Jeder Eintrag hat das folgende Format:

root@kitploit:~
struct Entry
{
    uint32_t type_or_id; // nicht sicher, aber wahrscheinlich ein Typ (feste Länge = 2, variable Länge = 1 ?)
    uint32_t size;
    uint8_t data[size];
}

Die Spielfunktion, die für das Kopieren der Daten dieser Einträge verantwortlich ist, vertraut blind dem Größenfeld, was einen Out-of-Bounds-Lesezugriff verursacht. Dies kann von einem böswilligen Client ausgenutzt werden, indem das Größenfeld auf Werte wie 0x7FFFFFFF gesetzt wird, was zu einem Speicherzuweisungsfehler und einem Absturz des Spiels des Opfers führt. Später wird diese Größe auch an den Konstruktor eines DLMemoryInputStream übergeben, der ein wesentlicher Bestandteil des Exploits ist.

Fehler #2: Pufferüberlauf im NRSessionSearchResult-Parser

Einer der Einträge in der oben beschriebenen Datenstruktur ist ein serialisiertes NRSessionSearchResult-Objekt. Der Parser für diese Daten analysiert zuerst eine Liste von Eigenschaften. Diese Eigenschaften können 4-Byte-Ints, 8-Byte-Ints oder nullterminierte Breitstrings sein. Auf diese Eigenschaftenliste folgt der Steam-Persona-Name des Hosts als nullterminierter Breitstring sowie einige zusätzliche Daten, die für den Exploit nicht wichtig sind. Sowohl diese Funktion als auch der Eigenschaftenlisten-Parser verwenden einen Stack-Puffer fester Größe zum Lesen von Strings, und in beiden Fällen wird keine Grenzüberprüfung des Puffers durchgeführt. Hier ist der Spielcode, der für das Kopieren des Hostnamens verantwortlich ist (mit dem Ghidra-Decompiler erstellt und dann bereinigt):

root@kitploit:~
size_t idx = 0;
wchar_t wchr = 0;
do {
  // read_wchar()-Funktion am vftable-Index 17 von DLEndianStreamReader
  wchr = stream_reader->read_wchar();
  player_name_buff[idx] = wchr;
  idx++;
} while (wchr != 0);

Dies führt zu einem Pufferüberlauf-Exploit, der es dem Angreifer ermöglicht, den Stack zu korrumpieren.

Vorbereitung der virtuellen Aufruf- / ROP-Kette

Um eine beliebige Code-Umleitung zu erreichen, nutzen wir dies und das Speicherlayout eines DLMemoryInputStream-Objekts, das vom aufrufenden Parser auf dem Stack instanziiert wird und intern vom Stream-Reader verwendet wird:

root@kitploit:~
struct DLMemoryInputStream {
    uintptr_t* vftable_ptr; // Offset 0
    size_t data_size;       // Offset 4 (32bit) / 8 (64bit)
    uint8_t* data_buffer;   // Offset 8 (32bit) / 16 (64bit)
    // Einträge nach dem Puffer sind für den Exploit nicht wichtig
}

Da wir das data_size-Feld kontrollieren (Fehler #1), kann es auf die Stack-Speicheradresse des data_buffer-Felds gesetzt werden. Dies wird gelingen, vorausgesetzt die Adresse ist konstant und nicht zu groß (DS3 erfüllt diese Anforderungen). Da der Compiler den Stack-Puffer oben im Frame platziert, kann der Angreifer mit Fehler #2 die unteren zwei Bytes der vftable_ptr des DLMemoryInputStream überschreiben. Wenn das nächste Zeichen vom DLEndianStreamReader gelesen wird, ruft es intern den DLMemoryInputStream auf und der Code wird umgeleitet. Die 2 Bytes geben genug Spielraum, um zur 22. Funktion in der vftable des DLEndianStreamReader zu springen, die die 6. virtuelle Methode des Objekts aufruft, auf das sein erstes Feld zeigt. In einem 64-Bit-Prozess (d. h. Dark Souls III) würden die folgenden Anweisungen ausgeführt werden:

root@kitploit:~
MOV       RCX,qword ptr [RCX + 0x8]
MOV       RAX,qword ptr [RCX]
JMP       qword ptr [RAX + 0x40]

Da RCX ein Zeiger auf das DLMemoryInputStream-Objekt ist, schreibt die erste Anweisung das data_size-Feld, das vom Angreifer mit Fehler #1 auf eine Stack-Adresse gesetzt wurde, die auf das data_buffer-Feld zeigt, in RCX. Die beiden nächsten Anweisungen leiten die Ausführung somit auf die Speicheradresse um, die der Angreifer bei Offset 0x40 im Datenpuffer geschrieben hat. Eine beliebige Code-Umleitung wurde nun erreicht! Von dort aus kann der Angreifer eine Kette von Code-Umleitungen aufbauen, die seine Payload in einen geeigneten Speicherbereich kopieren und ausführen, indem er Code in der Nähe von virtuellen Aufrufen mit verschiedenen Offsets auswählt, da der Puffer nun als virtuelle Methodentabelle fungiert. Für den Dark Souls III Proof of Concept habe ich ein Setup gefunden, das nur 3 Gadgets benötigt, um RCE zu erreichen:

  • 0x18: 140e97700
  • 0x40: 1422be020
  • 0x68: 140e40f15

Weitere Details zu diesen 3 Gadgets finden Sie hier. Wenn dieser Ansatz mit virtuellen Aufrufen für ein anderes Spiel nicht praktikabel ist, kann die beliebige Code-Umleitung dennoch verwendet werden, um einen traditionelleren ROP-Exploit aufzubauen.

Dark Souls III Proof-of-Concept-Code

Ausführen des PoC-Codes

Um den Proof-of-Concept-Code auszuführen, müssen Sie zuerst einen Server zum Verbinden haben. Da die offiziellen Server aufgrund des Exploits deaktiviert wurden, können Sie einen privaten mit ds3os einrichten. ds3os ist so konzipiert, dass es das Verhalten des Einzelhandelsservers so genau wie möglich nachahmt, aber zur Behebung dieses Exploits wurden bereits Sicherheitspatches in diesem Projekt bereitgestellt. Sie können jedoch noch eine Testumgebung einrichten, indem Sie das Projekt selbst mit den Konstanten SEND_MESSAGE_TO_PLAYERS_SANITY_CHECKS und NRSSR_SANITY_CHECKS auf false in BuildConfig.h erstellen. Dies ahmt das unsichere Verhalten des Einzelhandelsservers nach. Folgen Sie den Anweisungen von ds3os, um das Spiel zu starten und eine Verbindung zu Ihrem Server herzustellen.

Sobald dies erledigt ist und Ihr Spiel mit den Servern verbunden ist, erstellen Sie den PoC-Code und starten Sie die ausführbare Datei Injector.exe. Sie injiziert eine DLL mit dem Exploit-Code in den Prozess von Dark Souls III. Diese DLL verwendet dann die Spielfunktion, die FRPG-Nachrichten an den Server sendet, um den Exploit an Ihren eigenen Client zu liefern.

Angriffsvektor

Für den Proof of Concept habe ich mich für eine PushRequestVisit-Nachricht entschieden, die mit RequestSendMessageToPlayers gesendet wird. Dies ist die wirksamste Version des Exploits in dem Sinne, dass das Spiel des Ziels die verwundbaren Daten sofort nach Erhalt in allen Situationen (auch im Hauptmenü) verarbeitet.

Virtuelle Aufruf-Umleitungskette

Offset 0x18: 140e97700

root@kitploit:~
LEA       RAX,[DAT_144786150]
RET

Dieses Gadget wird in dem bei 0x68 verwendet. Wir müssen eine Adresse, die niedriger, aber ziemlich nahe an 144786998 liegt, in RAX laden; dies ist die nächstgelegene.

Offset 0x40: 1422be020

root@kitploit:~
MOV       RDX,RAX
MOV       R8,qword ptr [RCX]
CALL      qword ptr [R8 + 0x68]

Um das Gadget bei Offset 0x68 verwenden zu können, muss die Datenpufferadresse in RDX gespeichert sein und RCX unverändert bleiben. Dies wird hiermit genau erreicht.

Offset 0x68: 140e40f15

root@kitploit:~
; Sprung hierher vom Gadget bei Offset 0x40
MOV       RBX,RDX
CMP       R9,R8

 ; Springt nie, R9 != R8
JZ        LAB_140e40f7a
MOV       RAX,qword ptr [RCX]
MOV       R8,qword ptr [RSP + 0x50]
MOV       RDX,R9
MOV       qword ptr [RSP + 0x30],RSI

; Aufruf-Gadget bei Offset 18 (140e97700). Lädt 144786150 in RAX
CALL      qword ptr [RAX + 0x18]
MOV       RSI,RAX
TEST      RAX,RAX

; Springt nie, RAX ist die Datenpufferadresse.
JZ        LAB_140e40f4d 
CMP       RBP,RDI
MOV       RDX,RBX
MOV       RCX,RAX
CMOVC     RDI,RBP
MOV       R8,RDI ; RDI ist eine Stack-Adresse nahe 14F3B0, daher ist der memcpy erfolgreich
CALL      memcpy

LAB_140e40f4d:
TEST      RBX,RBX
; Springt nie, da RBX == RDX == Datenpufferadresse, ungleich null.
JZ        LAB_140e40f62 

; Wir haben nun die vollständige Kontrolle über diesen RWE-Speicherbereich aufgrund des memcpy bei 144786150. RCE wurde erreicht!
MOV       RCX,qword ptr [DAT_144786998]
MOV       RDX,RBX
MOV       RAX,qword ptr [RCX]
CALL      qword ptr [RAX + 0x68]

Dieses Gadget erledigt fast alles für uns. Es ruft Offset 0x18 auf, um einen memcpy-Zielzeiger zu erhalten, kopiert unser Paket dorthin und ruft dann die virtuelle Funktion bei Offset 0x68 auf dem statischen Objekt bei 144786998 auf, das wir nun aufgrund des memcpy-Aufrufs vollständig kontrollieren. Da die durch den memcpy beschädigte Speichermenge groß ist und einige Regionen ständig von anderen Spiel-Threads beschrieben werden, lädt der Exploit zuerst eine „Setup“-Payload, die an einen sicheren Ort kopiert wird, unterbricht alle anderen Threads und kopiert unsere tatsächliche Payload erneut, bevor er zu ihr springt. Weitere Informationen finden Sie in rce.h.

Zusätzliche Informationen

Ich empfehle, sich den Quellcode des Proof-of-Concept-Codes anzusehen, da er viele Kommentare zur Struktur des Pakets enthält. Wenn Sie sehen möchten, was bei jedem Schritt in Echtzeit passiert (das sollten Sie, es ist ziemlich cool!), können Sie die Proof-of-Concept-DLL injizieren, während das Spiel unter einem Debugger mit Haltepunkten an den folgenden relevanten Adressen läuft:

140ca5960

Im Wesentlichen, wo der Exploit beginnt. Diese Funktion ist für das Parsen der größenbegrenzten Eintragslistendaten der PushRequestVisit-Nachricht verantwortlich. Sie extrahiert zuerst jeden Eintrag der Liste in verschiedene Vektoren:

root@kitploit:~
0x140ca59f8:
    player_data_cpy_ptr = (std_vector *)VectorCopy2_140ca4ef0(&player_data_cpy,player_data);
    FUN_140ca5010(player_data_cpy_ptr,&spawn_data,0x1c);
    FUN_140ca5010(player_data_cpy_ptr,&unk,4);
    FUN_140ca4fa0(player_data_cpy_ptr,&nrssr_data);

Die Funktion 140ca5010 prüft die Eintragsgrößen, aber 140ca4fa0 ist für variable Größen und führt keine Plausibilitätsprüfung des Größenfelds durch (Fehler #1). Um die oben beschriebene beliebige Code-Umleitung zu erreichen, müssen wir es auf 14F3B0 setzen. Dies verursacht einen Out-of-Bounds-Lesezugriff von ca. 1,3 MiB, aber die Speicherseite sollte groß genug sein, um Zugriffsverletzungen zu vermeiden.

140ca56b0

Diese Funktion wird von der vorherigen mit nrssr_data als Argument aufgerufen. Erstellt das DLMemoryInputStream-Objekt auf dem Stack, das dann als Argument an den NRSSR-Parser übergeben wird.

141955f50: ParseNRSessionSeachResult

Der NRSessionSearchResult-Parser. Überprüft NRSSR-Signatur und Versionsnummern (14196a0f0), parst die Eigenschaftenliste (14196a260), den Hostnamen (14195603a) und einige weitere Informationen (siehe rce.h)

14195603a

Schleife in der obigen Funktion, die den Hostnamen unsicher kopiert (Fehler #2). Hier sind einige Adressen, die helfen, den Überblick über das Geschehen während des Pufferüberlaufs zu behalten:

  • Parser-Stack-Puffer-Adresse: 14F128
  • DLMemoryInputStream-Stack-Adresse: 14F3A0
  • DLMemoryInputStream-vtable-Zeiger nach dem Überschreiben: 1439e8b30
  • Offset der virtuellen Funktion im DLMemoryInputStream, die vom DLInputStreamReader verwendet wird: 0x18

1439e8b48

root@kitploit:~
MOV       RCX,qword ptr [RCX + 0x8]
MOV       RAX,qword ptr [RCX]
JMP       qword ptr [RAX + 0x40]

Wohin wir nach der ersten Code-Umleitung gelangen, die durch die überschriebene Speicherstrom-vftable verursacht wird. Hier beginnt die Kette der virtuellen Aufruf-Umleitungen.

Footnotes

  1. Für Dark Souls III Ver. 1.15. Die maximale theoretische Payload-Größe hängt vom Stack-Layout ab und variiert daher je nach Spiel und Version. ↩

Tool herunterladen