Heap Overflow
Reading time: 7 minutes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Informações Básicas
Um heap overflow é como um stack overflow, mas no heap. Basicamente, isso significa que algum espaço foi reservado no heap para armazenar alguns dados e os dados armazenados eram maiores do que o espaço reservado.
Em stack overflows, sabemos que alguns registradores, como o ponteiro de instrução ou o quadro de pilha, serão restaurados da pilha e pode ser possível abusar disso. No caso de heap overflows, não há nenhuma informação sensível armazenada por padrão no chunk do heap que pode ser transbordado. No entanto, pode haver informações sensíveis ou ponteiros, então a criticidade dessa vulnerabilidade depende de quais dados podem ser sobrescritos e como um atacante pode abusar disso.
tip
Para encontrar offsets de overflow, você pode usar os mesmos padrões que em stack overflows.
Stack Overflows vs Heap Overflows
Em stack overflows, a disposição e os dados que estarão presentes na pilha no momento em que a vulnerabilidade pode ser acionada são bastante confiáveis. Isso ocorre porque a pilha é linear, sempre aumentando em memória colidida, em lugares específicos da execução do programa, a memória da pilha geralmente armazena um tipo semelhante de dados e tem uma estrutura específica com alguns ponteiros no final da parte da pilha usada por cada função.
No entanto, no caso de um heap overflow, a memória usada não é linear, mas chunks alocados geralmente estão em posições separadas da memória (não um ao lado do outro) devido a bins e zonas que separam alocações por tamanho e porque memória previamente liberada é usada antes de alocar novos chunks. É complicado saber qual objeto estará colidindo com aquele vulnerável a um heap overflow. Portanto, quando um heap overflow é encontrado, é necessário encontrar uma maneira confiável de fazer o objeto desejado estar próximo na memória do que pode ser transbordado.
Uma das técnicas usadas para isso é Heap Grooming, que é usada, por exemplo, neste post. No post, é explicado como, quando no kernel do iOS, uma zona fica sem memória para armazenar chunks de memória, ela a expande por uma página do kernel, e essa página é dividida em chunks dos tamanhos esperados que seriam usados em ordem (até a versão 9.2 do iOS, depois esses chunks são usados de maneira aleatória para dificultar a exploração desses ataques).
Portanto, no post anterior onde um heap overflow está acontecendo, para forçar o objeto transbordado a colidir com uma ordem de vítima, vários kallocs
são forçados por várias threads para tentar garantir que todos os chunks livres sejam preenchidos e que uma nova página seja criada.
Para forçar esse preenchimento com objetos de um tamanho específico, a alocação fora da linha associada a um mach port do iOS é um candidato ideal. Ao elaborar o tamanho da mensagem, é possível especificar exatamente o tamanho da alocação kalloc
e, quando o mach port correspondente é destruído, a alocação correspondente será imediatamente liberada de volta para kfree
.
Então, alguns desses espaços reservados podem ser liberados. A lista livre kalloc.4096
libera elementos em uma ordem de último a primeiro, o que basicamente significa que, se alguns espaços reservados forem liberados e a exploração tentar alocar vários objetos de vítima enquanto tenta alocar o objeto vulnerável ao overflow, é provável que esse objeto seja seguido por um objeto de vítima.
Exemplo libc
Nesta página é possível encontrar uma emulação básica de Heap overflow que mostra como sobrescrever o bit prev in use do próximo chunk e a posição do tamanho prev é possível consolidar um chunk usado (fazendo-o pensar que está não utilizado) e então alocá-lo novamente, sendo capaz de sobrescrever dados que estão sendo usados em um ponteiro diferente também.
Outro exemplo do protostar heap 0 mostra um exemplo muito básico de um CTF onde um heap overflow pode ser abusado para chamar a função vencedora para obter a flag.
No exemplo do protostar heap 1, é possível ver como abusar de um buffer overflow é possível sobrescrever em um chunk próximo um endereço onde dados arbitrários do usuário serão escritos.
Exemplo ARM64
Na página https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/ você pode encontrar um exemplo de heap overflow onde um comando que será executado é armazenado no chunk seguinte do chunk transbordado. Assim, é possível modificar o comando executado sobrescrevendo-o com uma exploração fácil, como:
python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt
Outros exemplos
- Auth-or-out. Hack The Box
- Usamos uma vulnerabilidade de Integer Overflow para obter um Heap Overflow.
- Corrompemos ponteiros para uma função dentro de um
struct
do chunk transbordado para definir uma função comosystem
e obter execução de código.
Exemplo do Mundo Real: CVE-2025-40597 – Uso indevido de __sprintf_chk
No firmware 10.2.1.15 do SonicWall SMA100, o módulo de reverse-proxy mod_httprp.so
aloca um chunk de heap de 0x80 bytes e então concatena várias strings nele com __sprintf_chk
:
char *buf = calloc(0x80, 1);
/* … */
__sprintf_chk(buf, /* destination (0x80-byte chunk) */
-1, /* <-- size argument !!! */
0, /* flags */
"%s%s%s%s", /* format */
"/", "https://", path, host);
__sprintf_chk
é parte de _FORTIFY_SOURCE. Quando recebe um parâmetro size
positivo, verifica se a string resultante cabe dentro do buffer de destino. Ao passar -1
(0xFFFFFFFFFFFFFFFF), os desenvolvedores efetivamente desativaram a verificação de limites, transformando a chamada reforçada de volta em um sprintf
clássico e inseguro.
Fornecer um cabeçalho Host:
excessivamente longo, portanto, permite que um atacante transborde o chunk de 0x80 bytes e sobrescreva os metadados do chunk de heap seguinte (tcache / fast-bin / small-bin dependendo do alocador). Um crash pode ser reproduzido com:
import requests, warnings
warnings.filterwarnings('ignore')
requests.get(
'https://TARGET/__api__/',
headers={'Host': 'A'*750},
verify=False
)
A exploração prática exigiria heap grooming para colocar um objeto controlável logo após o bloco vulnerável, mas a causa raiz destaca dois pontos importantes:
- _FORTIFY_SOURCE não é uma solução mágica – o uso indevido pode anular a proteção.
- Sempre passe o tamanho correto do buffer para a família
_chk
(ou, ainda melhor, usesnprintf
).
Referências
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.