Libc Protections

Apoie o HackTricks

Aplicação de Alinhamento de Chunks

Malloc aloca memória em grupos de 8 bytes (32 bits) ou 16 bytes (64 bits). Isso significa que o final dos chunks em sistemas de 32 bits deve se alinhar com 0x8, e em sistemas de 64 bits com 0x0. A funcionalidade de segurança verifica se cada chunk se alinha corretamente nessas localizações específicas antes de usar um ponteiro de um bin.

Benefícios de Segurança

A aplicação do alinhamento de chunks em sistemas de 64 bits melhora significativamente a segurança do Malloc ao limitar a colocação de chunks falsos para apenas 1 a cada 16 endereços. Isso complica os esforços de exploração, especialmente em cenários onde o usuário tem controle limitado sobre os valores de entrada, tornando os ataques mais complexos e difíceis de executar com sucesso.

  • Ataque Fastbin no __malloc_hook

As novas regras de alinhamento no Malloc também impedem um ataque clássico envolvendo o __malloc_hook. Anteriormente, os atacantes podiam manipular tamanhos de chunk para sobrescrever este ponteiro de função e obter execução de código. Agora, o requisito estrito de alinhamento garante que tais manipulações não sejam mais viáveis, fechando uma rota comum de exploração e melhorando a segurança geral.

Ofuscação de Ponteiros em fastbins e tcache

Ofuscação de Ponteiros é um aprimoramento de segurança usado para proteger ponteiros Fd de fastbin e tcache em operações de gerenciamento de memória. Essa técnica ajuda a prevenir certos tipos de táticas de exploração de memória, especificamente aquelas que não requerem informações de memória vazadas ou que manipulam diretamente locais de memória relativos a posições conhecidas (sobrescritas relativas).

O cerne dessa técnica é uma fórmula de ofuscação:

Novo_Ptr = (L >> 12) XOR P

  • L é a Localização de Armazenamento do ponteiro.

  • P é o Ponteiro Fd de fastbin/tcache real.

A razão para o deslocamento de bits da localização de armazenamento (L) por 12 bits para a direita antes da operação XOR é crítica. Essa manipulação aborda uma vulnerabilidade inerente à natureza determinística dos 12 bits menos significativos dos endereços de memória, que são tipicamente previsíveis devido às restrições da arquitetura do sistema. Ao deslocar os bits, a parte previsível é removida da equação, aumentando a aleatoriedade do novo ponteiro ofuscado e, assim, protegendo contra explorações que dependem da previsibilidade desses bits.

Este ponteiro ofuscado aproveita a aleatoriedade existente fornecida pela Randomização do Layout do Espaço de Endereços (ASLR), que randomiza os endereços usados pelos programas para dificultar que os atacantes prevejam o layout de memória de um processo.

Desofuscar o ponteiro para recuperar o endereço original envolve o uso da mesma operação XOR. Aqui, o ponteiro ofuscado é tratado como P na fórmula e, quando XORado com a localização de armazenamento inalterada (L), revela o ponteiro original. Essa simetria na ofuscação e desofuscação garante que o sistema possa codificar e decodificar eficientemente ponteiros sem sobrecarga significativa, ao mesmo tempo em que aumenta substancialmente a segurança contra ataques que manipulam ponteiros de memória.

Benefícios de Segurança

A ofuscação de ponteiros visa prevenir sobrescritas parciais e completas de ponteiros em heap, um aprimoramento significativo em segurança. Essa funcionalidade impacta as técnicas de exploração de várias maneiras:

  1. Prevenção de Sobrescritas Relativas de Bye Byte: Anteriormente, os atacantes podiam alterar parte de um ponteiro para redirecionar chunks de heap para diferentes locais sem conhecer endereços exatos, uma técnica evidente no exploit House of Roman sem vazamento. Com a ofuscação de ponteiros, tais sobrescritas relativas sem um vazamento de heap agora exigem força bruta, reduzindo drasticamente a probabilidade de sucesso.

  2. Aumento da Dificuldade de Ataques a Tcache Bin/Fastbin: Ataques comuns que sobrescrevem ponteiros de função (como __malloc_hook) manipulando entradas de fastbin ou tcache são prejudicados. Por exemplo, um ataque pode envolver vazar um endereço LibC, liberar um chunk no tcache bin e, em seguida, sobrescrever o ponteiro Fd para redirecioná-lo para __malloc_hook para execução de código arbitrário. Com a ofuscação de ponteiros, esses ponteiros devem ser corretamente ofuscados, exigindo um vazamento de heap para manipulação precisa, elevando assim a barreira de exploração.

  3. Necessidade de Vazamentos de Heap em Locais Não-Heap: Criar um chunk falso em áreas não-heap (como a pilha, seção .bss ou PLT/GOT) agora também requer um vazamento de heap devido à necessidade de ofuscação de ponteiros. Isso estende a complexidade de explorar essas áreas, semelhante à necessidade de manipular endereços LibC.

  4. Vazar Endereços de Heap se Torna Mais Desafiador: A ofuscação de ponteiros restringe a utilidade de ponteiros Fd em fastbin e tcache bins como fontes de vazamento de endereços de heap. No entanto, ponteiros em bins não ordenados, pequenos e grandes permanecem não ofuscados, ainda podendo ser usados para vazar endereços. Essa mudança leva os atacantes a explorar esses bins em busca de informações exploráveis, embora algumas técnicas ainda possam permitir desofuscar ponteiros antes de um vazamento, embora com restrições.

