Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2023-28252 — Technische Analyse und Proof-of-Concept-Exploit für CVE-2023-28252, eine Windows Common Log File System (CLFS)-Treiber-Privilegienausweitungsschwachstelle, die bei Nokoyawa-Ransomware-Angriffen verwendet wurde. | Kitploit
Tools/GitHubGitHub/fortra/cve-2023-28252
Privilege EscalationSpeicherforensikSchwachstellenanalyseExploitationReverse EngineeringDebuggerBinary-Exploitation
GitHubfortra/cve-2023-28252

CVE-2023-28252

Technische Analyse und Proof-of-Concept-Exploit für CVE-2023-28252, eine Windows Common Log File System (CLFS)-Treiber-Privilegienausweitungsschwachstelle, die bei Nokoyawa-Ransomware-Angriffen verwendet wurde.

Repository anzeigen
18444vor 3 JahrenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Seit Februar 2022 wurde eine neue Ransomware gemeldet, die offenbar eine Windows-0-Day-Schwachstelle ausnutzt, so die von Trend Micro durchgeführte Forschung.
Weitere Informationen zu dieser Ransomware finden Sie unter diesem Link.
Laut der Analyse von Kaspersky hat die Nokoyawa-Ransomware-Gruppe seit Juni 2022 andere Exploits eingesetzt, die den Common Log File System (CLFS)-Treiber angreifen, mit ähnlichen, aber unterschiedlichen Merkmalen, die alle mit einem einzigen Exploit-Entwickler verbunden sind.
Im April 2023, als Microsoft den Patch veröffentlichte, wurde die CVE-2023-28252 zugewiesen.
Zuvor, im Jahr 2022, wurde von uns ein ähnlicher Fehler in derselben Komponente untersucht und in diesem Blogbeitrag dokumentiert.

Common Log File System (CLFS) Dateiformat:

Um die Analyse durchführen zu können, ist es notwendig, das .blf-Dateiformat zu kennen, das von dem anfälligen Common Log File System-Treiber namens CLFS.sys verwaltet wird und sich im Treiberordner innerhalb von system32 befindet.

Weitere Informationen zu diesem Dateityp finden Sie unter den folgenden Links:

https://www.zscaler.com/blogs/security-research/technical-analysis-windows-clfs-zero-day-vulnerability-cve-2022-37969-part

https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-the-common-log-file-system

https://github.com/ionescu007/clfs-docs/blob/main/README.md

https://www.coresecurity.com/core-labs/articles/understanding-cve-2022-37969-windows-clfs-lpe

Die Schwachstelle:

Diese Analyse wurde für Windows 11 21H2, clfs.sys Version 10.0.22000.1574 durchgeführt, obwohl sie auch auf Windows 10 21H2, Windows 10 22H2, Windows 11 22H2 und Windows Server 2022 funktioniert.

In früheren Windows-Versionen müssen einige Werte angepasst werden, da sonst ein BSOD auftreten würde.

Microsoft Patch Tuesday April 2023.

Ein Screenshot eines Computers Beschreibung automatisch generiert mit mittlerer SicherheitSie können die Treiberversion wie gezeigt überprüfen

Als die Schwachstelle im April 2023 veröffentlicht wurde, begann ich zusammen mit Esteban Kazimirow mit dem Reversing des CLFS.sys-Treibers. In diesem Fall war es jedoch sehr schwierig, allein durch die Analyse des Patches abzuleiten, wo der Fehler lag und wie er ausgelöst werden kann, da die Ausnutzung sehr komplex ist.

Später erschien ein Blogbeitrag, dessen Autor anhand einer Malware-Stichprobe einige Teile des von HexRays dekompilierten Codes sowie einige Informationen zeigte, die uns die Richtung vorgaben, in die die Ausnutzung gehen musste.

Offensichtlich waren die bereitgestellten Informationen nicht vollständig, aber ohne diese Hilfe wäre es unwahrscheinlich gewesen, dass wir den PoC und später einen funktionierenden Exploit hätten erstellen können.

Um das Verständnis zu erleichtern, werden wir zuerst erklären, wie der PoC aufgebaut wird, und dann die Schwachstellenanalyse durchführen.

Dieser Blogbeitrag enthält zwei Abschnitte:

Aufbau des PoC:

1- Beschaffen der benötigten Kernel-Adressen für die Ausnutzung

2- Vorbereiten des Pfads zum Erstellen der .blf-Dateien:

3- Erstellen der „trigger blf“-Datei mit der Funktion CreateLogFile()

4- Erstellen der „trigger blf“-Datei

5- Beschaffen der Kernel-Adresse des BASE BLOCK von trigger blf

6- Aufrufen von AddLogContainer mit dem Handle von trigger blf

7- Vorbereiten der spray blf-Dateien

8- Vorbereiten des Speichers für das Spray

9- Auslösen des Fehlers

Debugging:

1- Überprüfen des Memory Sprays

2- Betrachten des RecordOffset[12] von trigger blf

3- Betrachten des iFlushBlock-Werts in der spray blf-Datei

4- Warum wird von BLOCK 1 SHADOW statt von BLOCK 0 CONTROL gelesen?

5- Warum ist die Prüfsumme in den spray blf-Dateien gleich null?

6- Abschluss der Ausnutzung.

7- Der eigentliche Patch

Aufbau des PoC:

1-Beschaffen der benötigten Kernel-Adressen für die Ausnutzung

Ich werde eine Funktion namens InitEnvironment erstellen, um einige notwendige Kernel-Adressen zu erhalten.

Holen der EPROCESS-Adresse meines Prozesses und Speichern in der Variablen g_EProcessAddress, dann die EPROCESS-Adresse des SYSTEM-Prozesses und Speichern in system_EPROCESS, dann die EHTREAD-Adresse des Hauptthreads meines Prozesses und Speichern in g_EThreadAddress und schließlich die Adresse des PREVIOUS MODE, die in dieser Version des PoC nicht verwendet wird.

Ein Screenshot eines Computercodes Beschreibung automatisch generiert mit geringer Sicherheit

Diese Methode ist bekannt: Die GetObjectKernelAddress-Funktion ruft NtQuerySystemInformation zweimal auf, mit dem ersten Argument SystemExtendedHandleInformation. Der erste Aufruf erfolgt mit einer falschen Größe und gibt einen Fehler zurück, aber auch die korrekte Größe, die im zweiten Aufruf verwendet wird, um die Informationen aller Handles zu erhalten. Dann wird in einer Schleife die Information jedes Handles durchlaufen und im Feld Object des richtigen handleinfo die gesuchte Adresse im Kernel gefunden.

Ein Bild mit Text, Screenshot, Schriftart, Zeile Beschreibung automatisch generiert

