Translated ['src/binary-exploitation/libc-heap/heap-overflow.md', 'src/b

This commit is contained in:
Translator 2025-07-30 06:14:07 +00:00
parent f272b23488
commit c61c155d02
2 changed files with 73 additions and 12 deletions

View File

@ -6,7 +6,7 @@
Um heap overflow é como um [**stack overflow**](../stack-overflow/index.html), 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 isso pode ser possível de abusar. 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 poderia abusar disso.
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 poderia abusar disso.
> [!TIP]
> Para encontrar offsets de overflow, você pode usar os mesmos padrões que em [**stack overflows**](../stack-overflow/index.html#finding-stack-overflows-offsets).
@ -19,17 +19,17 @@ No entanto, no caso de um heap overflow, a memória usada não é linear, mas **
Uma das técnicas usadas para isso é **Heap Grooming**, que é usada, por exemplo, [**neste post**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). 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ários threads para tentar garantir que todos os chunks livres sejam preenchidos e que uma nova página seja criada**.
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.
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**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) é possível encontrar uma emulação básica de Heap overflow que mostra como sobrescrever o bit de uso anterior do próximo chunk e a posição do tamanho anterior é possível **consolidar um chunk usado** (fazendo-o pensar que está não utilizado) e **então alocá-lo novamente**, podendo sobrescrever dados que estão sendo usados em um ponteiro diferente também.
[**Nesta página**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) é 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 prev size é 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**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) 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 bandeira**.
Outro exemplo do [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) 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**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html), é 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.
@ -45,4 +45,36 @@ python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt
- 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 como `system` 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`:
```c
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:
```python
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:
1. **_FORTIFY_SOURCE não é uma solução mágica** o uso indevido pode anular a proteção.
2. Sempre passe o **tamanho correto do buffer** para a família `_chk` (ou, ainda melhor, use `snprintf`).
## Referências
* [watchTowr Labs Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -8,11 +8,11 @@ Um **stack overflow** é uma vulnerabilidade que ocorre quando um programa escre
O principal problema dessa sobrescrita é que o **ponteiro de instrução salvo (EIP/RIP)** e o **ponteiro base salvo (EBP/RBP)** para retornar à função anterior estão **armazenados na pilha**. Portanto, um atacante poderá sobrescrever esses valores e **controlar o fluxo de execução do programa**.
A vulnerabilidade geralmente surge porque uma função **copia na pilha mais bytes do que a quantidade alocada para ela**, conseguindo assim sobrescrever outras partes da pilha.
A vulnerabilidade geralmente surge porque uma função **copia dentro da pilha mais bytes do que a quantidade alocada para ela**, conseguindo assim sobrescrever outras partes da pilha.
Algumas funções comuns vulneráveis a isso são: **`strcpy`, `strcat`, `sprintf`, `gets`**... Além disso, funções como **`fgets`**, **`read` & `memcpy`** que aceitam um **argumento de comprimento**, podem ser usadas de maneira vulnerável se o comprimento especificado for maior do que o alocado.
Por exemplo, as seguintes funções podem ser vulneráveis:
Por exemplo, as seguintes funções poderiam ser vulneráveis:
```c
void vulnerable() {
char buffer[128];
@ -21,7 +21,7 @@ gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
```
### Encontrando os offsets de Stack Overflows
### Encontrando offsets de Stack Overflows
A maneira mais comum de encontrar stack overflows é fornecer uma entrada muito grande de `A`s (por exemplo, `python3 -c 'print("A"*1000)'`) e esperar um `Segmentation Fault` indicando que o **endereço `0x41414141` foi tentado acessar**.
@ -50,10 +50,10 @@ pattern search $rsp #Search the offset given the content of $rsp
```
## Explorando Estouro de Pilha
Durante um estouro (supondo que o tamanho do estouro seja grande o suficiente) você poderá **sobrescrever** valores de variáveis locais dentro da pilha até alcançar o **EBP/RBP e EIP/RIP salvos (ou até mais)**.\
Durante um estouro (supondo que o tamanho do estouro seja grande o suficiente), você poderá **sobrescrever** valores de variáveis locais dentro da pilha até alcançar o **EBP/RBP e EIP/RIP salvos (ou até mais)**.\
A maneira mais comum de abusar desse tipo de vulnerabilidade é **modificando o endereço de retorno** para que, quando a função terminar, o **fluxo de controle seja redirecionado para onde o usuário especificou** neste ponteiro.
No entanto, em outros cenários, apenas **sobrescrever alguns valores de variáveis na pilha** pode ser suficiente para a exploração (como em desafios CTF fáceis).
No entanto, em outros cenários, talvez apenas **sobrescrever alguns valores de variáveis na pilha** possa ser suficiente para a exploração (como em desafios CTF fáceis).
### Ret2win
@ -79,7 +79,7 @@ Esta técnica é a estrutura fundamental para contornar a principal proteção d
../rop-return-oriented-programing/
{{#endref}}
## Estouros de Heap
## Estouro de Heap
Um estouro não ocorrerá sempre na pilha, também pode ocorrer no **heap**, por exemplo:
@ -87,7 +87,7 @@ Um estouro não ocorrerá sempre na pilha, também pode ocorrer no **heap**, por
../libc-heap/heap-overflow.md
{{#endref}}
## Tipos de proteções
## Tipos de Proteções
Existem várias proteções tentando prevenir a exploração de vulnerabilidades, confira-as em:
@ -95,4 +95,33 @@ Existem várias proteções tentando prevenir a exploração de vulnerabilidades
../common-binary-protections-and-bypasses/
{{#endref}}
### Exemplo do Mundo Real: CVE-2025-40596 (SonicWall SMA100)
Uma boa demonstração de por que **`sscanf` nunca deve ser confiável para analisar entradas não confiáveis** apareceu em 2025 no dispositivo SSL-VPN SMA100 da SonicWall.
A rotina vulnerável dentro de `/usr/src/EasyAccess/bin/httpd` tenta extrair a versão e o endpoint de qualquer URI que comece com `/__api__/`:
```c
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
```
1. A primeira conversão (`%2s`) armazena com segurança **dois** bytes em `version` (por exemplo, `"v1"`).
2. A segunda conversão (`%s`) **não tem especificador de comprimento**, portanto `sscanf` continuará copiando **até o primeiro byte NUL**.
3. Como `endpoint` está localizado na **pilha** e tem **0x800 bytes de comprimento**, fornecer um caminho mais longo que 0x800 bytes corrompe tudo que está após o buffer incluindo o **stack canary** e o **endereço de retorno salvo**.
Uma prova de conceito em uma única linha é suficiente para acionar a falha **antes da autenticação**:
```python
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
```
Mesmo que canários de pilha abortem o processo, um atacante ainda ganha um **Denial-of-Service** primitivo (e, com vazamentos de informações adicionais, possivelmente execução de código). A lição é simples:
* Sempre forneça uma **largura máxima de campo** (por exemplo, `%511s`).
* Prefira alternativas mais seguras, como `snprintf`/`strncpy_s`.
## Referências
* [watchTowr Labs Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)
{{#include ../../banners/hacktricks-training.md}}