Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
ds3-nrssr-rce — Documentazione e codice proof of concept per CVE-2022-24125 e CVE-2022-24126. | Kitploit
Strumenti/GitHubGitHub/tremwil/ds3-nrssr-rce
Framework di ExploitAnalisi delle VulnerabilitàExploitReverse EngineeringShellcodePenetration TestingApprendimento e FormazioneRed TeamingGenerazione di ShellcodeSviluppo PayloadBinary Exploitation
16983 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
GitHub
tremwil/ds3-nrssr-rce

ds3-nrssr-rce

Documentazione e codice proof of concept per CVE-2022-24125 e CVE-2022-24126.

Vedi Repository

Aggiornamento: Dark Souls III 1.15.1

Un nuovo aggiornamento di gioco, 1.15.1, è stato rilasciato per Dark Souls III il 25/08/2022, insieme al ripristino dei servizi online. Questo aggiornamento ha corretto sia CVE-2022-24125 che CVE-2022-24126, insieme a un'ampia varietà di altre potenziali vulnerabilità di sicurezza presenti nella rete P2P del gioco (letture/scritture fuori dai limiti). Inoltre, tutti gli exploit conosciuti che permettevano di corrompere il salvataggio di altri giocatori sono stati risolti. Molti comuni cheat di poco conto (ad es. "coltello della maledizione") che si potevano incontrare spesso durante il multiplayer online sono stati anche corretti.

ds3-nrssr-rce

Questo repository contiene codice proof of concept e documentazione per il più recente exploit RCE che colpisce i giochi FROM SOFTWARE, CVE-2022-24126. Sebbene teoricamente possibile in altri giochi, l'attenzione è su Dark Souls III poiché è il gioco su cui è stata condotta la mia ricerca. Al momento il codice proof of concept esiste solo per Dark Souls III; la vulnerabilità è stata confermata presente in:

  • Dark Souls 1 PTDE (crediti: LukeYui)
  • Dark Souls Remastered (crediti: metal-crow)
  • Dark Souls 2 (incluso Scholar) (crediti: LukeYui)
  • Dark Souls 3 (fino a 1.15.0) (crediti: tremwil)

Il codice vulnerabile è presente anche in Sekiro (crediti: LukeYui), sebbene non ci sia modo di attivarlo. La presenza in Demon's Souls non è stata confermata ma è molto probabile. Mentre il network test chiuso è stato colpito da ciò, la versione finale di Elden Ring non lo è. Di fatto, un'enorme lista di crash di rete, letture/scritture fuori dai limiti ed exploit che permettevano ai giocatori di modificare i dati di gioco dei pari, presenti in Dark Souls III, sono stati corretti in Elden Ring. Complimenti a LukeYui per aver compilato questa lista e a FROM SOFTWARE per aver agito rapidamente! Sono felice di dire che Elden Ring è innegabilmente il titolo FROM SOFTWARE più sicuro per quanto riguarda l'entità del danno che gli hacker possono infliggere.

Dissipare le idee sbagliate

Contrariamente a quanto si crede, questo NON è un exploit di rete peer-to-peer. È correlato al server di matchmaking e quindi molto più grave, poiché non è necessario partecipare ad alcuna attività multiplayer per essere vulnerabili a causa di un'altra vulnerabilità del server di matchmaking (CVE-2022-24125).

In Dark Souls III, un attaccante malintenzionato che abusasse di ciò sarebbe stato in grado di eseguire in modo affidabile un payload fino a 1,3 MiB1 di shellcode su ogni macchina di un giocatore online in pochi secondi.

Considerando che il gioco aveva una base di giocatori contemporanei media di circa 20.000 nei mesi precedenti la chiusura del server, era chiaramente un problema che necessitava di una correzione immediata, specialmente con la possibilità che fosse presente in Elden Ring. Poiché FROM SOFTWARE non aveva ancora agito dopo oltre 40 giorni dal mio rapporto iniziale con video proof of concept e documentazione dettagliata dell'exploit (su cui gran parte di questo readme si basa), ho deciso di dimostrare pubblicamente l'esistenza dell'exploit in modo benigno, nella speranza di attirare l'attenzione per farlo affrontare dagli sviluppatori, e ha funzionato.

