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
CVE-2024-30051 — Analisi tecnica dettagliata e exploit proof-of-concept per CVE-2024-30051, un heap-based buffer overflow nella libreria Windows DWM Core Library che consente l'escalation dei privilegi locali al livello Integrity System. | Kitploit
Strumenti/GitHubGitHub/fortra/cve-2024-30051
Escalation di PrivilegiAnalisi delle VulnerabilitàExploitReverse EngineeringApprendimento e FormazioneBinary Exploitation
GitHubfortra/cve-2024-30051

CVE-2024-30051

Analisi tecnica dettagliata e exploit proof-of-concept per CVE-2024-30051, un heap-based buffer overflow nella libreria Windows DWM Core Library che consente l'escalation dei privilegi locali al livello Integrity System.

Vedi Repository
12636122 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

Vulnerabilità di Elevazione dei Privilegi nella Libreria DWM Core di Windows (CVE-2024-30051) (Pubblicata il 15 Agosto 2024)

In questo post del blog, spiegherò una vulnerabilità nella libreria DWM Core di Microsoft Windows che ho analizzato quando lo exploit per Core Impact veniva sviluppato. Permette a un utente malintenzionato non privilegiato di eseguire codice come utente DWM con privilegi di Integrità di Sistema (CVE-2024-30051).

Poiché all'epoca non c'erano abbastanza informazioni pubbliche per sviluppare l'exploit, ho dovuto fare molto reverse engineering, quindi qui mostrerò come fare il reverse della patch KB5037771 per Windows 23H2 usando IDA PRO, userò BINDIFF per eseguire un binary diffing tra dwmcore.dll versione 10.0.22621.3447 e versione 10.0.22621.3593, mostrerò come viene prodotto l'heap overflow e poi lo sfrutterò elevando i privilegi, infine creerò un PoC funzionante.

Indice:

