Skip to content
KitploitKITPLOIT
FerramentasBlog
Log in
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2016-3308 — Use a CVE-2016-3308 para corromper o desktop heap do win32k | Kitploit
Ferramentas/GitHubGitHub/jackhuyh/cve-2016-3308
Forensia de MemóriaAnálise de VulnerabilidadesExploraçãoExploração de Binários
GitHubjackhuyh/cve-2016-3308

CVE-2016-3308

Use a CVE-2016-3308 para corromper o desktop heap do win32k

Ver Repositório
12111há 10 anosAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Use a CVE-2016-3308 para corromper o desktop heap do win32k

autor : @55-AA, 18 de setembro de 2016

##Introdução

O desktop heap é um pool do kernel usado pelo win32k, que pode ser explorado por aplicações em modo de usuário. Aqui descreverei em detalhes como implementar uma exploração confiável para ler/escrever endereços arbitrários no kernel. Este writeup e a análise associada foram feitos em uma instalação do win7_sp1_x86(build 17842).

##Vulnerabilidade

Em 9 de agosto de 2016, a Microsoft lançou o MS16-098. O código da vulnerabilidade existe na função win32k!xxxInsertMenuItem, cujo protótipo é:

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

Primeiro, vejamos o pseudocódigo do bug em 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 {

No código acima, quando o 9º (a partir do 1º) item foi adicionado ao pMenu, DesktopAlloc() foi chamado para realocar um novo pMenu->rgItems. Em seguida, MNLookUpItem() foi chamado para obter a localização do item em pMenu->rgItems. Mas o pItem retornado por MNLookUpItem() é um rgItems de outro pSubMenu, em vez do pMenu; então, quando RtlMoveMemory() foi chamado, o pItem do pSubMenu e os bytes seguintes seriam sobrescritos devido ao tamanho incorreto da movimentação.

A seguir está o código de desmontagem sobre o bug, que acionaria uma sobrescrita no heap e pode ser usado para construir um chunk falso:

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)

Para rastrear o bug, uso estes breakpoints no 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

Para acionar o bug, as seguintes etapas precisam ser executadas:

  1. Criar um menu.
  2. Criar um submenu como o primeiro ITEM do menu com ID 0x123; é necessário definir MENUITEMINFO.hbmpItem com HBMMENU_SYSTEM.
  3. Adicionar outros 7 ITEMs com ID de 0x1001 a 0x1007 ao menu.
  4. Adicionar um ITEM com ID 1 ao submenu.
  5. Adicionar outros 8 ITEMs ao submenu, para obter um tagMENU.rgItems com 16 slots. Mas esta etapa não é necessária para acionar, se você precisar apenas de um crash.
  6. Adicionar o 9º ITEM com ID 0x123 ao menu; assim, a chamada esperada a RtlMoveMemory() foi executada com parâmetros incorretos.

Desktop Heap

O desktop heap é um pool global usado por todos os processos de GUI. Todos os objetos de GUI, como Window, Menu, são armazenados no desktop heap e gerenciados pelo alocador de heap do kernel. O alocador de heap do kernel usa funções conhecidas, como RtlAllocateHeap e RtlFreeHeap. Diferentemente do heap em modo de usuário, o desktop heap não utiliza alocadores de front-end, portanto não há Low Fragmentation Heap, nem lista Lookaside etc. Além disso, não há Heap Encoding até o Windows 8 e versões posteriores. A seguir está a estrutura do chunk no win7_sp1_x86:

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

Os campos Size e PreviousSize representam o tamanho dos chunks deslocado à direita em HEAP_GRANULARITY_SHIFT (definido como 3 em sistemas de 32 bits) bits; o campo Size especifica o chunk atual, e PreviousSize especifica o anterior. O bit menos significativo de Flags geralmente é definido como HEAP_ENTRY_BUSY (0x01), representando que o chunk está em uso; caso contrário, é 0x00.

A figura a seguir demonstra a relação entre esses campos e esses blocos de chunk. O segundo WORD sublinhado em verde (0x000f) representa que o tamanho do chunk atual é 0x78 bytes; o segundo WORD sublinhado em preto (0x0003) representa que o tamanho do chunk anterior é 0x18 bytes; e os WORDs sublinhados em vermelho (0x0001) representam que os chunks atuais estão em uso. Aqui, o tamanho do chunk inclui o tamanho do cabeçalho; o cabeçalho é definido pela estrutura HEAP_ENTRY acima.

Essa é a característica mais importante para a corrupção de heap: o alocador de heap sempre obtém o chunk liberado mais recentemente. Isso significa que podemos, na prática, alocar um chunk de qualquer tamanho e em uma localização específica que desejarmos.

Corrupção

Usando o bug, posso sobrescrever alguns bytes no desktop heap, obtendo assim um chunk falso que substitui um chunk normal. Então eu libero o chunk substituído, fazendo com que o chunk falso seja empurrado para o topo da lista de chunks livres. Posteriormente, o chunk falso é reutilizado e posso escrever quaisquer bytes nele; a região gravável se sobrepõe a vários chunks normais, mas não cobre todo o espaço do kernel. Portanto, preciso construir outra primitiva de leitura/escrita na região sobreposta, que aproveite o tagWND.strName para escrever em endereços arbitrários. O ponteiro de strName.Buffer pode nos levar a qualquer lugar, incluindo o espaço do kernel e o espaço do usuário. Naturalmente, nosso alvo é apenas o nt!HalDispatchTable.

A figura a seguir mostra o procedimento de alteração do heap:

De acordo com as demonstrações, corrompo o desktop heap passo a passo e implemento a exploração por meio das seguintes etapas:

Baixar ferramenta