Ich benötige auch die Kernel-Adressen der folgenden von CLFS.sys exportierten Funktionen:

• ClfsEarlierLsn

• ClfsMgmtDeregisterManagedClient

Und die von NTOSKRNL.exe exportierten Funktionen

• RtlClearBit/PoFxProcessorNotification

• SeSetAccessStateGenericMapping

Um diese Adressen zu erhalten, wird eine ähnliche Methode verwendet, wie um die Kernel-Basis beider Module zu erhalten, indem NtQuerySystemInformation zweimal aufgerufen wird, aber in diesem Fall ist das erste Argument SYSTEM_INFORMATION_CLASS (im PoC verwenden wir die Funktion FindKernelModulesBase zu diesem Zweck).

Ein Bild mit Text, Schriftart, Screenshot, Zeile Beschreibung automatisch generiertDann wird CLFS.sys und NTOSKRNL.exe als normale Module im Benutzermodus durch Aufruf von LoadLibrary geladen, die Adressen im Benutzermodus mit GetProcAddress ermittelt, dann die Imagebase von jedem abgezogen, um den Offset der Funktion zu erhalten, und schließlich jeder Offset zu den entsprechenden Kernel-Basen addiert, um die Kernel-Adressen aller benötigten Funktionen zu erhalten.

Ein Bild mit Text, Schriftart, Zeile, Screenshot Beschreibung automatisch generiert

2-Vorbereiten des Pfads zum Erstellen der .blf-Dateien:

Ich erstelle eine Funktion namens createInitialTriggerBlfFile, die eine .blf-Datei generiert und schreibt.

Der Pfad, der als Argument in CreateLogFile verwendet wird, unterscheidet sich von einem normalen Pfad. Zum Öffnen der Datei 1280.blf im Ordner C:\Users\Public müssen wir z.B. den Pfad LOG:C:\Users\Public\1280 angeben. Dieser wird in der Variablen stored_name_CreateLog gespeichert.

Ich mache dies mit wsprintfW(), da stored_env den Pfad C:\Users\Public speichert, der zuvor aus den Umgebungsvariablen abgerufen wurde. Dieser Zeichenfolge füge ich die Zeichenfolge LOG: und einen zufälligen Namen am Ende voran, ohne die Erweiterung .blf.

Ein Screenshot eines Computers Beschreibung automatisch generiert mit mittlerer Sicherheit

Dies wird der Pfad zu meiner anfänglichen Datei sein, die ich "trigger blf" nenne. Natürlich muss ich auch den normalen Pfad zu derselben Datei ohne das vorangestellte LOG: und mit der BLF-Erweiterung speichern, um sie mit CreateFile(), WriteFIle() wie jede andere Datei zu öffnen und zu ändern. Dieser Pfad wird z.B. C:\Users\Public\1280.blf sein und in der Variablen stored_name_fopen gespeichert.

Ein Bild mit Text, Schriftart, Zeile, Screenshot Beschreibung automatisch generiert

Natürlich entsprechen beide Pfade derselben Datei, und ich muss je nach Situation den einen oder anderen verwenden.

3-Erstellen der „trigger blf“-Datei mit der Funktion CreateLogFile().

Die CreateLogFile-Funktion erfüllt eine Funktion, die CreateFile() recht ähnlich ist (sie erstellt neue Dateien oder öffnet vorhandene Dateien und gibt deren Handle zurück), sogar einige Argumente sind ähnlich, aber CreateLogFile() arbeitet nur mit blf-Dateien.

Außerdem wird beim Öffnen einer vorhandenen Datei überprüft, ob das Format in Ordnung ist, selbst wenn jeder Block eine Prüfsumme hat und wenn diese nicht korrekt ist, wird ein Fehler zurückgegeben.

Ich werde zwei Arten von BLF-Dateien erstellen:

  1. Die Trigger blf

  2. Die Spray blf

Beides sind blf-Dateien, aber auf unterschiedliche Weise modifiziert.

Eine Nahaufnahme eines Computercodes Beschreibung automatisch generiert mit geringer SicherheitAuf diese Weise erstellt der PoC zuerst die „trigger blf“-Datei mit CreateLogFile mit dem zuvor festgelegten Pfad, z.B. LOG:C:\Users\Public\1280, der in der Variablen stored_name_CreateLog gespeichert ist.

Das fünfte Argument fCreateDisposition kann wie bei CreateFileA() die folgenden Werte annehmen:

Ein Bild mit Text, Schriftart, Zeile, Beleg Beschreibung automatisch generiert

In diesem Fall werde ich das Argument OPEN_ALWAYS verwenden, sodass die Datei erstellt wird, wenn sie nicht existiert, und geöffnet wird, wenn sie existiert. Da die Datei noch nicht existiert, wird sie mit einem zufälligen Namen erstellt.

logFile = CreateLogFile(stored_name_CreateLog, GENERIC_READ | GENERIC_WRITE, 1, 0, 4, 0);

CreateLogFile() wird unsere „trigger blf“-Datei mit ihren 6 Blöcken und den entsprechenden Prüfsummen erstellen und das Handle zurückgeben, das in der Variablen logFile gespeichert wird.

Ein Bild mit Text, Screenshot, Schriftart, Nummer Beschreibung automatisch generiert

Jeder Block hat ab dem in der linken Spalte angezeigten Offset einen Header, dessen Größe 0x70 Bytes beträgt.

So erstreckt sich z.B. der Header des CONTROL BLOCK von Offset 0x0 bis 0x70.

Ein Screenshot eines Computers Beschreibung automatisch generiert mit geringer Sicherheit

Alle Header aller Blöcke haben dieselbe Struktur namens _CLFS_LOG_BLOCK_HEADER.

Dies ist die Header-Struktur:

Ein Screenshot eines Computers Beschreibung automatisch generiert mit mittlerer Sicherheit

Bei Offset 0xC des Headers befindet sich die Prüfsumme. Da der CONTROL BLOCK bei Offset 0 beginnt, befindet sich die Prüfsumme bei Offset 0xC der Datei, und jeder Block hat seine Prüfsumme bei 0xC vom Anfang seines Blocks an.

Ein Screenshot eines Computers Beschreibung automatisch generiert mit geringer Sicherheit

4-Erstellen der „trigger blf“-Datei:

Um die trigger blf-Datei zu ändern, muss ich sie als normale Datei entweder mit CreateFileA oder mit fopen öffnen und sie dann mit WriteFile bzw. fwrite ändern. Dies führe ich am Anfang der Funktion fun_prepare des PoC aus.

Denken Sie daran, dass der normale Pfad in der Variablen stored_name_fopen gespeichert ist, also verwende ich ihn, um die Datei mit wfopen_s (einer Variante von fopen, die Unicode-Zeichenfolgen unterstützt) zu öffnen.