[Windows DWM Core Library Elevation of Privilege Vulnerability (CVE-2024-30051) 1](#windows-dwm-core-library-elevation-of-privilege-vulnerability-cve-2024-30051)

[Dettagli della vulnerabilità: 2](#dettagli-della-vulnerabilità)

[Diffing per trovare il bug: 3](#diffing-per-trovare-il-bug)

[Analisi del PoC che sfrutta CVE-2024-30051: 8](#analisi-del-poc-che-sfrutta-cve-2024-30051)

[1) Inizializzazione 8](#inizializzazione)

[2) Hooking 8](#hooking)

[3) Creazione della finestra 16](#creazione-della-finestra)

[4) Creazione del Device 16](#creazione-del-device)

[5) Creazione della Factory 22](#creazione-della-factory)

[6) Creazione di un Device Context 28](#creazione-di-un-device-context)

[7) Creazione di un Composition Device 29](#creazione-di-un-composition-device)

[8) Chiamata della funzione hook3 31](#chiamata-della-funzione-hook3)

[9) Creazione del target per HWND 32](#creazione-del-target-per-hwnd)

[10) Creazione della Surface 33](#creazione-della-surface)

[11) Chiamata a BeginDraw, EndDraw e CreateVisual 34](#chiamata-a-begindraw-enddraw-e-createvisual)

[12) Chiamata a Visual SetContent 36](#chiamata-a-visual-setcontent)

[13) Rilascio degli oggetti 38](#rilascio-degli-oggetti)

[14) Commit del Composition Device 38](#commit-del-composition-device)

[15) Chiamata a hook2 39](#chiamata-a-hook2)

[16) Chiamata a hook 39](#ricorda-che-la-funzione-vulnerabile-può-essere-raggiunta-usando-alcuni-metodi-della-classe-cprimitivegroup.-a-questo-punto-crea-un-heap-poi-hook2-cattura-e-salva-il-corrispondente-heaphandle.)

[17) Chiamata a hook4 41](#chiamata-alla-funzione-hook4)

[18) Esecuzione dell'Heap Spray 49](#esecuzione-dellheappray)

[19) Modifica del chunk base prima dell'invio 51](#modifica-del-chunk-base-prima-dellinvio)

[20) Debug del processo DWM 52](#debug-del-processo-dwm)

[21) Elevazione dei privilegi al livello Integrity System 62](#elevazione-dei-privilegi-al-livello-integrity-system)

Dettagli della vulnerabilità:

Vulnerabilità di Elevazione dei Privilegi nella Libreria DWM Core di Windows CVE-2024-30051

Rilasciata: 14 maggio 2024

CNA assegnante: Microsoft CVE-2024-30051

Impatto: Elevazione dei Privilegi

Gravità massima: Importante

Debolezza:

CWE-122: Buffer Overflow basato su Heap

CVSS: 3.1 7.8 / 7.2

La vulnerabilità esiste a causa di un errore di calcolo della dimensione in una divisione intera all'interno della principale libreria DWM di Windows chiamata dwmcore.dll. Un utente locale può causare un buffer overflow nell'heap nel metodo CCommandBuffer::Initialize in dwmcore.dll e può eseguire codice arbitrario con l'utente DWM con privilegi di Integrità di Sistema. L'exploit eseguirà un Heap Spray nel processo DWM per preparare la memoria e infine produce un Heap Overflow in dwmcore.dll che verrà attivato rilasciando determinate parti dell'heap spray.

Una volta che l'exploit ha successo, il processo DWM caricherà la nostra DLL appositamente creata che esegue il nostro codice o il nostro eseguibile (nel nostro caso un CMD) come utente DWM che ha privilegi di Integrità di Sistema.

Esaminiamo questa vulnerabilità e vediamo come ci permette di eseguire come utente DWM con Livello di Integrità SYSTEM. Si noti che poiché non si tratta di un utente appartenente al gruppo Amministratori, ha alcune restrizioni di privilegi.

Diffing per trovare il bug:

La patch per Windows 11 23H2 può essere scaricata da:

https://www.catalog.update.microsoft.com/Search.aspx?q=KB5037771

windows11.0-kb5037771-x64_19a3f100fb8437d059d7ee2b879fe8e48a1bae42.msu

La versione vulnerabile di dwmcore.dll è: 10.0.22621.3447

La versione patchata di dwmcore.dll è: 10.0.22621.3593

Analizzando le funzioni modificate, è chiaro che la versione patchata di CCommandBuffer::Initialize ha molti blocchi aggiunti, rendendola molto diversa dalla versione non patchata.

Dopo aver fatto reverse engineering statico di quella funzione, ci sono due chiamate a CD2DSharedBuffer::GetBufferSize.

La prima chiamata ottiene la dimensione da allocare nel new e la seconda chiamata ottiene la stessa dimensione per il memcpy.

Tutto sembra inizialmente corretto. Tuttavia, prima dell'allocazione, esegue alcune operazioni con la dimensione.

Ottiene buffer_size e buffer_size2 chiamando la stessa funzione CD2DSharedBuffer::GetBufferSize, che restituisce entrambi lo stesso valore. Ma nel new esegue una pre-operazione, una divisione intera di buffer_size per 0x90 e poi moltiplicazione per 0x90, mentre nel memcpy usa il buffer_size2 restituito senza operare su di esso.

Con queste operazioni, ho scoperto che la dimensione finalmente usata nel new e nel memcpy può essere diversa.

buffer_size = buffer_size2 (dimensioni restituite)

size_new = buffer_size / 0x90 x 0x90

size_memcpy = buffer_size2

Ad esempio, se buffer_size è 0x91

buffer_size = buffer_size2 = 0x91

size_new = buffer_size / 0x90 x 0x90 = 0x90

size_memcpy = buffer_size2 = 0x91

Questo esempio dimostra che c'è un heap overflow. Copia più byte di quanti allocati, e la dimensione è controllabile.

Ad esempio, se buffer_size è 0x23f come usato nel POC.

buffer_size = buffer_size2 = 0x23F

size_new = buffer_size / 0x90 x 0x90 = 0x1b0

size_memcpy = buffer_size2 = 0x23f

Analizzata la funzione vulnerabile, volevo vedere come raggiungere la funzione vulnerabile CCommandBuffer::Initialize. È qui che le cose iniziano a complicarsi.

Rivedendo i riferimenti a questa funzione, sembra essere raggiunta dai metodi della classe CPrimitiveGroup:

Tali metodi possono essere accessibili dalla vftable degli oggetti CPrimitiveGroup:

Ha il suo costruttore:

E viene raggiunto in questo modo:

Mentre inizialmente attraversavo questo processo, mi sono preso il tempo di leggere il PDF “The Lost World of DirectComposition: Hunting Windows Desktop Window Manager Bugs” e mi sono immerso nel mondo di Direct Composition. Questo mi ha aiutato a creare il mio primo PoC.

Inoltre, avevo bisogno di fare reverse di win32ksys e ho provato a inviare pacchetti attraverso le funzioni:

  • NtDCompositionCreateChannel

  • NtDCompositionProcessChannelBatchBuffer

  • NtDCompositionCommitChannel

Il mio primo PoC ha raggiunto il costruttore di CPrimitiveGroup. Tuttavia, dopo molto reverse engineering, non ho trovato un modo per gestire le chiamate ai metodi della vftable per arrivare alla funzione vulnerabile direttamente attraverso chiamate ALPC usando queste funzioni.

Ho passato molto tempo a fare reverse engineering complicato. Durante questo processo, ho trovato il campione del malware che sfruttava la vulnerabilità, il che è stato immensamente utile perché il metodo di sfruttamento è molto più complesso di quanto pensassi inizialmente. Include anche diversi hook di API di sistema e usa metodi che forse sono un po' discutibili. Ma tutto è valido in guerra e negli exploit, quindi ho iniziato ad analizzare il malware e da quell'analisi ho creato il mio PoC finale che finalmente sfrutta la vulnerabilità, che spiegherò di seguito.

Prima di tutto, voglio chiarire che il malware non solo sfrutta la vulnerabilità CVE-2024-30051 che eleva il nostro processo a Livello di Integrità di Sistema, ma esegue anche una seconda parte che da lì finisce per elevare un utente SYSTEM con tutti i privilegi, il che va già oltre il CVE spiegato.

Inoltre, è importante notare che il malware è molto più complesso del mio PoC, che cerca di minimizzare il codice. Il malware esegue molti più controlli per garantire l'affidabilità e per questo funziona al primo tentativo. Ho scartato tutti quei controlli per semplificare e mi sono dedicato allo sfruttamento puro, anche se forse è necessario eseguire il PoC due o tre volte per ottenere lo sfruttamento.

Analisi del PoC che sfrutta CVE-2024-30051:

1) Inizializzazione

Il link al PoC eseguibile è https://github.com/fortra/CVE-2024-30051

Prima di tutto, il PoC chiama GetVersion per ottenere la versione del sistema operativo su cui è in esecuzione e secondo quella esegue diverse inizializzazioni di alcune variabili globali. Il mio PoC è stato testato su Windows 11 23H2 e Windows 11 22h2. Anche altri sistemi sono vulnerabili e ho aggiunto i valori per sfruttarli.

2) Hooking

Esegue l'hook di quattro funzioni di sistema e senza hookarle non può ottenere lo sfruttamento. Queste funzioni sono: RtlAllocateHeap, RtlCreateHeap, NtDCompositionCreateChannel e NtDCompositionCommitChannel.

In queste funzioni modificherà i primi 5 byte per farle saltare al proprio codice. Naturalmente, il codice non può essere molto lontano poiché un salto di 5 byte non copre tutta la memoria e deve essere vicino.

Per farlo, il malware usa un codice molto lungo, analizzando la mappa di memoria per decidere dove può eseguire l'allocazione del proprio codice. Poiché il codice è complicato, mi sono concentrato su due semplici righe:

base_ntdll = GetModuleHandleW(L"ntdll.dll");

global4_ = (char *)VirtualAlloc((LPVOID)(base_ntdll-0x2000), 0x1000uLL, 0x3000u, 0x40u);

Ho sottratto dalla base di ntdll, 0x2000 e ho passato quell'indirizzo a VirtualAlloc per allocare lì.
Le DLL a 64 bit sono mappate abbastanza separatamente nella memoria l'una dall'altra con spazi vuoti tra di loro.
Vediamo come funzionano gli hook:

Chiama una funzione di hooking, che è quella che eseguirà l'hooking dell'API RtlAllocateHeap, che ha tre argomenti, il primo è l'indirizzo dell'API da patchare, chiamato sym_RtlAllocateHeap.
Prima della patch, punta all'inizio dell'API:

Ecco la funzione RtlAllocateHeap:

Il secondo argomento è la routine chiamata hook che verrà eseguita quando l'API è completamente patchata:

La funzione hook chiama my_RtlAllocateHeap.

La funzione hooking modificherà i primi 5 byte dell'API in modo che salti a hook.

Chiamerà il codice nell'area allocata dove eseguirà la prima istruzione dell'API che è stata sostituita con i 5 byte e poi salterà a RtlAllocateHeap+5 subito dopo i byte patchati:

Ecco come apparirà l'API dopo l'hook. I primi 5 byte sono cambiati in modo che salti a hook. Chiamerà my_RtlAllocateHeap il codice che è appena sopra che tornerà all'area evidenziata in viola per continuare l'esecuzione dell'API:

Quando l'API termina l'esecuzione, tornerà a hook. Da lì confronterà la variabile globale heap_base (che inizialmente è zero) con il primo argomento passato a RtlAllocateHeap:

Dopodiché il codice attende una certa allocazione speciale, che ha uno specifico HeapHandle. All'inizio questa variabile è zero e finché è zero salterà e funzionerà come un normale RtlAllocateheap:

Il parametro HeapHandle viene ottenuto all'interno di RtlCreateHeap che è casualmente la seconda API hookata.

Cercando riferimenti alla variabile globale heap_base, cambia il suo valore solo nella funzione hook2, che è quella eseguita dopo l'hooking di RtlCreateHeap:

Quindi, l'idea è catturare un certo HeapHandle e salvarlo in heap_base. Poiché ora è diverso da zero, la funzione hook inizierà a confrontare ogni allocazione. Quindi, il PoC salverà l'indirizzo di memoria che ha lo stesso HeapHandle di quello precedentemente memorizzato.

Quando è questo il caso, salverà l'indirizzo dell'allocazione nella variabile chiamata base:

Questi primi due hook sono ora concatenati. Quando hook2 salva il valore atteso di HeapHandle, attiva la funzione hook che salverà l'indirizzo dell'allocazione che usa lo stesso HeapHandle.

Il terzo hook è inviato a NtDCompositionCreateChannel. La prima volta che viene chiamato salverà il MappedAddress, che è il contenuto del terzo argomento. Da lì cambierà hooked_flag a 1 così da allora in poi non salverà più e funzionerà normalmente.

L'indirizzo salvato nella variabile base verrà letto successivamente tre volte. Due di queste avverranno nell'ultimo hook, chiamato hook4:

La funzione hook4 per NtDCompositionCommitChannel sarà analizzata in seguito perché è piuttosto complessa e molto importante.

3) Creazione della finestra

Dopo che i quattro hook sono completati, torna alla funzione principale per iniziare a creare una finestra. Questo viene fatto chiamando RegisterClassExW. Tuttavia, per registrare una classe di finestra per un uso successivo, dovrebbe essere chiamata con CreateWindowExW function.

Questo inizializza la libreria COM chiamando CoInitializeEx per essere usata dal thread chiamante:

Calcola la dimensione richiesta del rettangolo della finestra, basata sulla dimensione desiderata:

La funzione CreateWindowExW viene chiamata per creare una finestra che verrà disegnata:

4) Creazione del Device