Desofuscar Ponteiros com um Vazamento de Heap

Para uma melhor explicação do processo verifique a postagem original aqui.

Visão Geral do Algoritmo

A fórmula usada para ofuscar e desofuscar ponteiros é:

Novo_Ptr = (L >> 12) XOR P

Onde L é a localização de armazenamento e P é o ponteiro Fd. Quando L é deslocado para a direita por 12 bits, ele expõe os bits mais significativos de P, devido à natureza do XOR, que produz 0 quando os bits são XORados consigo mesmos.

Passos Chave no Algoritmo:

  1. Vazamento Inicial dos Bits Mais Significativos: Ao XORar o L deslocado com P, você obtém efetivamente os 12 bits superiores de P porque a parte deslocada de L será zero, deixando os bits correspondentes de P inalterados.

  2. Recuperação dos Bits do Ponteiro: Como o XOR é reversível, conhecer o resultado e um dos operandos permite calcular o outro operando. Essa propriedade é usada para deduzir o conjunto completo de bits para P sucessivamente XORando conjuntos conhecidos de bits com partes do ponteiro ofuscado.

  3. Desofuscação Iterativa: O processo é repetido, cada vez usando os bits de P recém-descobertos da etapa anterior para decodificar o próximo segmento do ponteiro ofuscado, até que todos os bits sejam recuperados.

  4. Manuseio de Bits Determinísticos: Os últimos 12 bits de L são perdidos devido ao deslocamento, mas são determinísticos e podem ser reconstruídos pós-processo.

Você pode encontrar uma implementação desse algoritmo aqui: https://github.com/mdulin2/mangle

Proteção de Ponteiro

O ponteiro guard é uma técnica de mitigação de exploração usada no glibc para proteger ponteiros de função armazenados, especialmente aqueles registrados por chamadas de biblioteca como atexit(). Essa proteção envolve embaralhar os ponteiros através de XOR com um segredo armazenado nos dados da thread (fs:0x30) e aplicando uma rotação bitwise. Esse mecanismo tem como objetivo evitar que atacantes assumam o controle do fluxo de execução sobrescrevendo ponteiros de função.

Burlando o Ponteiro Guard com um vazamento

  1. Compreendendo as Operações do Ponteiro Guard: O embaralhamento (mangling) dos ponteiros é feito usando a macro PTR_MANGLE, que faz XOR do ponteiro com um segredo de 64 bits e então realiza uma rotação à esquerda de 0x11 bits. A operação reversa para recuperar o ponteiro original é tratada por PTR_DEMANGLE.

  2. Estratégia de Ataque: O ataque é baseado em uma abordagem de texto conhecido, onde o atacante precisa conhecer tanto a versão original quanto a versão embaralhada de um ponteiro para deduzir o segredo usado para o embaralhamento.

  3. Explorando Textos Conhecidos:

  • Identificando Ponteiros de Função Fixos: Ao examinar o código-fonte do glibc ou tabelas de ponteiros de função inicializados (como __libc_pthread_functions), um atacante pode encontrar ponteiros de função previsíveis.

  • Calculando o Segredo: Usando um ponteiro de função conhecido, como __pthread_attr_destroy, e sua versão embaralhada da tabela de ponteiros de função, o segredo pode ser calculado revertendo a rotação (rotação à direita) do ponteiro embaralhado e então fazendo XOR com o endereço da função.

  1. Textos Alternativos: O atacante também pode experimentar embaralhar ponteiros com valores conhecidos como 0 ou -1 para ver se produzem padrões identificáveis na memória, potencialmente revelando o segredo quando esses padrões são encontrados em despejos de memória.

  2. Aplicação Prática: Após calcular o segredo, um atacante pode manipular ponteiros de forma controlada, essencialmente burlando a proteção do Ponteiro Guard em um aplicativo multithread com conhecimento do endereço base do libc e capacidade de ler locais de memória arbitrários.

Referências

Last updated