Die Datei wird in der Funktion craftTriggerBlfFile geändert, die von fun_prepare aufgerufen wird.

Ein Bild mit Text, Zeile, Schriftart, Screenshot Beschreibung automatisch generiert

Dann rufe ich fseek auf, um auf den zu ändernden Offset zu zeigen, und dann wird die Datei mit fwrite geändert.

Ein Screenshot eines Computers Beschreibung automatisch generiert mit mittlerer SicherheitDie an der „trigger blf“-Datei vorzunehmenden Änderungen sind wie folgt:

Nachdem diese Änderungen vorgenommen wurden, wird FixCRCFile aufgerufen, um die neue Prüfsumme zu berechnen und die Prüfsummen der ersten 4 Blöcke zu korrigieren. Die nächsten beiden Blöcke haben keine Änderungen, daher ist es nicht notwendig, ihre Prüfsummen neu zu berechnen.

Ein Bild mit Text, Schriftart, Screenshot, Nummer Beschreibung automatisch generiert

5-Beschaffen der Kernel-Adresse des BASE BLOCK von trigger blf:

Der CLFS.sys-Treiber liest die sechs Blöcke der Datei und führt zur Speicherung ihres Inhalts eine Zuweisung im Kernel-Pool durch.

Ein Bild mit Text, Screenshot, Schriftart, Nummer Beschreibung automatisch generiert

Es gibt eine sehr wichtige Struktur der Größe 0x90, die im vorherigen Blogbeitrag zu CVE-2022-37969 durch Reversing einige Felder gefunden und als pool_0x90 bezeichnet wurde. Nach viel weiterem Reversing weiß ich jetzt, dass ihr richtiger Name m_rgBlocks ist, und während der Controller Speicher zuweist, um den Inhalt jedes Blocks aus der Datei zu kopieren, speichert er dort die Größe jedes Blocks, den Start-Offset und die Kernel-Adresse, an der er gespeichert wurde.

Ein Bild mit Text, Screenshot, Schriftart Beschreibung automatisch generiert

Es hat sechs CLFS_METADATA_BLOCK, die jeweils einem Block nach seiner Nummer entsprechen.

Jede Struktur CLFS_METADATA_BLOCK ist 0x18 Bytes lang. (0x18*6=0x90)

Ein Bild mit Text, Schriftart, Zeile, Nummer Beschreibung automatisch generiertBei Offset 0 befindet sich eine Union, aber zumindest in diesem Exploit wird nur das Feld pbImage verwendet, also vereinfacht wäre es:

Die Zuweisung dieser Struktur kann von zwei verschiedenen Stellen des CLFS.sys-Treibers aus erfolgen, je nachdem, ob eine neue Datei erstellt oder eine vorhandene geöffnet wird. Wenn eine neue Datei erstellt wird, weist der Treiber die 0x90 Bytes von CClfsBaseFilePersisted::CreateImage+28A zu, während bei einer vorhandenen Datei von CClfsBaseFilePersisted::ReadImage+6E zugewiesen wird.

Danach werde ich die Startadresse von Block 2 holen, die der trigger blf-Datei entspricht, dem sogenannten BASE BLOCK, der bei Offset 0x800 beginnt und eine Länge von 0x7a00 hat.

Ein Bild mit Text, Screenshot, Schriftart, Nummer Beschreibung automatisch generiert

Innerhalb der fun_prepare-Funktion wird diese Adresse im Kernel mit diesem Code gefunden.

Ein Screenshot eines Computercodes Beschreibung automatisch generiert mit geringer Sicherheit

Zuerst findet die getBigPoolInfo-Funktion alle Zuweisungen im Pool, die das "Clfs"-Tag und eine Größe von 0x7a00 haben, und speichert sie in einem Array.

Danach wird die zuvor geänderte trigger blf-Datei erneut mit CreateLogFile und dem Argument OPEN_EXISTING geöffnet, sodass eine vorhandene Datei geöffnet wird. Dies führt zur Zuweisung ihres BASE BLOCK.

Wenn getBigPoolInfo erneut aufgerufen wird, gibt es einen neuen "Clfs"-Pool der Größe 0x7a00, und seine Adresse wird durch zweimaligen Aufruf von NtQuerySystemInformation abgerufen.

Die Adresse des BASE BLOCK der trigger blf-Datei wird in der Variablen CLFS_kernelAddrArray gespeichert.

Beachten Sie, dass die Funktion CreateLogFile() fehlschlägt, wenn die geänderte trigger blf-Datei nicht die korrekte Prüfsumme hat.

6-Aufrufen von AddLogContainer mit dem Handle von trigger blf:

Der letzte Teil der fun_prepare-Funktion ruft die AddLogContainer-API mit dem Handle der trigger blf-Datei auf.

Eine Nahaufnahme eines Computercodes Beschreibung automatisch generiert mit geringer Sicherheit

7-Vorbereiten der spray blf-Dateien:

In der letzten Funktion des PoC namens to_trigger wird eine zweite Art von blf-Datei erstellt,

Ich nenne sie spray blf.

Diese Art von Datei wird verwendet, um einen Speicherbereich zu füllen (Spray), es werden 10 gleiche dieser Art benötigt, aber zunächst wird nur eine erstellt. Ein Bild mit Text, Schriftart, Zeile, Screenshot Beschreibung automatisch generiert

Es werden drei Arrays erstellt, um die zufälligen Namen dieser Dateien zu speichern:

stored_log_arrays: speichert zehn neue Zufallsnamen von .blf-Dateien, die mit CreateLogFile verwendet werden.

stored_container_arrays: speichert Zufallsnamen, um zehn neue Container-Dateien zu erstellen.

stored_fopen_arrays: speichert die Log-Dateinamen des ersten Arrays (Variable stored_log_arrays), jedoch mit ihrem normalen Pfad (ohne die Zeichenfolge „LOG:“) und mit der Erweiterung .blf.

Ein Screenshot eines Computercodes Beschreibung automatisch generiert mit mittlerer Sicherheit

In jeder Iteration wird die blf-Datei mit CopyFileW kopiert, und die im Array gespeicherten Namen werden zugewiesen.

Die Funktion fun_trigger ruft craftSprayBlfFile auf, wo Änderungen an jeder Datei vorgenommen werden, und FixCRCFile korrigiert die CRCs.

Ein Screenshot eines Computerprogramms Beschreibung automatisch generiert mit mittlerer Sicherheit

Zusammenfassend habe ich 10 ähnliche Dateien (spray blf) mit Zufallsnamen erstellt, mit den folgenden Änderungen:

Ein Screenshot eines Computers Beschreibung automatisch generiert mit mittlerer Sicherheit

Die letzte Änderung besteht darin, den gesamten Block 0 (CONTROL BLOCK) zu Block 1 (CONTROL BLOCK SHADOW) zu kopieren.