Da lì, chiama D3D11CreateDevice per creare un device o dispositivo DirectX che rappresenta l'adattatore video:

Nel mio PoC ppDevice è chiamato d3dDevice e ppImmediateContext è chiamato d3dContext:

L'argomento flags deve essere impostato a 0x20:

Poi chiama AddRef:

Questo incrementa il contatore di riferimento per un puntatore a interfaccia di un oggetto COM:

Il valore 0x10 viene sottratto a THIS:

All'offset 0xf8 da ID3D11Device-0x10 c'è un puntatore a TComObject:

Questo sarà il nuovo THIS e finisce per saltare a TComObject::AddRef:

E termina aggiungendo uno al contatore oggetto che si trova nell'offset 8 di TComObject:

Poi, AddRef incrementerà il contatore dell'altro tipo di oggetto creato in D3D11CreateDevice, che è di tipo ID3D11DeviceContext:

In questo caso, per trovare il nuovo THIS, sottrae 0x108:

Salta qui dove all'offset 0x98 c'è il nuovo THIS:

Questo è il contatore. In questo esempio, è un QWORD:

5) Creazione della Factory

Il PoC chiama D2D1CreateFactory per usare Direct2D, e per creare l'interfaccia ID2D1Factory che viene usata per creare altre risorse Direct2D che possono essere utilizzate per disegnare o descrivere forme:

L'argomento riid è quello suggerito dalla pagina Microsoft:

https://learn.microsoft.com/en-us/windows/win32/api/d2d1/nf-d2d1-d2d1createfactory

Questi sono quelli usati dal malware:

Quello giusto per ID2D1Factory si può trovare qui**:**

https://github.com/apitrace/dxsdk/blob/master/Include/d2d1_1.h

Poiché non sono un esperto di Direct Composition, ho quindi usato gli stessi passaggi del malware:

La nuova factory restituita non fornisce alcun tipo dettagliato. Dice void *, il che significa che non è ufficialmente documentata:

Poiché non conosco un tipo di oggetto come in questo caso, ho sviluppato un eseguibile che lo usa per vederlo facilmente in memoria:

Aggiungi breakpoint nelle quattro funzioni hook. In questo caso, un breakpoint in hook2 mostrerà quando cattura il HeapHandle:

L'hook dovrebbe fermarsi quando il chunk desiderato viene catturato:

Metti breakpoint negli altri due hook:

Poi continua chiamando QueryInterface:

https://help.solidworks.com/2020/english/api/sldworksapi/queryinterface_example_cplusplus_com.htm

https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/shared/dxgi.idl

Tenta di eseguire una sorta di casting dinamico. Se l'oggetto di tipo ID3D11Device può accettare l'interfaccia (usare i metodi, ecc.) di IDXGIDevice, crea una copia dell'oggetto originale che accetta il nuovo tipo, dopodiché restituisce il puntatore a esso. In questo caso la variabile d3dContext1 sarà di tipo IDXGIDevice:

Entrambi gli oggetti ereditano da CLayeredObject<Cdevice>

L'originale ID3D11Device è**:**

Come quello che restituisce il puntatore.

Poi crea un oggetto ID2D1Device con la funzione CreateDevice:

In value2 restituisce un oggetto di tipo ID2D1Device.

6) Creazione di un Device ContextA questo punto, la PoC crea un nuovo contesto di dispositivo da un dispositivo Direct2d. Utilizzando la funzione CreateDeviceContext

https://learn.microsoft.com/en-us/windows/win32/api/d2d1_1/nf-d2d1_1-id2d1device-createdevicecontext

Ecco come è implementato nella PoC:

7)Creare un Dispositivo di Composizione

Poi chiama DCompositionCreateDevice

https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-dcompositioncreatedevice

L'IID appartiene a _IDCompositionDevice

8)Chiamata della Funzione DCompositionCreateDevice

Nello stesso momento in cui la funzione viene tracciata su DCompositionCreateDevice, si ferma a hook3, quando chiama NtDCompositionCreateChannel:

In questo modo viene catturato il MappedAddress che il sistema utilizza internamente quando DCompositionCreateDevice è stata chiamata:

Questo è lo stack di chiamate fino a qui:

Questo è il punto in cui il modulo dcomp chiama la funzione NtDCompositionCreateChannel:

9)Creare un Target per Handle HWND

Dopo essere tornato dal passo precedente, salva il MappedAddress. Utilizzando ALPC, si connetterà al processo DWM e poi chiamerà CreateTargetForHwnd

https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-idcompositiondevice-createtargetforhwnd

Utilizza l'handle HWND della finestra creata. È correlato al dispositivo che ho appena creato, che è il THIS di questo metodo:

10)Creare una Superficie

Poi chiama CreateSurface

https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-idcompositiondevice-createsurface

11)Chiamata a BeginDraw, EndDraw e CreateVisual

Poi chiama BeginDraw, EndDraw, e arriva a CreateVisual.

Chiama BeginDraw

https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-idcompositionsurface-begindraw

Questo utilizza l'IID _IDXGISurface:

Poi utilizza EndDraw:

https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-idcompositionsurface-enddraw

Infine, chiama CreateVisual:

https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-idcompositiondevice-createvisual

12)Chiamata a Visual SetContent

Successivamente, chiama IDCompositionVisual::SetContent:

https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-idcompositionvisual-setcontent

E chiama SetRoot:

L'updateObject ricevuto in BeginDraw non specifica nella documentazione di che tipo sia.

13)Rilasciare gli Oggetti