Indice dei contenuti

  • Riepilogo dell'Exploit (CVE-2022-24126)
  • Vettori di Distribuzione (CVE-2022-24125)
  • La Tattica Generale di Sfruttamento per Tutti i Giochi
    • Bug #1: Nessun Controllo dei Limiti nel Parser dell'elenco delle Voci
    • Bug #2: Superamento del Buffer nel Parser NRSessionSearchResult
    • Preparare il Terreno per la Catena ROP
  • Codice Proof of Concept per Dark Souls III
    • Esecuzione del codice PoC
    • Vettore d'Attacco
    • Catena di Reindirizzamento delle Chiamate Virtuali
    • Informazioni Extra

Riepilogo dell'Exploit (CVE-2022-24126)

Un controllo errato dei limiti su un buffer dello stack e sul campo della dimensione dei dati durante l'analisi dei dati di matchmaking NRSessionSearchResult permette a un attaccante di eseguire codice arbitrario. L'overflow dello stack consente di sovrascrivere i due byte inferiori di vftable_ptr dell'oggetto DLMemoryInputStream utilizzato internamente dal lettore di flusso, reindirizzando l'esecuzione a codice vicino accuratamente scelto. Lo sfruttamento intelligente della struttura dell'oggetto DLMemoryInputStream e del campo della dimensione dei dati permette quindi di ottenere un reindirizzamento arbitrario del codice, con RCX che punta all'indirizzo del nostro pacchetto. Da lì, una serie di reindirizzamenti di codice tramite chiamate virtuali con offset diversi (che ora salteranno agli indirizzi che abbiamo scritto nel buffer del pacchetto) può essere utilizzata per ottenere l'esecuzione di codice arbitrario.

Vettori di Distribuzione (CVE-2022-24125)

I vettori di distribuzione sono ciò che rende questo particolare RCE particolarmente grave (al di là del fatto che è già un RCE). L'exploit viene trasmesso attraverso richieste push di matchmaking contenenti informazioni NRSessionSearchResult. Ciò significa che l'attaccante può prendere di mira chiunque si unisca alla sua sessione online. In particolare, per DS3:

  • evocazioni (PushRequestSummonSign)
  • invasori spiriti oscuri (PushRequestAllowBreakInTarget)
  • giocatori che si uniscono tramite covenant (PushRequestVisit)
  • combattenti dell'arena (PushRequestAcceptQuickMatch)

Questo è già piuttosto grave, ma il vero potenziale è sbloccato dalla richiesta RequestSendMessageToPlayers:

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

L'host usa questa richiesta per inviare direttamente il push message PushRequestAllowBreakInTarget agli invasori in modo che possano ottenere le coordinate di spawn e unirsi alla sessione P2P. Tutto qui. È l'unico modo in cui questa richiesta viene utilizzata dal gioco.

La Tattica Generale di Sfruttamento per Tutti i Giochi

Sebbene l'RCE non sia esattamente portabile a ogni gioco, l'idea centrale dell'exploit che fornisce all'attaccante il reindirizzamento arbitrario del codice è la stessa. Se questo può essere ottenuto, è molto probabile che si possa poi trovare una catena di chiamate virtuali o una catena ROP specifica per il gioco. Questo "primo passo" sfrutta le seguenti vulnerabilità:

Bug #1: Nessun Controllo dei Limiti nel Parser dell'Elenco delle Voci

Le richieste push di matchmaking contenenti informazioni di sessione memorizzano tali informazioni in un formato binario personalizzato che consiste in una catena di voci di dati delimitate dalla lunghezza. Ogni voce ha il seguente formato:

root@kitploit:~
struct Entry
{
    uint32_t type_or_id; // non sicuro, ma probabilmente un tipo (lunghezza fissa = 2, lunghezza variabile = 1 ?)
    uint32_t size;
    uint8_t data[size];
}

La funzione di gioco responsabile della copia dei dati di queste voci si fida ciecamente del campo size, creando una lettura fuori dai limiti. Questo può essere abusato da un client malintenzionato impostando il campo size su valori come 0x7FFFFFFF, causando il fallimento dell'allocazione di memoria e il crash del gioco della vittima. Successivamente, questa dimensione viene anche passata al costruttore di un DLMemoryInputSteam, che è una parte fondamentale dell'exploit.

Bug #2: Superamento del Buffer nel Parser NRSessionSearchResult

Una delle voci nella struttura dati descritta sopra è un oggetto NRSessionSearchResult serializzato. Il parser per questi dati analizza prima un elenco di proprietà. Queste proprietà possono essere interi a 4 byte, interi a 8 byte o stringhe wide con terminazione null. A questo elenco di proprietà segue il nome Steam dell'host come stringa wide con terminazione null e alcuni dati aggiuntivi non importanti per l'exploit. Sia questa funzione che il parser dell'elenco delle proprietà utilizzano un buffer dello stack di dimensione fissa per leggere le stringhe, e in entrambi i casi non viene eseguito alcun controllo dei limiti sul buffer. Ecco il codice di gioco responsabile della copia del nome dell'host (prodotto utilizzando il decompilatore di Ghidra e poi ripulito):

root@kitploit:~
size_t idx = 0;
wchar_t wchr = 0;
do {
  // funzione read_wchar() all'indice 17 della vftable di DLEndianStreamReader
  wchr = stream_reader->read_wchar();
  player_name_buff[idx] = wchr;
  idx++;
} while (wchr != 0);

Ciò porta a un exploit di superamento del buffer, permettendo all'attaccante di corrompere lo stack.

Preparare il Terreno per la Catena di Chiamate Virtuali / ROP

Per ottenere un reindirizzamento arbitrario del codice, utilizziamo questo e il layout di memoria di un oggetto DLMemoryInputStream istanziato sullo stack dalla funzione che chiama il parser, che viene utilizzato internamente dal lettore di flusso:

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)
    // Le voci dopo il buffer non sono importanti per l'exploit
}