Ein Screenshot eines Computers Beschreibung automatisch generiert mit geringer Sicherheit

Die Wirkung dieser Änderungen, zusammen mit denen an der trigger blf-Datei, wird später im Debugging-Kapitel erläutert.

Einige dieser Änderungen sind diejenigen, die die Schwachstelle verursachen, während andere nur notwendig sind, um die Treiberüberprüfungen zu umgehen.

An diesem Punkt sind die Dateien bereits erstellt und modifiziert, bereit, um das Spray durchzuführen. Wenn sie dann mit CreateLogFile geöffnet werden, werden sie in dem Speicherbereich platziert, den wir wünschen, wie später gezeigt wird.

8-Vorbereiten des Speichers für das Spray

In der to_trigger-Funktion wird ein Array mit 12 Elementen erstellt, das die Adresse des BASE BLOCK der trigger blf-Datei plus 0x30 enthält.

Dann wird in der fun_pipeSpray-Funktion der Speicher mit einem Spray von Pipes gefüllt. Darin gibt es eine Schleife, die CreatePipe aufruft und die Anzahl der Pipes erstellt, die als erstes Argument übergeben werden. Das zweite Argument ist ein Array, das die Handles aller erstellten Pipes speichert.

Innerhalb einer Schleife wird CreatePipe aufgerufen, um Lese-Schreib-Pipes zu erstellen.

Auf diese Weise werden zunächst 0x5000 Pipes erstellt und dann erneut aufgerufen, um weitere 0x4000 Pipes zu erstellen.

Dann wird WriteFile verwendet, um in die ersten 5000 Pipes das kürzlich erstellte Array mit den Adressen von BASE BLOCK + 0x30 der trigger blf-Datei zu schreiben.

Ein Screenshot eines Computercodes Beschreibung automatisch generiert mit geringer Sicherheit

Jetzt gibt es bereits einen kompakten Block im Speicher. Es werden 0x667 Pipes von Nummer 0x2000 bis 0x2667 freigegeben, da die Pipes im Speicher nicht in derselben Reihenfolge erstellt wurden. Was passieren wird, ist, dass in diesem Speicherblock freie Stellen entstehen.

Ein Bild mit Text, Screenshot, Schriftart, Software Beschreibung automatisch generiertBeachten Sie, dass die Zuweisungen der Pipes eine Benutzergröße von 0x90 Bytes haben. Wenn sie also freigegeben werden, haben wir

Es gibt die Speicherbereiche der Größe 0x90 zwischen dem mit Pipes gefüllten Speicher frei.
Dann wird in einer Schleife CreateLogFile mit den 10 spray blf-Dateien aufgerufen.
Wenn CreateLogFile zum Öffnen vorhandener Dateien aufgerufen wird, wird die Zuweisung von 0x90 Bytes für die m_rgBlocks für jede spray blf-Datei durchgeführt, sodass diese Zuweisungen die Lücken füllen, die beim Freigeben der Pipes entstanden sind, da sie die gleiche Größe haben.

Ein Screenshot eines Computercodes Beschreibung automatisch generiert mit mittlerer Sicherheit

Dann wird der Vorgang wiederholt: In die letzten 0x4000 Pipes wird das Array mit der Adresse von BASE BLOCK + 0x30 von trigger blf geschrieben.

9-Auslösen des Fehlers

All diese Manipulationen erzeugen einen kontrollierten Speicherbereich. Ich werde Ihnen zeigen, wie er aussieht, wenn er debuggt wird, aber die Idee ist, dass die m_rgBlocks jeder spray blf-Datei die 0x90-Byte-Lücken besetzen, die freigegeben wurden.

Dann wird im letzten Teil der Fehler innerhalb einer while(1)-Schleife durch einen Aufruf von AddLogContainer auf die spray blf-Dateien ausgelöst.A picture containing text, font, line, number Description
automatically generated

Innerhalb dieser While-Schleife wird der Bug ausgelöst:

A screenshot of a computer program Description automatically generated
with low confidence

Diese While-Schleife wird beendet, sobald sie das System-Token findet, unter Verwendung der NtFsControlFile-Funktion, die die Attribute der Pipes liest.

A screenshot of a computer code Description automatically generated
with low confidence

Dann überschreibt CreateLogFile erneut das Token unseres Prozesses mit dem gerade gefundenen System-Token, und auf diese Weise erreichen wir die Privilegienausweitung.

A picture containing text, font, line, screenshot Description
automatically generated

Anschließend werden einige Werte wiederhergestellt, die Handles der Pipes und der blf-Dateien geschlossen, und ein Notepad als System ausgeführt, um zu überprüfen, ob wir die Erhöhung korrekt durchgeführt haben.

A screenshot of a computer Description automatically generated with
medium confidence

Beachten Sie die im PUBLIC-Ordner erstellten blf-Dateien. Denken Sie daran, dass Sie für einen weiteren Versuch zuerst die erstellten Dateien löschen müssen. Einige werden gesperrt sein und können nicht gelöscht werden, aber der PoC funktioniert trotzdem.

A screenshot of a computer Description automatically generated with
medium confidence

Debugging:

1- Überprüfen des Memory-Sprays

Bevor ich mit der Wirkung der Änderungen an trigger blf und spray blf-Dateien zur Durchführung der Ausnutzung beginne, muss ich überprüfen, ob sich m_rgBlocks der spray blf-Dateien in Löchern befinden, die in der Speicherverteilung nach dem Pipe-Spray und der anschließenden Freigabe einer festgelegten Anzahl von Pipes entstehen.

Wenn dieser Vorgang beendet ist, sollte sich eine Pipe unter den 0x90 Bytes von m_rgBlocks befinden, sodass bei Verwendung von m_rgBlocks ein OUT OF BOUNDS auftritt und von der darunter liegenden Pipe gelesen wird.

Der PoC bietet eine ideale Stelle zum Setzen eines Breakpoints:

A screen shot of a computer code Description automatically generated
with low confidence

An diesem Punkt ist das Öffnen der spray blf-Dateien abgeschlossen, die Funktion AddLogContainer wurde noch nicht aufgerufen.

Zum Debuggen im Benutzermodus verwende ich x64dbg und für den Kernel-Modus IDA mit dem Windbg-Plugin.

A screen shot of a computer Description automatically generated with
low confidence

An diesem Punkt sollte der Speicher bereits vorbereitet sein, und ich kann die Verteilung sehen.

Ich pausiere IDA, um eine interessante Stelle zum Setzen eines Breakpoints zu finden.

Ich setze einen Breakpoint bei CClfsBaseFilePersisted::AddContainer, der von AddLogContainer aufgerufen wird, und am Anfang zeigt das RCX-Register auf die CClfsBaseFilePersisted-Struktur und an Offset 0x30 befindet sich ein Zeiger auf m_rgBlocks.