Successivamente, rilascia gli oggetti creati in precedenza:

14)Commit del Dispositivo di Composizione

E ora utilizzando lo stesso oggetto dcompDevice di tipo IDCompositionDevice, chiama il metodo Commit:

15)Chiamata a hook2

Chiamare quel metodo Commit si ferma su hook2 che cattura il desired HeapHandle:

Questo è lo stack di chiamate ora:

Ricorda che la funzione vulnerabile può essere raggiunta utilizzando alcuni metodi della classe CPrimitiveGroup. A questo punto crea un Heap, poi hook2 cattura e salva il corrispondente HeapHandle.

16)Chiamata alla Funzione Hook

Prima di tornare al main, crea anche un chunk utilizzando RtlAllocateHeap. Viene quindi intercettato e memorizzato nella variabile base all'interno della funzione hook:

Le chiamate a Create e Allocate vengono eseguite una dopo l'altra:

Entrambe (Allocate e Create) vengono chiamate da DirectComposition::Cdevice::Commit:

17)Chiamata alla Funzione hook4

Dopo di che, quando viene chiamato NtDCompositionCommitChannel, si ferma su hook4:

NtDCompositionCommitChannel viene chiamato da qui:

Viene anche chiamato da DirectComposition::Cdevice::Commit

Vale la pena menzionare che il sistema ha già messo in coda i comandi da inviare tramite ALPC a DWM. Dopo di che, invia comandi utilizzando NtDCompositionCommitChannel.
La funzione hook4 intercetta le chiamate a NtDCompositionCommitChannel e a questo punto verranno aggiunti ulteriori comandi alla coda.

Vediamo cosa fa hook4:

Viene eseguito un ciclo attraverso il chunk puntato da base.

Esce dal ciclo quando trova il valore 0x120 all'interno del chunk:

Memorizza l'indirizzo e l'offset dove è stato localizzato il valore 0x120:

Sovrascrive il valore 0x120 con value4, che è uguale a 0x1b0 + 0x8f = 0x23f. Questa è la dimensione che utilizzerà in memcpy quando si verifica l'overflow:

Aggiunge 0xbc + 0x90 al puntatore all'indirizzo dove si trovava 0x120:

Ricorda che all'offset 0x48 da base c'era la dimensione 0x120. Quella è stata sovrascritta con 0x23f, quindi il chunk originale deve avere dimensione 0x120:

La sorgente è il puntatore all'indirizzo di 0x23f + 0x2c:

Inizialmente aveva aggiunto 0x90 ma ora sta sottraendo di nuovo 0x90.
La destinazione sarà l'indirizzo del puntatore a 0x120 + 0xbc:

Scriverà su questo:

Tutte le scritture saranno all'interno del chunk:

Ripeterà il ciclo 3 volte, che è il risultato della divisione intera di 0x1b0/0x90:

Dopo di ciò, poiché il canale ArgChannelHandle è lo stesso che è stato utilizzato quando MappedAddress è stato catturato. La PoC aggiungerà comandi al batch utilizzando NtDCompositionProcessChannelBatchBuffer. Questi verranno elaborati insieme a quelli che il sistema aveva già aggiunto. Il batch li raccoglie e poi i comandi vengono inviati tutti insieme utilizzando NtDCompositionCommitChannel:

Il comando inviato ha il valore 8, che corrisponde a SetResourceIntegerProperty per 4 diversi tracker (1,2,3 e 4).

18)Esecuzione di Heap Spray

Quando la PoC ritorna alla funzione main, crea un canale diverso per eseguire l'HeapSpray.

Mette in coda 0x10000 comandi, che vengono inviati con NtDCompositionCommitChannel:

Questo utilizza il valore CreateResource=1 e il tipo che corrisponde a CHolographicInteropTextureMarshaler = 0x50:

Le allocazioni vengono eseguite nel codice sottostante. La dimensione degli oggetti creati per effettuare lo spray è 0x1b0:

Esegue quindi un ciclo per rilasciare gli oggetti creati nel passo precedente e ora crea buchi nella distribuzione di memoria.
La variabile counter2 inizia a 0x3000 e aggiunge passi di 0x20 fino a quando è minore di 0x7000:

19)Modifica del Chunk Base Prima dell'Invio

