Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
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.

FeedsKontaktDatenschutz© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2016-3308 — CVE-2016-3308 nutzen, um den win32k-Desktop-Heap zu korrumpieren. | Kitploit
Tools/GitHubGitHub/jackhuyh/cve-2016-3308
SpeicherforensikSchwachstellenanalyseExploitationBinary-Exploitation
GitHubjackhuyh/cve-2016-3308

CVE-2016-3308

CVE-2016-3308 nutzen, um den win32k-Desktop-Heap zu korrumpieren.

Repository anzeigen
12111vor 10 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Nutzung von CVE-2016-3308 zur Korruption des win32k-Desktop-Heaps

Autor : @55-AA, 18. September 2016

##Einleitung

Desktop-Heap ist ein Kernel-Pool, der von win32k verwendet wird und durch eine Anwendung im Benutzermodus ausgenutzt werden kann. Hier werde ich im Detail beschreiben, wie eine zuverlässige Ausnutzung implementiert werden kann, um beliebige Adressen im Kernel zu lesen/schreiben. Dieser Bericht und die zugehörige Analyse wurden auf einer win7_sp1_x86-Installation (Build 17842) durchgeführt.

##Schwachstelle

Am 9. August 2016 veröffentlichte Microsoft MS16-098. Der verwundbare Code befindet sich in der Funktion win32k!xxxInsertMenuItem. Der Funktionsprototyp ist:

BOOL xxxInsertMenuItem(
        PMENU pMenu, 
        UINT wIndex, 
        BOOL fByPosition, 
        LPMENUITEMINFOW lpmii, 
        PUNICODE_STRING pstrItem
    );

Zuerst betrachten wir den Pseudocode des Fehlers in xxxInsertMenuItem:

if (pMenu->cItems >= pMenu->cAlloced) {
    if (pMenu->rgItems) {
        pNewItems = (PITEM)DesktopAlloc(
                        pMenu->head.rpdesk,
                        (pMenu->cAlloced + CMENUITEMALLOC) * sizeof(ITEM),
                        DTAG_MENUITEM);
 ......

    pMenu->cAlloced += CMENUITEMALLOC;
    pMenu->rgItems = pNewItems;
    if (wIndex != MFMWFP_NOITEM)
        pItem = MNLookUpItem(pMenu, wIndex, fByPosition, &pMenuItemIsOn);

......

pMenu->cItems++;
if (pItem != NULL) {
    RtlMoveMemory(pItem + 1, pItem, (pMenu->cItems - 1) *
            sizeof(ITEM) - ((char *)pItem - (char *)pMenu->rgItems));
} else {

Im obigen Code: Als das 9. (ab dem 1.) Element in pMenu eingefügt wurde, wurde DesktopAlloc() aufgerufen, um ein neues pMenu->rgItems neu zu allozieren. Dann wurde MNLookUpItem() aufgerufen, um die Position des Elements in pMenu->rgItems zu ermitteln. Aber das von MNLookUpItem() zurückgegebene pItem ist ein rgItems eines anderen pSubMenu statt des pMenu. Wenn RtlMoveMemory() aufgerufen wird, würden das pItem des pSubMenu und die folgenden Bytes aufgrund der fehlerhaften Verschiebegröße überschrieben.

Im Folgenden ist der Disassemblierungscode zu dem Fehler, der einen Heap-Overwrite auslöst; er kann genutzt werden, um einen gefälschten Chunk aufzubauen:

0: kd> u win32k!xxxInsertMenuItem+0x1f5 l8
win32k!xxxInsertMenuItem+0x1f5:
95d295af 6bc06c          imul    eax,eax,6Ch
95d295b2 2bc3            sub     eax,ebx
95d295b4 034634          add     eax,dword ptr [esi+34h]
95d295b7 50              push    eax
95d295b8 8d436c          lea     eax,[ebx+6Ch]
95d295bb 53              push    ebx
95d295bc 50              push    eax
95d295bd e85ea40100      call    win32k!memmove (95d43a20)

Um den Fehler zu verfolgen, verwende ich diese Haltepunkte in WinDbg:

ba e1 win32k!xxxInsertMenuItem

ba e1 win32k!xxxInsertMenuItem+0xf3    
95d294e3 e843e70200      call    win32k!DesktopAlloc (836d7bf5)

ba e1 win32k!xxxInsertMenuItem+0x129
95d294e3 e80de70200      call    win32k!DesktopAlloc (836d7bf5)

ba e1 win32k!xxxInsertMenuItem+0x1f5
95d295af 6bc06c          imul    eax,eax,6Ch

Um den Fehler auszulösen, müssen die folgenden Schritte durchgeführt werden:

  1. Ein Menü erstellen.
  2. Ein Untermenü als erstes ITEM des Menüs mit der ID 0x123 erstellen; dabei ist es notwendig, MENUITEMINFO.hbmpItem auf HBMMENU_SYSTEM zu setzen.
  3. Weitere 7 ITEMs mit IDs von 0x1001 bis 0x1007 zum Menü hinzufügen.
  4. Ein ITEM mit der ID 1 zum Untermenü hinzufügen.
  5. Weitere 8 ITEMs zum Untermenü hinzufügen, um ein tagMENU.rgItems mit 16 Slots zu erhalten. Dieser Schritt ist jedoch nicht notwendig, um den Fehler auszulösen, falls nur ein Absturz gewünscht ist.
  6. Das 9. ITEM mit der ID 0x123 zum Menü hinzufügen, sodass das erwartete RtlMoveMemory() mit falschen Parametern aufgerufen wird.

Desktop-Heap

Desktop-Heap ist ein globaler Pool, der von allen GUI-Prozessen verwendet wird. Alle GUI-Objekte wie Fenster und Menüs werden im Desktop-Heap gespeichert und vom Kernel-Heap-Allokator verwaltet. Der Kernel-Heap-Allokator verwendet vertraute Funktionen wie RtlAllocateHeap und RtlFreeHeap. Anders als der User-Mode-Heap verwendet der Desktop-Heap keine Front-End-Allokatoren, es gibt also keinen Low-Fragmentation-Heap, keine Lookaside-Liste usw. Außerdem gibt es erst ab Windows 8 eine Heap-Verschlüsselung. Im Folgenden ist die Struktur eines Chunks auf win7_sp1_x86:

typedef struct _HEAP_ENTRY {
    USHORT Size;
    UCHAR Flags;
    UCHAR SegmentIndex;
    USHORT PreviousSize;
    UCHAR SegmentOffset;
    UCHAR UnusedBytes;
 } HEAP_ENTRY, *PHEAP_ENTRY;

Die Felder Size und PreviousSize repräsentieren die Chunk-Größe, die um HEAP_GRANULARITY_SHIFT (auf 32-Bit-Systemen als 3 definiert) Bits nach rechts verschoben ist. Das Feld Size gibt den aktuellen Chunk an, und PreviousSize den vorherigen. Das niederwertigste Bit von Flags ist normalerweise auf HEAP_ENTRY_BUSY (0x01) gesetzt, was bedeutet, dass der Chunk in Benutzung ist; andernfalls ist es 0x00.

Die folgende Abbildung zeigt die Beziehung zwischen diesen Feldern und den Chunk-Blöcken. Das zweite grün unterstrichene WORD (0x000f) repräsentiert, dass die aktuelle Chunk-Größe 0x78 Bytes beträgt. Das zweite schwarz unterstrichene WORD (0x0003) repräsentiert, dass die vorherige Chunk-Größe 0x18 Bytes beträgt, und die rot unterstrichenen WORDs (0x0001) repräsentieren, dass die aktuellen Chunks in Benutzung sind. Hier enthält die Chunk-Größe die Header-Größe; der Header ist als die obige HEAP_ENTRY-Struktur definiert.

Das wichtigste Merkmal für die Heap-Korruption ist, dass der Heap-Allokator immer den zuletzt freigegebenen Chunk zurückgibt. Das bedeutet, dass wir tatsächlich einen Chunk beliebiger Größe an einer von uns gewünschten Position allozieren können.

Korruption

Durch Ausnutzung des Fehlers kann ich einige Bytes im Desktop-Heap überschreiben. Dadurch erhalte ich einen gefälschten Chunk, der einen normalen Chunk ersetzt. Dann gebe ich den ersetzten Chunk frei, sodass der gefälschte Chunk an die Spitze der Freiliste gelangt. Anschließend wird der gefälschte Chunk wiederverwendet; ich kann beliebige Bytes in ihn schreiben. Der schreibbare Bereich überlappt mehrere normale Chunks, kann aber nicht den gesamten Kernel-Bereich abdecken. Daher muss ich in dem überlappten Bereich eine weitere Lese-/Schreib-Primitive aufbauen, die tagWND.strName ausnutzt, um an beliebige Adressen zu schreiben. Der Zeiger strName.Buffer kann uns überallhin führen, einschließlich Kernel- und Benutzerbereich. Unser Ziel ist natürlich nur die nt!HalDispatchTable.

Die folgende Abbildung zeigt den Ablauf der Heap-Veränderung:

Entsprechend der Darstellung korrumpiere ich den Desktop-Heap Schritt für Schritt und implementiere die Ausnutzung in den folgenden Phasen:

Tool herunterladen