Poiché controlliamo il campo data_size (Bug #1), può essere impostato sull'indirizzo di memoria dello stack del campo data_buffer. Ciò riuscirà a condizione che l'indirizzo sia costante e non troppo grande (DS3 soddisfa questi requisiti). Poiché il compilatore posiziona il buffer dello stack all'inizio del frame, l'attaccante può quindi utilizzare il Bug #2 per sovrascrivere i due byte inferiori di vftable_ptr del DLMemoryInputStream. Quindi, quando il carattere successivo viene letto da DLEndianStreamReader, chiamerà internamente il e il codice verrà reindirizzato. I 2 byte danno abbastanza margine per saltare alla 22ª funzione nella vftable di , che chiama il 6° metodo virtuale dell'oggetto puntato dal suo primo campo. In un processo a 64 bit (cioè Dark Souls III), verrebbero eseguite le seguenti istruzioni:

Vedi qui per maggiori dettagli su questi 3 gadget. Se per qualche altro gioco questo metodo di chiamata virtuale non è un approccio fattibile, il reindirizzamento arbitrario del codice può comunque essere utilizzato per impostare un exploit ROP più tradizionale.

Codice Proof of Concept per Dark Souls III

Esecuzione del codice PoC

Per eseguire il codice proof of concept, devi prima avere un server a cui connetterti. Mentre i server ufficiali sono stati disabilitati a causa dell'exploit, puoi impostarne uno privato usando ds3os. ds3os è progettato per imitare il comportamento del server retail il più fedelmente possibile, ma le patch di sicurezza sono già state implementate in questo progetto per risolvere questo exploit. Tuttavia puoi comunque impostare un ambiente di test compilando tu stesso il progetto con le costanti SEND_MESSAGE_TO_PLAYERS_SANITY_CHECKS e NRSSR_SANITY_CHECKS impostate su false in BuildConfig.h. Questo imita il comportamento pericoloso del server retail. Segui le istruzioni fornite da ds3os per avviare il gioco e connetterti al tuo server.

Una volta fatto ciò e il tuo gioco è connesso ai server, compila il codice PoC e avvia l'eseguibile Injector.exe. Inietterà una DLL contenente il codice exploit nel processo di Dark Souls III. Questa DLL utilizzerà quindi la funzione di gioco che invia messaggi FRPG al server per consegnare l'exploit al tuo stesso client.

Vettore d'Attacco

Per il proof of concept ho deciso di utilizzare un messaggio PushRequestVisit inviato tramite RequestSendMessageToPlayers. Questa è la versione più potente dell'exploit nel senso che il gioco del bersaglio analizzerà immediatamente i dati vulnerabili dopo averli ricevuti in tutte le situazioni (anche nel menu principale).

Catena di Reindirizzamento delle Chiamate Virtuali

Offset 0x18: 140e97700

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

Questo gadget viene utilizzato in quello all'offset 0x68. Dobbiamo mettere un indirizzo inferiore ma abbastanza vicino a 144786998 in RAX; questo è il più vicino.

Offset 0x40: 1422be020

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

Per poter utilizzare il gadget all'offset 0x68 abbiamo bisogno che l'indirizzo del buffer dati sia memorizzato in RDX e che RCX rimanga lo stesso. Questo realizza esattamente ciò.

Offset 0x68: 140e40f15

Informazioni Extra

Raccomando di controllare il codice sorgente del proof of concept poiché ha molti commenti che dettagliano la struttura del pacchetto. Se vuoi vedere cosa succede ad ogni passo in tempo reale (dovresti, è piuttosto interessante!), puoi iniettare la DLL del proof of concept mentre esegui il gioco sotto un debugger con punti di interruzione ai seguenti indirizzi di interesse:

140ca5960

Essenzialmente dove inizia l'exploit. Questa funzione è responsabile dell'analisi dei dati dell'elenco di voci delimitate dalla dimensione del messaggio PushRequestVisit. Estrae prima ogni voce dell'elenco in diversi vettori:

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);

