
Ricreando l'exp per cve-2023-21768.
Causa: Confrontando AFD.sys tra le build 202209 e 202307, nella funzione AfdNotifyRemoveIOCompletion, sia la build 202209 che quella 202307 di Windows hanno un passo in cui usano ProbeForWrite per controllare se una regione di memoria è in modalità utente, ma l'indirizzo del buffer controllato differisce di 0x8 byte. Prima della patch per questa vulnerabilità, non c'era questo controllo, quindi si può ipotizzare che l'indirizzo del buffer controllato nella build 202209 potesse essere sbagliato e quindi inefficace. Il buffer controllato è correlato a un'assegnazione intermedia: **(_DWORD **)(a3 + 24) = v20; dove il buffer da controllare dovrebbe essere a3+24, e il valore di v20 è correlato a v8 = IoRemoveIoCompletion(v25, Pool2, v4, (unsigned int)v6, &v20, a1, v13, 0), dove almeno Pool2, v4, v13 sembrano essere determinati dalla struct sconosciuta passata dalla modalità utente, quindi si suppone che anche v20 sia correlato a quella struct passata dalla modalità utente (dopo aver visto il writeup, è il valore di ritorno di IoRemoveIoCompletion che chiama KeRemoveQueueEx).
Se a3+24 memorizza un indirizzo in modalità kernel, potrebbe creare una primitiva di kernel arbitrary write, che può poi essere sfruttata tramite IORING (metodo di sfruttamento: https://windows-internals.com/one-i-o-ring-to-rule-them-all-a-full-read-write-exploit-primitive-on-windows-11/).
Ambiente di riproduzione: compilazione del codice sorgente con Visual Studio 2022 + Windows 11 202209 (eseguito su Hyper-V). Opzioni di compilazione: x64 Release. Poiché su HyperV manca vcruntime140.dll, si utilizza il collegamento statico.
Catena di funzioni in AFD.sys: AfdFastIOdeviceControl -> AfdNotifySock -> AfdNotifyRemoveIOCompletion. Questa assegna a un campo di una struct sconosciuta un indirizzo determinato dalla modalità utente, creando così una primitiva di kernel arbitrary Write-Where, che viene poi sfruttata da IORing.
Implementazione dell'exploit: la funzione ArbitraryKernelWrite0x1 realizza la scrittura arbitraria. La parte principale di tale funzione nell'exploit riutilizza una ruota del maestro x86matthew per bypassare Winsock e interagire direttamente con AFD.sys (la ruota originale serviva per creare socket TCP direttamente) (https://www.x86matthew.com/view_post?id=ntsockets).
La struct AFD_NOTIFYSOCK_DATA (cioè la struct sconosciuta menzionata sopra) implementa la scrittura a indirizzi arbitrari; le sue varie componenti servono principalmente a superare i vari controlli nella catena di chiamate di funzione.
Il primo parametro, l'handle, viene creato tramite la funzione NT non documentata NtCreateIoCompletion (https://securityintelligence.com/x-force/patch-tuesday-exploit-wednesday-pwning-windows-ancillary-function-driver-winsock/).
Un aggiornamento sulle sensazioni del debugging: codice apparentemente simile può comunque bloccarsi in punti imprevisti durante il debug.
Ad esempio, inizialmente chiamando _NtCreateFile con il primo parametro passato come hSocket, nella funzione originale __imp_ObReferenceObjectByHandle restituiva sempre un numero negativo. Dopo aver esaminato, ho definito un altro handle da passare come parametro a _NtCreateFile e _NtDeviceIoControlFile (queste due funzioni sembrano interagire principalmente con afd.sys, come descritto nell'articolo di x86matthew).
Inoltre, inizialmente non chiamavo NtSetIOCompletion, quindi il controllo IORemoveIOCompletion falliva... così ho fatto riferimento anche all'approccio di https://securityintelligence.com/x-force/patch-tuesday-exploit-wednesday-pwning-windows-ancillary-function-driver-winsock/..
Poi, nel gruppo shadow, ho chiesto aiuto perché la tabella dei simboli non veniva caricata, e ho scoperto che la causa era che il computer su cui girava Windbg non aveva il proxy attivo, quindi non riusciva a connettersi alla tabella dei simboli online.
Infine, per usare Windbg per eseguire il debug di un programma su Hyper-V, non è necessario complicarsi come descritto in Microsoft Learn; basta inserire nel prompt dei comandi di Hyper-V: bcdedit /debug on; bcdedit /dbgsettings net hostip:(indirizzo IPv4 del default switch Ethernet sull'host) port:50001 key:1.2.3.4.
Nello zip è presente il progetto Visual Studio completo per la riproduzione.
Infine, un ringraziamento speciale alla sorella Tingting e al fratello Mimi che hanno aiutato con il troubleshooting di Windbg.