
Nachbau des Exploits für CVE-2023-21768.
Ursache: Beim Vergleich von AFD.sys aus den Versionen 202209 und 202307 wurde festgestellt, dass in der Funktion AfdNotifyRemoveIOCompletion sowohl in der Windows-Version 202209 als auch in 202307 ein Schritt mit ProbeForWrite vorhanden ist, der einen Speicherbereich im Benutzermodus prüft. Die geprüfte Pufferadresse unterscheidet sich jedoch um 0x8 Bytes. Vor dem Patch dieser Schwachstelle fehlte diese Prüfung. Es wird vermutet, dass die Prüfadresse des Puffers in der Version 202209 möglicherweise falsch und damit unwirksam war. Der geprüfte Puffer steht im Zusammenhang mit einer Zuweisung in einem Zwischenschritt: **(_DWORD **)(a3 + 24) = v20;. Der eigentlich zu prüfende Puffer ist a3+24, und der Wert von v20 hängt mit v8 = IoRemoveIoCompletion(v25, Pool2, v4, (unsigned int)v6, &v20, a1, v13, 0) zusammen. Dabei scheinen mindestens Pool2, v4, v13 von der vom Benutzermodus übergebenen unbekannten Struktur bestimmt zu werden. Daher wird vermutet, dass der Wert von v20 ebenfalls mit der vom Benutzermodus übergebenen Struktur zusammenhängt ~ (laut Writeup ist er der Rückgabewert des Aufrufs von KeRemoveQueueEx durch IoRemoveIoCompletion).
Wenn a3+24 eine Adresse im Kernel-Modus speichert, könnte dies zu einer primitiven Kernel-Arbitrary-Write führen, die dann über IORING ausgenutzt werden kann ~ (Ausnutzungsmethode: https://windows-internals.com/one-i-o-ring-to-rule-them-all-a-full-read-write-exploit-primitive-on-windows-11/)
Reproduktionsumgebung: Visual Studio 2022 kompiliert Quellcode + Windows 11 202209 (ausgeführt auf Hyper-V). Compileroption: x64 Release. Da in Hyper-V die Datei vcruntime140.dll fehlt, wurde statisch gelinkt.
Funktionskette in AFD.sys: AfdFastIOdeviceControl -> AfdNotifySock -> AfdNotifyRemoveIOCompletion. Dabei wird ein Feld einer unbekannten Struktur auf eine vom Benutzermodus bestimmte Adresse gesetzt, wodurch eine Arbitrary-Kernel-Write-Where-Primitive entsteht, die dann von IORing ausgenutzt werden kann.
EXP-Implementierung: Der arbitrary Write wird über die Funktion ArbitraryKernelWrite0x1 realisiert. Der Hauptteil dieser Funktion im EXP verwendet ein Rad von x86matthew, um Winsock zu umgehen und direkt mit AFD.sys zu interagieren (das Rad diente ursprünglich dazu, direkt einen TCP-Socket zu erstellen) (https://www.x86matthew.com/view_post?id=ntsockets).
Die im obigen Text beschriebene Struktur, die das Schreiben auf eine beliebige Adresse ermöglicht, ist struct*AFD_NOTIFYSOCK_DATA*, also die oben erwähnte unbekannte Struktur. Ihre Zusammensetzung dient hauptsächlich dazu, verschiedene Prüfungen in der Funktionskette zu umgehen.
Das erste Argument, das Handle, wird über die undokumentierte NT-Funktion NtCreateIoCompletion erstellt (https://securityintelligence.com/x-force/patch-tuesday-exploit-wednesday-pwning-windows-ancillary-function-driver-winsock/).
Update zu Debugging-Erfahrungen: Code, der auf den ersten Blick sehr ähnlich aussieht, kann beim Debuggen immer noch an seltsamen Stellen hängen bleiben.
Zum Beispiel wurde beim ersten Aufruf von _NtCreateFile das erste Argument auf hSocket gesetzt. Dann gab __imp_ObReferenceObjectByHandle in der ursprünglichen Funktion immer eine negative Zahl zurück. Nach einer Analyse wurde ein weiteres Handle definiert, das als Parameter für _NtCreateFile und _NtDeviceIoControlFile dient (diese beiden Funktionen scheinen hauptsächlich zur Interaktion mit afd.sys zu dienen – siehe den Artikel von x86matthew).
Außerdem wurde anfangs NtSetIOCompletion nicht aufgerufen, sodass die Prüfung von IORemoveIOCompletion fehlschlug. Daher wurde auch auf das Vorgehen in https://securityintelligence.com/x-force/patch-tuesday-exploit-wednesday-pwning-windows-ancillary-function-driver-winsock/ Bezug genommen.
Und die Anfrage in der Shadow-Gruppe bezüglich des nicht ladbaren Symboltables ergab, dass der Grund war, dass der Rechner, auf dem Windbg lief, keinen Proxy hatte, um sich mit dem Online-Symboltable zu verbinden.
Schließlich wurde Windbg zum Debuggen von Programmen auf Hyper-V verwendet – das ist nicht so kompliziert wie in der Microsoft-Learn-Beschreibung. Etwa bcdedit /debug on; bcdedit /dbgsettings net hostip:(IPv4-Adresse des Ethernet-Standard-Switches auf dem Host) port:50001 key:1.2.3.4 in die Hyper-V-Kommandozeile eingeben.
Im ZIP-Archiv befindet sich das vollständige Visual-Studio-Projekt zur Reproduktion.
Abschließend ein besonderer Dank an Tingting und Mijia (Mimi), die bei der Fehlersuche mit Windbg geholfen haben.