A screen shot of a computer Description automatically generated with
medium confidence

Wenn der Breakpoint erreicht wird, überprüfe ich im Call-Stack, ob AddLogContainer von meinem PoC aus aufgerufen wird.

A screenshot of a computer Description automatically generated with
medium confidence

Das RCX-Register zeigt auf:

A screenshot of a computer Description automatically generated with
low confidence A screenshot of a computer
Description automatically generated with low
confidence

Das erste Feld ist der Zeiger auf eine vtable (CLFS! CClfsBaseFilePersisted::'vftable'), und an Offset 0x30 befindet sich der Zeiger auf m_rgBlocks.

A screenshot of a computer code Description automatically generated
with medium confidence

Die Blöcke 0, 1, 4 und 5 haben pbImage noch nicht gespeichert, während die Blöcke 2 (BASE BLOCK) und 3 (SHADOW BLOCK) dies getan haben.

Jeder Block in der m_rgBlocks-Tabelle hat sein cbOffset, das der Offset ist, an dem der Block in der Datei beginnt, cbImage ist die Blockgröße und eBlockType ist der Blocktyp.

Wenn das Spray korrekt ist, sollte sich unter m_rgBlocks eine Pipe befinden, und darin die Zeiger auf BASE BLOCK + 0x30 der trigger blf.

A screenshot of a computer code Description automatically generated
with low confidence

Der Befehl "!pool" in Windbg zeigt die Speicherverteilung:

A screenshot of a computer Description automatically generated with
medium confidence

Jeder m_rgBlocks hat ein „Clfs"-Tag und seine Größe ist 0xa0, da es sich um die 0x90 Benutzergröße plus 0x10 Header handelt. Darunter befindet sich eine Pipe mit dem „NpFr“-Tag, die die gleiche 0x90 Benutzergröße + 0x10 Header hat.

Da die Verteilung keine exakte Wissenschaft ist, wurden einige „Clfs“ kontinuierlich platziert, was unerwünscht ist, aber derjenige, mit dem ich arbeite, ist korrekt platziert, gefolgt von einer Pipe.

2-Betrachten des RecordOffset[12] von trigger blf

Eine der ersten Änderungen, die wirkt, ist die in der trigger blf-Datei bei Offset 0x858, wo der Wert 0x369 gespeichert ist.

A close-up of a sign Description automatically generated with low
confidence

Der BASE BLOCK beginnt bei Offset 0x800 in der Datei.

A picture containing text, screenshot, font, line Description
automatically generated

Innerhalb des _CLFS_LOG_BLOCK_HEADER bei Offset 0x800+0x58 (0x58 ab Beginn des BASE BLOCK-Headers).

A picture containing text, screenshot, font, display Description
automatically generated

Bei Offset 0x28 beginnt das Array RecordOffsets (DWORD).

Wenn Sie sich 0x30 Bytes vorwärts bewegen, befindet sich bei Offset 0x58 (0x828+0x30=0x858 ab Anfang) Feld 12 der RecordOffsets.

A picture containing text, font, screenshot, graphics Description
automatically generated

Ich führe den PoC aus, um CreateLogFile wie im folgenden Bild gezeigt aufzurufen:

A screenshot of a computer code Description automatically generated
with low confidence A screenshot of a computer
code Description automatically generated with low
confidence

A screenshot of a computer Description automatically
generated

Bevor ich in CreateLogFile eintrete, werde ich einen Breakpoint an einer Stelle setzen, an der der Wert 0x369 noch nicht verwendet wurde.

In einem Fall, in dem CreateLogFile eine vorhandene Datei öffnet, wird die m_rgBlocks-Struktur hier zugewiesen:

CClfsBaseFilePersisted::ReadImage+6E

Also setze ich in IDA einen Breakpoint genau hier:

A screenshot of a computer Description automatically generated with
medium confidence

Wenn der Breakpoint ausgelöst wird**:**

A picture containing text, screenshot, font, number Description
automatically generated

In m_rgBlocks befindet sich noch Garbage, da es noch nicht initialisiert ist, aber sobald pbImage von Block 2 zugewiesen wird, wird die Adresse an Offset 0x30 vom Anfang gespeichert, da das erste Feld innerhalb jedes CLFS_METADATA_BLOCK pbImage ist.

A screen shot of a computer Description automatically generated with
medium confidence

A picture containing text, screenshot, font, line Description
automatically generated

Jetzt setze ich einen Hardware-Breakpoint auf Schreiben: ba w1 ffffd003'7f5bea30

Nach der Initialisierung auf Null stoppt er, wenn pbImage gespeichert wird.

Die Analyse besagt, dass es Block0 entspricht, da die Konstante r14*8, die danach 0x30 beträgt, nicht berücksichtigt wird. Als Ergebnis wird tatsächlich das pbImage von Block 2 geschrieben.

A picture containing text, screenshot, font Description automatically
generated

Beachten Sie, dass CClfsBaseFilePersisted::ReadMetadataBlock verwendet wird, um einen der Blöcke zuzuweisen, unter Verwendung der als Argument übergebenen Größe.

A picture containing text, font, screenshot, line Description
automatically generated

Setzen Sie nun einen Lese-/Schreib-Breakpoint bei 0x58 vom Basisblock, um zu sehen, wann der Wert 0x369 verwendet wird.

ba r1 FFFF978A'16ECF000+0x58

Wenn der Breakpoint erreicht wird, liest er den Wert 0x369, der sich bei RecordOffset[12] befindet, addiert ihn zu einem seltsamen Zeiger auf r14 und erhöht den Inhalt von RAX+r14.

Einige Zeilen weiter oben im Code hat ESI den Wert 0x13 und multipliziert mit 0x18, was der Größe jedes Blocks in m_rgBlocks entspricht.

WINDBG>? 0x18*0x13

Evaluate expression: 456 = 00000000'000001c8

Wenn ich den Wert von r8= 0x1c8, der größer als 0x90 ist, zur Anfangsadresse von m_rgBlocks addiere, wird es OUT OF BOUNDS lesen.

A screenshot of a computer Description automatically
generated

Unterhalb von m_rgBlocks befindet sich die Pipe mit dem Zeiger auf BASE BLOCK + 0x30, er liest diesen Zeiger, der strategisch innerhalb der Pipe platziert wurde.

A screenshot of a computer program Description automatically generated
with low confidenceDie aktuelle Position im Code wurde von der while(1)-Anweisung des Hauptmoduls aus aufgerufen.

In der spray blf-Datei habe ich strategisch den Wert 0x13 bei Offset 0x48a (iFlushBlock) platziert.

A picture containing text, font, line, screenshot Description
automatically generated