Scrive 0x41 dall'indirizzo del chunk che era in base + 0x48 + 44 + 0x1b0
Cioè, sta scrivendo valori che verranno utilizzati in seguito—quando si verifica l'overflow del chunk adiacente:

Quel pvalue7 si trova all'indirizzo 0x224 da base:

Poi va alla funzione “escribe”:

Scrive la pKernelCallbacktable più 0x388, l'indirizzo di LoadLibraryA e il percorso della DLL che verrà caricata. In questo caso, l'ho chiamata s11.dll.

20)Debug del Processo DWM

Ora è necessario un debugger kernel per fermarsi alla funzione vulnerabile quando si verifica l'heap overflow. Questo perché il processo DWM non può essere debugato con un debugger user mode.

Utilizzando IDA PRO per eseguire il debug remoto del target, imposta un breakpoint condizionale in modo che si fermi quando la dimensione è uguale a 0x1b0:

print ("VALUE1 %x" % ((cpu.rax)))
return cpu.rax==0x1b0.

Poiché un programma in user mode viene debugato dal kernel, è necessario passare al contesto del processo DWM per inserire il breakpoint. Ricarica i simboli utente con:

. reload /user

Ricarica quelli del kernel con:

. reload /f

Si fermerà quando ShowWindow viene eseguito passo passo:

Alloca con dimensione 0x1b0 e copia con dimensione 0x23f, producendo l'heap overflow:

A questo punto lo stack di chiamate appare così:

Per creare l'overflow, il DWM riceve valori nel codice sottostante:

I valori manipolati in base inviati dalla mia PoC vengono letti utilizzando MapViewofFile dal processo DWM nel modulo dwmcore.dll:

La funzione precedente viene chiamata da:

Quando viene inviato tramite ALPC da hook4 utilizzando destination_copy (NtDCompositionCommitChannel) si ferma:

Ricorda che in hook4 sono stati aggiunti comandi al batch. Tuttavia, il sistema aveva già aggiunto alcuni comandi al batch, inclusi base e i dati manipolati:

In questo caso condivide un'area di memoria che inizia a 000001cd'178d0000. Quando viene utilizzata come sorgente per eseguire il memcpy, sarà a 0x794 byte più avanti nella stessa area di memoria.

La dimensione dell'area di memoria condivisa è 0x4000:

Si fermerà quando la dimensione da allocare è 0x1b0, e raggiunge il memcpy per copiare 0x23f byte:

Oltre 0x1b0 nella memoria si trova il codice che overflowerà sovrascrivendo il blocco adiacente:

Quando i chunk vengono rilasciati dalla PoC, termina saltando a LoadLibraryA, che carica la libreria manipolata:

Ciò proviene da qui:

L'Heap spray è stato effettuato con oggetti di dimensione 0x1b0 di tipo CHolographicInteropTexture.

Poiché avevo creato buchi nella distribuzione di memoria, questo rilascia alcuni oggetti. Poiché il blocco che andrà in overflow ha anch'esso dimensione 0x1b0, ha un'alta probabilità di essere posizionato nei buchi dell'heap spray.

Alla destinazione del memcpy, i blocchi si trovano ogni 0x1b0 byte:

Il puntatore a una vftable viene sovrascritto dal puntatore a LoadLibrary:

Prima della sovrascrittura:

Dopo la sovrascrittura:

Ricorda che è terminato saltando a [R11+50], che è il puntatore a LoadLibraryA.

21)Elevazione dei Privilegi a Integrity System Level

Eseguendo la PoC, copia la DLL nello stesso percorso indicato nella PoC:

Dopo aver eseguito la PoC, viene eseguito un processo CMD con privilegi di Integrity System Level dell'utente DWM:

Riferimenti:

PoC su GitHub di Fortra: https://github.com/fortra/CVE-2024-30051

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-30051

https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2024-30051

Questo completa la PoC. Ricorda che se la esegui molte volte, l'heap rimarrà in uno stato instabile, quindi potrebbe essere necessario riavviare la macchina per farla funzionare di nuovo. Inoltre, anche se potrebbe non funzionare sempre al primo tentativo, di solito funziona correttamente al secondo o terzo tentativo. Come puoi vedere, il reverse engineering può essere difficile, quindi se hai domande, puoi consultarmi.

Mail: [email protected]

X: @ricnar456

Scarica lo strumento