La funzione 140ca5010 controlla le dimensioni delle voci, ma 140ca4fa0 è per voci di dimensione variabile e non esegue controlli di sicurezza sul campo size (Bug #1). Per ottenere l'exploit di reindirizzamento arbitrario del codice descritto sopra, dobbiamo impostarlo a 14F3B0. Ciò causerà una lettura fuori dai limiti di circa 1,3 MiB, ma la pagina di memoria dovrebbe essere abbastanza grande da evitare violazioni di accesso.

140ca56b0

Questa funzione viene chiamata dalla precedente con nrssr_data come argomento. Crea l'oggetto DLMemoryInputStream sullo stack che viene poi passato come argomento al parser NRSSR.

141955f50: ParseNRSessionSeachResult

Il parser NRSessionSearchResult. Verifica la firma NRSSR e i numeri di versione (14196a0f0), analizza l'elenco delle proprietà (14196a260), il nome dell'host (14195603a) e alcune altre informazioni (vedi rce.h)

14195603a

Ciclo nella funzione sopra che copia in modo non sicuro il nome dell'host (Bug #2). Ecco alcuni indirizzi che possono aiutare a tenere traccia di ciò che accade durante l'overflow del buffer:

  • Indirizzo del buffer dello stack del parser: 14F128
  • Indirizzo dello stack di DLMemoryInputStream: 14F3A0
  • Puntatore vtable di DLMemoryInputStream dopo la sovrascrittura: 1439e8b30
  • Offset della funzione virtuale nel DLMemoryInputStream utilizzato da DLInputStreamReader: 0x18

1439e8b48

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

Dove finiamo dopo il primo reindirizzamento del codice causato dalla vftable corrotta del flusso di memoria. Qui inizia la catena di reindirizzamenti delle chiamate virtuali.

Footnotes

  1. Per Dark Souls III Ver. 1.15. La dimensione massima teorica del payload dipende dal layout dello stack e quindi varierà in base al gioco e alla versione. ↩

Scarica lo strumento

Eppure permette a qualsiasi client di inviare messaggi push arbitrari a centinaia di migliaia di giocatori specifici.

Non posso sottolineare abbastanza quanto sia terribilmente insicuro. Qualsiasi giocatore può praticamente impersonare il server di matchmaking. Usando questa richiesta per inviare l'exploit tramite un PushRequestVisit, qualsiasi giocatore online può essere preso di mira a distanza dall'attaccante purché il suo ID giocatore sia noto. L'attaccante può anche inviare l'exploit all'intera base di giocatori online molto rapidamente inviando più richieste, ciascuna contenente un grande intervallo di possibili ID giocatore.

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

Poiché RCX è un puntatore all'oggetto DLMemoryInputStream, la prima istruzione scrive il campo data_size, che è stato impostato su un indirizzo dello stack che punta al campo data_buffer dall'attaccante utilizzando il Bug #1, in RCX. Le due istruzioni successive reindirizzeranno quindi l'esecuzione all'indirizzo di memoria che l'attaccante ha scritto all'offset 0x40 nel buffer dati. Il reindirizzamento arbitrario del codice è stato ora ottenuto! Da lì, l'attaccante può impostare una catena di reindirizzamento del codice che copia il proprio payload in una regione di memoria adatta e lo esegue scegliendo codice vicino a chiamate virtuali con offset diversi, poiché il buffer ora funge da tabella dei metodi virtuali. Per il proof of concept di Dark Souls III ho trovato una configurazione che richiede solo 3 gadget per ottenere l'RCE:

  • 0x18: 140e97700
  • 0x40: 1422be020
  • 0x68: 140e40f15
root@kitploit:~
; Salta qui dal gadget all'offset 0x40
MOV       RBX,RDX
CMP       R9,R8

 ; Non salta mai, 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

; Chiama gadget all'offset 18 (140e97700). Carica 144786150 in RAX
CALL      qword ptr [RAX + 0x18]
MOV       RSI,RAX
TEST      RAX,RAX

; Non salta mai, RAX è l'indirizzo del buffer dati.
JZ        LAB_140e40f4d 
CMP       RBP,RDI
MOV       RDX,RBX
MOV       RCX,RAX
CMOVC     RDI,RBP
MOV       R8,RDI ; RDI è un indirizzo dello stack vicino a 14F3B0, quindi la memcpy riesce
CALL      memcpy

LAB_140e40f4d:
TEST      RBX,RBX
; Non salta mai poiché RBX == RDX == indirizzo del buffer dati, diverso da zero. 
JZ        LAB_140e40f62 

; Ora abbiamo il pieno controllo di questa regione di memoria RWE grazie alla memcpy a 144786150. L'RCE è stato raggiunto!
MOV       RCX,qword ptr [DAT_144786998]
MOV       RDX,RBX
MOV       RAX,qword ptr [RCX]
CALL      qword ptr [RAX + 0x68]

Questo gadget fa quasi tutto per noi. Chiama l'offset 0x18 per ottenere un puntatore di destinazione per memcpy, copia lì il nostro pacchetto e poi chiama la funzione virtuale all'offset 0x68 sull'oggetto statico a 144786998, che ora controlliamo completamente a causa della chiamata memcpy. Poiché la quantità di memoria corrotta da memcpy è ampia e alcune regioni vengono costantemente scritte da altri thread di gioco, l'exploit carica prima un payload "di setup" che viene copiato in una posizione sicura, sospende tutti gli altri thread e ricopia il nostro payload effettivo prima di saltarci. Vedi rce.h per maggiori informazioni.