Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2016-3308 — Utiliser CVE-2016-3308 pour corrompre le tas de bureau win32k | Kitploit
Outils/GitHubGitHub/jackhuyh/cve-2016-3308
Criminalistique MémoireAnalyse des VulnérabilitésExploitationExploitation de Binaires
GitHubjackhuyh/cve-2016-3308

CVE-2016-3308

Utiliser CVE-2016-3308 pour corrompre le tas de bureau win32k

Voir le dépôt
12111il y a 10 ansPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Utiliser CVE-2016-3308 pour corrompre le tas du bureau win32k

auteur : @55-AA, 18 septembre 2016

##Introduction

Le tas du bureau (Desktop Heap) est un pool noyau utilisé par win32k ; il peut être exploité par une application en mode utilisateur. Je vais décrire en détail comment implémenter une exploitation fiable afin de lire/écrire une adresse arbitraire dans le noyau. Cet article et l'analyse associée ont été réalisés sur une installation win7_sp1_x86 (build 17842).

Vulnérabilité

Le 9 août 2016, Microsoft a publié MS16-098. Le code vulnérable se trouve dans la fonction win32k!xxxInsertMenuItem, dont le prototype est :

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

Commençons par examiner le pseudo-code du bug dans 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 {

Dans le code ci-dessus, lorsque le 9e (à partir du 1er) élément a été ajouté au pMenu, DesktopAlloc() a été appelé pour réallouer un nouveau pMenu->rgItems. Ensuite, MNLookUpItem() a été appelé pour obtenir l'emplacement de l'élément dans pMenu->rgItems. Mais le pItem retourné par MNLookUpItem() est un rgItems d'un autre pSubMenu, et non du pMenu. Ainsi, lorsque RtlMoveMemory() est appelé, le pItem du pSubMenu et les octets suivants sont écrasés en raison de la taille de déplacement erronée.

Voici le code de désassemblage du bug, qui déclenche un écrasement du tas ; il peut être exploité pour construire un faux bloc :

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)

Pour suivre le bug, j'utilise ces points d'arrêt dans 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

Pour déclencher le bug, les étapes suivantes doivent être effectuées :

  1. Créer un menu.
  2. Créer un sous-menu comme premier ITEM du menu avec l'ID 0x123 ; il est nécessaire de définir MENUITEMINFO.hbmpItem avec HBMMENU_SYSTEM.
  3. Ajouter 7 autres ITEMs avec des ID de 0x1001 à 0x1007 dans le menu.
  4. Ajouter un ITEM avec l'ID 1 au sous-menu.
  5. Ajouter 8 autres ITEMs au sous-menu, afin d'obtenir un tagMENU.rgItems avec 16 emplacements. Mais cette étape n'est pas nécessaire pour déclencher le bug si vous ne voulez qu'un crash.
  6. Ajouter le 9e ITEM avec l'ID 0x123 au menu ; ainsi, le RtlMoveMemory() attendu est appelé avec des paramètres erronés.

Tas du bureau

Le tas du bureau est un pool global utilisé par tous les processus GUI. Tous les objets GUI, comme les fenêtres et les menus, sont stockés dans le tas du bureau et gérés par l'allocateur de tas du noyau. L'allocateur de tas du noyau utilise des fonctions familières telles que RtlAllocateHeap et RtlFreeHeap. Contrairement au tas en mode utilisateur, le tas du bureau n'utilise aucun allocateur frontal : pas de Low Fragmentation Heap, pas de liste Lookaside, etc. Il n'y a pas non plus de Heap Encoding avant Windows 8 et ultérieur. Voici la structure d'un bloc sur win7_sp1_x86 :

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

Les champs Size et PreviousSize représentent la taille des blocs, décalée vers la droite de HEAP_GRANULARITY_SHIFT (défini comme 3 sur les systèmes 32 bits). Le champ Size spécifie le bloc courant, et PreviousSize spécifie le bloc précédent. Le bit de poids faible de Flags est généralement défini à HEAP_ENTRY_BUSY (0x01), indiquant que le bloc est en cours d'utilisation ; sinon, il est à 0x00.

La figure suivante illustre la relation entre ces champs et les blocs. Le deuxième WORD souligné en vert (0x000f) indique que la taille du bloc courant est de 0x78 octets, le deuxième WORD souligné en noir (0x0003) indique que la taille du bloc précédent est de 0x18 octets, et les WORDs soulignés en rouge (0x0001) indiquent que les blocs courants sont en cours d'utilisation. Ici, la taille du bloc inclut la taille de l'en-tête, dont la structure HEAP_ENTRY est définie ci-dessus.

C'est la caractéristique la plus importante pour la corruption du tas : l'allocateur de tas récupère toujours le bloc libéré le plus récemment. Cela signifie que nous pouvons en réalité allouer un bloc de n'importe quelle taille et à un emplacement précis de notre choix.

Corruption

En exploitant le bug, je peux écraser certains octets dans le tas du bureau. J'obtiens ainsi un faux bloc qui remplace un bloc normal ; puis je libère le bloc remplacé, de sorte que le faux bloc est poussé en tête de la liste des blocs libres. Ensuite, le faux bloc est réutilisé et je peux y écrire n'importe quels octets. La région inscriptible chevauche plusieurs blocs normaux, mais elle ne peut pas couvrir tout l'espace noyau. Je dois donc construire une autre primitive de lecture/écriture dans la région chevauchée, en tirant parti de tagWND.strName pour écrire à une adresse arbitraire. Le pointeur de strName.Buffer peut nous mener n'importe où, aussi bien dans l'espace noyau que dans l'espace utilisateur. Bien entendu, notre cible est uniquement nt!HalDispatchTable.

La figure suivante montre le déroulement des modifications du tas :

Comme le montrent les démonstrations, je corromps le tas du bureau étape par étape et mets en œuvre l'exploitation selon les étapes suivantes :

Télécharger l’outil