
(1) IQVW32.sys vor 1.3.1.0 und (2) IQVW64.sys vor 1.3.1.0 im Intel Ethernet-Diagnosetreiber für Windows ermöglicht es lokalen Benutzern, einen Denial-of-Service zu verursachen oder möglicherweise beliebigen Code mit Kernel-Berechtigungen auszuführen, indem sie einen manipulierten (a) 0x80862013, (b) 0x8086200B, (c) 0x8086200F oder (d) 0x80862007 IOCTL-Aufruf verwenden.
(1) IQVW32.sys vor Version 1.3.1.0 und (2) IQVW64.sys vor Version 1.3.1.0 im Intel Ethernet-Diagnosetreiber für Windows ermöglicht es lokalen Benutzern, einen Denial-of-Service zu verursachen oder möglicherweise beliebigen Code mit Kernel-Berechtigungen auszuführen, indem sie einen manipulierten (a) 0x80862013-, (b) 0x8086200B-, (c) 0x8086200F- oder (d) 0x80862007-IOCTL-Aufruf verwenden.
Dieses Repository enthält eine Aufarbeitung der fraglichen Sicherheitslücke sowie Proof-of-Concept-Exploits, die auf 64-Bit Windows 7 SP1 und Windows 10 20H2 funktionieren. Die Treiberdatei befindet sich im Verzeichnis Driver Files. Sollten Sie Tippfehler in der Aufarbeitung/dem Papier entdecken oder bestimmte Details ausführlicher beschrieben sehen wollen, erstellen Sie bitte ein Issue im Repository! Ich werde sie so schnell wie möglich beheben.
Die Motivation, einen Exploit für genau diesen Gerätetreiber zu schreiben, liegt einzig und allein darin, dass er derzeit in freier Wildbahn missbraucht wird, um das nicht signierte Rootkit eines Angreifers zu laden. Mit der BYOVD-Methode (Bring Your Own Vulnerable Driver) kann Malware prüfen, ob sie mit erhöhten Privilegien läuft, eine Kopie des anfälligen Gerätetreibers ablegen, den Treiber laden und ihn anschließend ausnutzen, um Kernel-Code-Ausführung zum Laden des Rootkits zu erlangen. Es gelang mir nicht, die Malware-Probe erfolgreich zu reverse-engineeren, also habe ich es mir zur Aufgabe gemacht, den Exploit zu erstellen.
In freier Wildbahn gesichtete Proben: https://bazaar.abuse.ch/sample/84ed7fec67de5621806dbb43af5167a5fc60ab7f2403448519dc0eca2b8f9022/ https://bazaar.abuse.ch/sample/0925b8985b19d7925d68186d666b0050a4cb3f2a577d64765d770a57a2eab9ae/ https://bazaar.abuse.ch/sample/e8b7f42d544fe8b954c4021315cff2fdd44d67d11704009cdf3037d34e0c0a93/
Der Gerätetreiber, nämlich iqvw64e.sys, ist ein Treiber, der für die Durchführung von Netzwerkadapter-Diagnosen entwickelt wurde. Er ermöglicht der Benutzermodus-Komponente die Interaktion mit dem Gerätetreiber, um eine Vielzahl von Kernel-Routinen auszuführen, indem er einige IO-Steuercodes (auch bekannt als IOCTLs) freigibt, wobei während der Interaktion ein „Unter“-IO-Steuercode im Eingabepuffer des Benutzers bereitgestellt wird. Der IO-Steuercode, der verwendet wird, um den anfälligen Codepfad zu treffen, ist 0x80862007. Zusätzlich zum primären Steuercode werden in dieser Analyse die genannten „Unter“-IO-Steuercodes behandelt: der Code 0x33 zum Treffen des memmove-Funktionsaufrufs und der Code 0x30 zum Treffen der Codepfade des memset-Funktionsaufrufs. Diese Aufarbeitung wird keine Details zur DriverEntry-Routine behandeln, da es auf der Microsoft-Dokumentationsseite genügend Dokumentation gibt, die Ihnen eine gründliche Erklärung liefert.
Zunächst möchten wir wissen, wie wir überhaupt mit diesem bestimmten Gerätetreiber interagieren können. Die gängigste Methode zur Kommunikation mit einem Gerätetreiber ist die Verwendung einer Funktion namens DeviceIoControl. Die grundlegende Idee hinter dieser Funktion ist, dass wir ein gültiges Treiberhandle übergeben können, das mit CreateFileA erstellt wurde, einen IO-Steuercode übergeben, der der gewünschten Kernel-Routine entspricht, eine Struktur (oder einen Puffer) übergeben, die erwartet wird, und die Funktion gibt Daten in unserem Ausgabepuffer zurück. Während Routinen wie diese manchmal notwendig sein können (z. B. Zugriff auf modellspezifische Register für Übertaktungszwecke), stellen sie auch ein ernstes Sicherheitsrisiko dar. Aber … wie?
Im Fall von CVE-2015-2291 kann die Sicherheitslücke von einem nicht privilegierten Benutzer ausgelöst werden. Da keine Bereinigungsprüfungen vorhanden sind und Administratorrechte nicht erforderlich sind, um die Sicherheitslücke auszunutzen, stellt dies ein Sicherheitsrisiko dar. Was unter diesen beiden Fehlern liegt, ist die Fähigkeit, die durch die IO-Steuercode-Schnittstelle freigegebenen memset- und memmove-Funktionsaufrufe vollständig zu kontrollieren. Erinnern Sie sich an die zuvor erwähnte Funktion DeviceIoControl, wie wir eine Struktur übergeben können, die in einer Kernel-Routine verwendet wird? So fügt sich alles zusammen.
Gehen wir einen Schritt zurück. Zuerst möchten wir das Treiberhandle erhalten, das mit dem anfälligen Gerätetreiber verbunden ist. Aber noch davor müssen wir das korrelierende benannte Geräteobjekt lokalisieren. Diese werden dem Benutzerraum durch einen symbolischen Link (oft hartcodiert) zur Verfügung gestellt, der mit WinObj, einem Teil der [SysInternals-Suite], gefunden werden kann. Obwohl wir ein String-Dump-Tool verwenden könnten, um den symbolischen Link auszulesen, oder alternativ den Gerätetreiber reverse-engineeren könnten, habe ich einfach den Gerätetreiber geladen und ihn mit WinObj lokalisiert. Der symbolische Link, der sich auf den Gerätetreiber bezieht, ist \\.\GLOBALROOT\Device\Nal. Um das Treiberhandle zu erhalten, müssen wir die Funktion CreateFileA aufrufen und sie ein gültiges Treiberhandle zurückgeben lassen, das wir später im Prozess verwenden können. Der Code für diesen Prozess lautet wie folgt:```C
if (h_nal == (HANDLE)-1)
{
printf("\n[-] Unable to obtain a driver handle to the Nal device driver. Error: %d (0x%x)", GetLastError(), GetLastError());
unused = getchar();
return 1;
}
printf("\n[+] Obtained a driver handle to the Nal device driver. Handle Value: 0x%p", h_nal);
Wir werden später im Exploitierungsprozess das Treiber-Handle verwenden. Zunächst beginnen wir mit der Vorbereitung unseres Exploits. Der nächste Schritt wäre das Laden der Bibliothek `ntdll.dll` mithilfe der Funktion [LoadLibraryA](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya), um ein [Modul-Handle](https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types) zurückzugeben, damit wir die benötigten Funktionen dynamisch lokalisieren können. Obwohl die Bibliothek `ntdll.dll` möglicherweise bereits in unseren Prozess geladen ist, müssen wir dennoch ein Handle für die Bibliothek erhalten, das wir verwenden können. Die Funktionen, die wir für den Exploit benötigen, sind [NtQuerySystemInformation](https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation), um die Basisadresse des NT-Kernels (mit mittlerer Prozessintegrität) für später im Exploitierungsprozess zu leaken, und die Funktion [NtQueryIntervalProfile](http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FProfile%2FNtQueryIntervalProfile.html), um die Sicherheitslücke auszulösen. Der Code zum Laden der Bibliothek `ntdll.dll` sieht wie folgt aus:```C
h_ntdll = LoadLibraryA("C:\\Windows\\System32\\ntdll.dll");
if (!h_ntdll)
{
printf("\n[-] Failed to load the \"ntdll.dll\" API library. Error: %d (0x%x)", GetLastError(), GetLastError());
unused = getchar();
return 0;
}
printf("\n[+] Loaded the \"ntdll.dll\" API library. Handle Value: 0x%p", h_ntdll);