3-Betrachten des iFlushBlock-Werts in der spray blf-Datei.

Bei Offset 0x8a der spray blf-Datei befindet sich der iFlushBlock von BLOCK 0, dessen Wert 4 ist, während Offset 0x48a zum iFlushBlock von BLOCK 1 gehört und dessen Wert 0x13 ist.

A screenshot of a computer Description automatically generated with
medium confidence

Jetzt muss ich herausfinden, warum iFlushBlock = 0x13 von BLOCK 1 anstatt iFlushBlock = 4 von BLOCK 0 gelesen wird.

4-Warum wird von BLOCK 1 SHADOW gelesen anstatt von BLOCK 0 CONTROL?

Wenn ich zurückblicke, um herauszufinden, woher die 0x13 stammt, sehe ich im Call-Stack, dass WriteMetadataBlock von CClfsBaseFilePersisted::ExtendMetadataBlock+416 aufgerufen wird, dort ist das zweite iFlushBlock-Argument EDX=0x13, das von r9w stammt.

A screenshot of a computer code Description automatically generated
with low confidence

A picture containing text, screenshot, font, line Description
automatically generated

A screenshot of a computer program Description automatically generated
with low confidenceEin paar Zeilen zuvor wurde CClfsBaseFile::GetControlRecord aufgerufen, um die Adresse von BLOCK 0 abzurufen. Vielleicht liegt das Problem hier, also starte ich neu und setze einen Breakpoint darauf.

GetControlRecord ruft CClfsBaseFile::AcquireMetadataBlock auf, der die m_rgBlocks-Tabelle mit der Adresse von Block 0 füllen sollte. Wenn ich über diese Funktion hinwegsteige, erhalte ich die Adresse von Block 1. Das Problem tritt also innerhalb von CClfsBaseFile::AcquireMetadataBlock auf.

Durch Hinzufügen von 0x8A zur abgerufenen Adresse kann ich bestätigen, dass der Wert 0x13, der zu BLOCK 1 gehört, vorhanden ist.

A screenshot of a computer code Description automatically generated
with medium confidence

Ich werde neu starten und dort einen Breakpoint setzen:

A screenshot of a computer program Description automatically generated
with low confidence

CClfsBaseFile::GetControlRecord+27 call CClfsBaseFile::AcquireMetadataBlock

A screenshot of a computer Description automatically
generated

Das zweite an AcquireMetadataBlock übergebene Argument ist Null, es entspricht Block 0, es wird aus der Datei kopiert und seine Adresse in m_rgBlocks gespeichert A screenshot of a computer Description automatically generated with medium confidence.

In der _CLFS_METADATA_BLOCK_TYPE-Blocktyp-Enumeration haben sie andere Namen als ich verwendet habe, aber es sind die gleichen 6 Blöcke.

A picture containing text, screenshot, font, line Description
automatically generated

Nachdem überprüft wurde, dass der Blocktyp kleiner als das Maximum m_cBlocks=6 ist, speichert er einen Referenz-Wert, um zu vermeiden, dass derselbe Block zweimal gelesen wird.

A screenshot of a computer code Description automatically generated
with low confidence

ReadMetadataBlock wird aufgerufen. Das Problem des Lesens von Block 1 anstelle von Block 0 würde innerhalb dieser Funktion liegen.

A picture containing text, font, number, line Description
automatically generated

Wenn alles in Ordnung ist, weist es mit cbImage als Größe zu und speichert die Adresse im Feld Block 0-> pbImage in m_rgBlocks.

A picture containing text, font, line, screenshot Description
automatically generated

Der Befehl !pool zeigt das Tag und die Größe der Zuweisung an.

A picture containing text, screenshot, font, line Description
automatically generated

A picture containing text, screenshot, font, line Description
automatically generatedIch habe also bereits die Adresse von pbImage von Block 0 in m_rgBlocks gespeichert. Ich muss also sehen, warum dort die Bytes von Block 1 anstelle der Bytes von Block 0 kopiert werden.

Ich gelange zu einem Aufruf von CClfsContainer::ReadSector, bei dem ein Zeiger auf eine Variable, die pbImage enthält, übergeben wird, um die Bytes zu schreiben.

Beachten Sie die Änderungen im Inhalt von pbImage, wenn Sie über ReadSector hinwegsteigen.

Durch Hinzufügen von 0x8a zu pbImage kann ich den Wert 4 finden, der korrekt ist, anstelle von 0x13. Das Problem muss also später auftreten.

Nach dem Aufruf von ClfsDecodeBlock wird ein Fehler 0x0C01A000A zurückgegeben.

CClfsBaseFilePersisted::ReadMetadataBlock+153 ruft ClfsDecodeBlock auf.

Nach diesem Fehler addiert es 1 zum Typ und ruft CClfsBaseFilePersisted::ReadMetadataBlock erneut auf, jedoch mit Typ 1, um Block 1 zu lesen.

A screenshot of a computer Description automatically
generated

In CClfsBaseFilePersisted::ReadMetadataBlock weist es ein neues pbImage zu und speichert es in m_rgBlocks für Block 1.

A screenshot of a computer code Description automatically generated
with low confidence

Blöcke 0 und 1 haben unterschiedliche Adressen. Wenn ich jetzt 0x8a zur Adresse von Block 1 hinzufüge, ist sein Wert 0x13.

Vielleicht verwendet es, da Block 0 einen Fehler zurückgab, Block 1 und gibt ihn an GetControlRecord als Control Block zurück.

Wie zuvor gezeigt, führt die Verwendung des Werts 0x13 anstelle von 4 dazu, dass die Grenzen von m_rgBlocks überschritten werden und die von mir kontrollierten Pipe-Spray-Werte gelesen werden.

A picture containing text, screenshot, font Description automatically
generatedDann wird das pbImage von Block 0 freigegeben und der Zeiger von Block 1 nach Block 0 kopiert.

A screenshot of a computer Description automatically
generated

Es wäre notwendig, den Wert zu finden, der den Fehler 0x0C01A000A innerhalb von ClfsDecodeBlock verursacht.

Innerhalb von ClfsDecodeBlock ist die Checksumme des ersten Blocks Null. Dies ist der Fehler 0xC01A000A.

A screenshot of a computer Description automatically generated with
medium confidence

5-Warum ist die Checksumme bei blf-Spray-Dateien gleich Null?

Vor dem Aufruf von AddLogContainer wurde beim Öffnen einer spray blf-Datei mit einem Hexadezimaleditor die Checksumme auf Null geändert.

A screenshot of a computer Description automatically
generated

Es hätte bereits vorher geändert werden müssen, als es mit CreateLogFile geöffnet wurde.

A picture containing text, screenshot, display, font Description
automatically generated

