Libc Protections
Last updated
Last updated
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
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.
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 é 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.
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:
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.
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.
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.
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.
Para uma melhor explicação do processo verifique a postagem original aqui.
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:
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.
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.
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.
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
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.
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
.
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.
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.
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.
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.