
Proof-of-Concept-Exploit für CVE-2022-37969, eine lokale Privilegieneskalation im Windows-Treiber für das Common Log File System. Demonstriert Heap-Spray, Token-Diebstahl und beliebiges Schreiben in den Kernel, um SYSTEM-Berechtigungen zu erlangen.
Autoren: Ricardo Narvaja & Daniel Kazimirow (Solid)
Nur zu Demonstrationszwecken. Der vollständige Exploit funktioniert auf anfälligen Windows 11 21H2-Systemen.
Funktionaler PoC basierend auf zuvor veröffentlichten Informationen von Zscaler
Siehe die Aufarbeitung Understanding the CVE-2022-37969 Windows Common Log File System Driver Local Privilege Escalation.
Exploit-Walkthrough:
Das hier verwendete Szenario war Windows 11 21H2 (OS Build 22000.918) clfs.sys v10.0.22000.918
Der erste Schritt besteht darin, eine Datei namens MyLog.blf im öffentlichen Ordner (%public%) zu erstellen, indem die Funktion CreateLogFile() verwendet wird:



Dann werden mehrere Protokolldateien mit zufälligen Namen in einer Schleife erstellt.
Und innerhalb der Schleife wird unsere Funktion getBigPoolInfo() aufgerufen:

Es wird NtQuerySystemInformation() mit 0x42 (66 dezimal) als erstem Argument aufgerufen; dies gibt in v5 die Informationen über die im bigpool vorgenommenen Zuordnungen zurück, deren Struktur vom Typ SYSTEM_BIGPOOL_INFORMATION ist.

Wir müssen diese Funktion zweimal aufrufen. Der erste Aufruf wird einen Fehler zurückgeben, aber uns die korrekte Größe des Puffers für den zweiten Aufruf liefern, um die gewünschten Informationen zu erhalten.

v5 empfängt die Informationen der SYSTEM_BIG_POOL_INFORMATION-Struktur.

Die Anzahl der Zuweisungen im bigpool wird im ersten Feld namens Count gespeichert; im zweiten Feld befindet sich ein Array von SYSTEM_BIGPOOL_ENTRY-Strukturen.

Dann durchsuchen wir alle Strukturen nach dem Tag „Clfs“ und der Größe 0x7a00.

Es speichert in einem Array namens kernelAddrArray die VirtualAddress, das erste Feld jeder Struktur, die das CLFS-Tag und die Größe 0x7a00 hat. Von nun an werden die Pools, die beide Bedingungen erfüllen, als „right pools“ bezeichnet.

Zusätzlich zum Speichern jedes right pool im Array speichert es den letzten gefundenen right pool im Inhalt der Variablen a2, die als Argument der Funktion verwendet wird.

Auf diese Weise zeigt a2 immer auf den zuletzt erstellten right pool mit CLFS-Tag und Größe 0x7a00.
Die Variable v26 speichert immer den zuvor gefundenen right pool, da sie vor dem Aufruf von getBigPoolinfo() gleich v24 ist (v26=v24), aber v24 wird beim Verlassen dieses Aufrufs mit dem letzten gefundenen right pool aktualisiert, und v26 bleibt mit dem zuvor gefundenen right pool.

Dann subtrahiert es beide Adressen, und falls das Ergebnis negativ ist, werden die Operanden umgekehrt, sodass es immer positiv ist.

Auf diese Weise speichert v32 die Differenz zwischen den VirtualAddresses der letzten beiden gefundenen right pools.
Dann macht es etwas Ähnliches; in diesem Fall ist v23 anfänglich null, also setzt es v23 = v32 beim ersten Mal.

Beim nächsten Durchlauf der Schleife hat v23 immer noch denselben Wert und ist nicht null, also bricht es ab und geht hierhin.

V32 hat die letzte Differenz und v23 die vorherige; wenn sie gleich sind, wird ausgegeben und um eins erhöht, aber der Zähler wird auf null zurückgesetzt.
Die Idee ist, 6 aufeinanderfolgende Vergleiche von CLFS-Tags und Größe 0x7a00 zu finden, deren Differenzen gleich sind, und diese Differenz wird 0x11000 sein. Wir werden sehen, dass bei der Ausführung, wenn 6 (da bei null begonnen wird) aufeinanderfolgende mit gleichen Abständen gefunden werden, dieser Wert der Differenz zwischen ihnen ausgegeben wird.


Dort sehen wir, dass er 6 aufeinanderfolgende gefunden hat und die Schleife zum Erstellen der Protokolldateien verlassen hat.
Im Ordner „public“ können wir die erstellten Dateien sehen