Aus irgendeinem Grund haben die spray blf-Dateien nach dem Verlassen von CreateLogFile eine Checksumme von Block 0 gleich 0 und geben ein gültiges Handle zurück. Sehen wir uns an, warum das passiert.

Ich halte an bei CreateLogFile, bevor ich eine Spray-BLF-Datei öffne.

A screenshot of a computer Description automatically generated with
medium confidence

Beachten Sie, dass die Spray-Dateien vor dem Aufruf von CreateLogFile die korrekte Checksumme in Block 0 haben, und nach Abschluss der Funktion ändert sich der Checksummenwert auf Null.

A screenshot of a computer code Description automatically generated
with low confidence

Also setze ich einen Breakpoint auf CClfsBaseFile::GetControlRecord, um hineinzuschauen.

A picture containing text, screenshot, font, line Description
automatically generatedNach dem Durchlaufen von CClfsContainer::ReadSector ist die Checksumme nicht Null.

Vor dem Eintritt in die CRC32-Berechnung setzt es das Checksummen-Feld im Speicher auf Null, um die CRC zu berechnen, und das Ergebnis ist korrekt.

A picture containing text, font, screenshot Description automatically
generated

A picture containing text, font, line, screenshot Description
automatically generated

Dann überprüft es den Wert von eExtendState =2 und geht zu WriteMetadataBlock.

A screenshot of a computer Description automatically generated with
medium confidence

Hier ist die Checksumme im Speicher noch Null. Ich muss nur sehen, wann dieser Wert in die Datei geschrieben wird.

A picture containing text, font, line, screenshot Description
automatically generated

Es überprüft einige Werte, die in der blf spray-Datei präpariert sind, um zu CClfsBaseFilePersisted::ExtendMetadataBlock zu gelangen.

A screenshot of a computer program Description automatically generated
with medium confidence

Nach einer Schleife zum Lesen von Blöcken, die noch nicht gelesen wurden, hat Block 0 weiterhin Checksumme = 0.

A white rectangle with black text Description automatically generated
with low confidence

Ankunft bei WriteMetadataBlock.

Da ich laufe, bevor Block 0 durch 1 ersetzt wird, ist der iFlushBlock-Wert der blf spray-Datei immer noch 4, der korrekte Wert.

A screenshot of a computer Description automatically generated with
medium confidence

Jetzt arbeitet es mit Block 4, und es wird Block 4 in die Datei schreiben. Hier ist das Problem noch nicht.

Dann kommt es zu CClfsBaseFilePersisted::FlushControlRecord

A screenshot of a computer program Description automatically generated
with medium confidence

Innerhalb erreicht es WriteMetadataBlock, aber mit Argument 0, um Block 0 in die Datei zu schreiben**.**

A screenshot of a computer Description automatically generated with
medium confidence

Dann gibt ClfsEncodeBlock den Fehler 0xC01A000A zurück, obwohl es die Datei mit dem schlechten Block 0 in CClfsContainer::WriteSector, direkt darunter, schreiben wird.

A screenshot of a computer Description automatically generated with
medium confidence

Die Variable var_54 speichert den Fehlerwert 0xC01A000A und wird vor dem Verlassen der Funktion überprüft.

A screenshot of a computer Description automatically generated with
medium confidence

Aber nach dem Aufruf von CClfsContainer::WriteSector, der keinen Fehler zurückgibt, wird der Inhalt von var_54 mit Null überschrieben.

Die Funktion gibt also Null ohne Fehler zurück, und sie arbeitet weiter, da CreateLogFile ein Handle anstelle eines Fehlerwerts zurückgibt.

A screenshot of a computer Description automatically
generated

6-Abschluss der Ausnutzung.

Der Wert 0x13 in iFlushBlock führt dazu, dass es die Grenzen überschreitet (out of bounds), und es wird der Zeiger gelesen, der sich in den Pipes befindet und auf den Base Block + 30 von trigger blf zeigt.

A screenshot of a computer Description automatically
generatedDann addiert es 0x28 zu diesem Zeiger ( 0x58 vom Anfang des Basisblocks des trigger blf), der den Wert 0x369 hat.

Ein Screenshot eines Computerprogramms, Beschreibung automatisch generiert mit mittlerer Sicherheit

Die INC-Anweisung erhöht den Wert 0x14 um 1 und wiederholt dies 4 Mal, sodass 0x14 zu 0x18 wird.

WINDBG>db r14+369

ffffcb82'091e7397 14 00 00 00

Danach wird CreateLogFile aufgerufen und liest den Wert 0x1858.

Ein Screenshot eines Computers, Beschreibung automatisch generiert mit mittlerer Sicherheit

Eine Nahaufnahme einer Karte, Beschreibung automatisch generiert mit niedriger SicherheitGetSymbol prüft, ob der zuvor in trigger blf erstellte Fake-Block, auf den der Offset 0x1858 zeigt, die korrekten Werte enthält.

Ein Bild mit Text, Schriftart, Linie, Screenshot, Beschreibung automatisch generiert

Wenn der Zeiger nicht mehrmals inkrementiert worden wäre, hätte er den ursprünglichen Wert 0x1458 und würde auf den richtigen Block zeigen.

Nach dem Verlassen von GetSymbol wird dieser Fake-Block hier verwendet.

Ein Screenshot eines Computers, Beschreibung automatisch generiert mit mittlerer Sicherheit

Dann wird der Wert des Offsets 0x18 des Fake-Blocks gelesen, wo ich 0x05000000 platziert habe, und es wird zum Inhalt dessen gesprungen, was dort steht.

WINDBG>dps 0x5000000

00000000'05000000 00000000'05001000

Es liest den Inhalt von 0x05000000 und dessen 0x05001000 und dort befindet sich ClfsEarlierLsn.

Ein Screenshot eines Computerprogramms, Beschreibung automatisch generiert mit niedriger Sicherheit

Diese Funktion wird verwendet, um den Wert 0xFFFFFFFF in RDX zurückzugeben, obwohl dieser Wert beim ersten Mal nicht verwendet wird.

Der zweite Aufruf erfolgt hier, es ruft PoFxProcessorNotification auf, das sich bei 0x501000 +8 befand.

Ein Bild mit Text, Schriftart, Screenshot, Linie, Beschreibung automatisch generiert Ein Bild mit Text, Schriftart, Screenshot, Linie, Beschreibung automatisch generiert

WINDBG>dps 00000000**'05001000**

00000000'05001000 fffff805'7ab13220 CLFS! ClfsEarlierLsn

00000000'05001008 fffff805'769dc3b0 nt! PoFxProcessorNotification

Ein Screenshot eines Computerbildschirms, Beschreibung automatisch generiert mit niedriger Sicherheit

In dieser Funktion ist RCX = 0x05000000, es prüft, dass 0x40 Bytes später ungleich Null sein müssen.

WINDBG>dps rcx+40

00000000'05000040 00000000'05000000

Die Adresse, zu der gesprungen wird, ist 0x68 später.

WINDBG>dps rcx+68

00000000'05000068 fffff805'7ab2bfb0 CLFS! ClfsMgmtDeregisterManagedClient

Und das Argument ist 0x48 Bytes später.

WINDBG>dps rcx+48

00000000'05000048 00000000'05000400

Die ClfsMgmtDeregisterManagedClient, es ist eine praktische Funktion, weil ich das Argument kontrollieren kann und ich auch zwei Sprünge zu von mir kontrollierten Funktionen habe.

Ein Screenshot eines Computers, Beschreibung automatisch generiert

Der erste Aufruf geht wieder an ClfsEarlierLsn, das RDX=0xFFFFFFFF zurückgab.

Ein Screenshot eines Computers, Beschreibung automatisch generiert mit mittlerer Sicherheit

Ein Screenshot eines Computers, Beschreibung automatisch generiert mit mittlerer Sicherheit

Es nimmt die Quelle, um daraus zu schreiben, aus dem Inhalt von RDX=0xFFFFFFFF.

WINDBG>dps rdx

00000000'ffffffff ffff8005'3a4ee000

An der Adresse 0xFFFFFFFF hatte ich den system_EPROCESS & 0xfffffffffffff000 gespeichert.

Ein Bild mit Text, Schriftart, Linie, Nummer, Beschreibung automatisch generiert

Das Ziel ist der Zeiger bei 0x5000400 +0x48

*(UINT64*)0x5000448 = para_PipeAttributeobjInkernel + 0x18;

Ein Screenshot eines Computers, Beschreibung automatisch generiert

Der PipeAttribute-Zeiger im Kernel, der auf einen mit „A“ gefüllten Puffer zeigt, wird mit dem hohen Teil des SYSTEM EPROCESS-Zeigers überschrieben.

Dieser Zeiger wurde erstellt, als ich zuvor _NtFsControlFile mit einem mit „A“ gefüllten Puffer aufgerufen habe.

Ein Screenshot eines Computerprogramms, Beschreibung automatisch generiert mit mittlerer Sicherheit

Der Inhalt dieses Attributs kann mit NtFsControlFile gelesen werden.

Ein Screenshot eines Computerbildschirms, Beschreibung automatisch generiert mit mittlerer Sicherheit

Nun zeigt das Pipe-Attribut nicht mehr auf den Puffer mit „A“, sondern auf system_EPROCESS & 0xffffffffffffff000.

Ein Screenshot eines Computerprogramms, Beschreibung automatisch generiert mit niedriger Sicherheit

Dieser Code wird wiederholt, bis das System-Token abgerufen ist.

Ein Screenshot eines Computercodes, Beschreibung automatisch generiert mit mittlerer Sicherheit

Ein Screenshot eines Computers, Beschreibung automatisch generiert

Unter Windows 11 befindet sich das System-Token bei Offset 0x4b8 der kürzlich gelesenen EPROCESS-Struktur.

Ein Screenshot eines Computers, Beschreibung automatisch generiert

Ich muss nur dieses System-Token in meinen Prozess schreiben, indem ich CreateLogFile aufrufe.

Ein Bild mit Text, Schriftart, Linie, Screenshot, Beschreibung automatisch generiert

Um diese Aufgabe zu erledigen, wiederhole ich einfach den Schritt, der zum Lesen des System-Tokens verwendet wurde.

Ein Screenshot eines Computers, Beschreibung automatisch generiert mit mittlerer Sicherheit

Beim doppelten Aufruf wird zuerst ClfsEarlierLsn aufgerufen, um 0xFFFFFFFF in RDX zurückzugeben, und dann wird nt_SeSetAccessStateGenericMapping aufgerufen.

Ein Bild mit Text, Screenshot, Schriftart, Linie, Beschreibung automatisch generiert

Ich überprüfe, ob der von RDX referenzierte Wert das System-Token ist.

Ein Bild mit Text, Screenshot, Schriftart, Beschreibung automatisch generiert

Das Token meines Prozesses ist:

Es wird dorthin schreiben.

WINDBG>dps rax+8

ffff9b8b'fc446578 ffffc402'f601c06c

WINDBG>dps rax+8

ffff9b8b'fc446578 ffffc402'ef841919

Jetzt ist mein Prozess System; ich kann einen Notepad ausführen, um dies zu überprüfen.

Ein Bild mit Text, Screenshot, Schriftart, Linie, Beschreibung automatisch generiert

Ein Screenshot eines Computers, Beschreibung automatisch generiert

Ein Screenshot eines Computers, Beschreibung automatisch generiert

7 – Der eigentliche Patch

BINDIFF zeigt viele geänderte Funktionen.

Ein Screenshot eines Computers, Beschreibung automatisch generiert

Die anfällige Funktion befindet sich hier:

Ein Screenshot eines Computers, Beschreibung automatisch generiert mit mittlerer Sicherheit

Ein Screenshot eines Computers, Beschreibung automatisch generiert

Die primäre ist die gepatchte Version, die sekundäre ist die anfällige Version.

Der Patch testet den Rückgabewert von CflsEncodeBlock, der 0xC01A000A ist, speichert ihn in der Variablen var_54, und da er negativ ist, wird er überprüft und vermeidet das WriteSector.

Der Patch schreibt nicht nur die Datei nicht, sondern die Funktion gibt auch korrekt 0xc01a000a zurück, womit CreateLogFile keinen Handle zurückgibt und die Ausnutzung nicht fortgesetzt werden kann.

Ein Screenshot eines Computers, Beschreibung automatisch generiert mit mittlerer Sicherheit

Ein Screenshot eines Computers, Beschreibung automatisch generiert

Nur wenn ClfsDecodeBlock nicht negativ ist, geht es zu WriteSector, lässt aber den negativen Wert 0xC01A000A zurückgeben.

Ein Screenshot eines Computers, Beschreibung automatisch generiert mit mittlerer SicherheitDies ist der eigentliche Patch, der die Ausnutzung mit dem soeben beigefügten PoC tatsächlich verhindert.

An diesem Punkt haben wir erklärt, wie der Bug ausgenutzt wurde; er führt zur Kontrolle der Funktionen, die es uns ermöglichen, das SYSTEM-Token zu lesen und es in unseren eigenen Prozess zu schreiben, um die lokale Rechteausweitung zu erreichen. Sie finden den funktionalen PoC auf Fortras GitHub.

Wir hoffen, es ist nützlich für Sie; bei Fragen können Sie uns kontaktieren:

[email protected] 
@ricnar456

 [email protected]
@solidclt

Tool herunterladen