Stack Overflow
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.
O que é um Stack Overflow
Um stack overflow é uma vulnerabilidade que ocorre quando um programa escreve mais dados na pilha do que foi alocado para armazená-los. Esses dados em excesso sobrescreverão o espaço de memória adjacente, levando à corrupção de dados válidos, interrupção do fluxo de controle e potencialmente à execução de código malicioso. Esse problema geralmente surge devido ao uso de funções inseguras que não realizam verificação de limites na entrada.
O principal problema dessa sobrescrita é que o ponteiro de instrução salvo (EIP/RIP) e o ponteiro de 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.
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 poderiam ser vulneráveis:
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
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.
Além disso, uma vez que você encontrou que há uma vulnerabilidade de Stack Overflow, você precisará encontrar o offset até que seja possível sobrescrever o endereço de retorno, para isso geralmente é usada uma sequência de De Bruijn. Que para um alfabeto dado de tamanho k e subsequências de comprimento n é uma sequência cíclica na qual cada possível subsequência de comprimento n aparece exatamente uma vez como uma subsequência contígua.
Dessa forma, em vez de precisar descobrir manualmente qual offset é necessário para controlar o EIP, é possível usar como preenchimento uma dessas sequências e, em seguida, encontrar o offset dos bytes que acabaram sobrescrevendo-o.
É possível usar pwntools para isso:
from pwn import *
# Generate a De Bruijn sequence of length 1000 with an alphabet size of 256 (byte values)
pattern = cyclic(1000)
# This is an example value that you'd have found in the EIP/IP register upon crash
eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value) # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")
ou GEF:
#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
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).
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).
Ret2win
Neste tipo de desafios CTF, há uma função dentro do binário que nunca é chamada e que você precisa chamar para vencer. Para esses desafios, você só precisa encontrar o offset para sobrescrever o endereço de retorno e encontrar o endereço da função a ser chamada (geralmente ASLR estaria desativado) para que, quando a função vulnerável retornar, a função oculta seja chamada:
{{#ref}} ret2win/ {{#endref}}
Shellcode na Pilha
Neste cenário, o atacante poderia colocar um shellcode na pilha e abusar do EIP/RIP controlado para pular para o shellcode e executar código arbitrário:
{{#ref}} stack-shellcode/ {{#endref}}
Técnicas ROP & Ret2...
Esta técnica é a estrutura fundamental para contornar a principal proteção da técnica anterior: Pilha não executável (NX). E permite realizar várias outras técnicas (ret2lib, ret2syscall...) que acabarão executando comandos arbitrários ao abusar de instruções existentes no binário:
{{#ref}} ../rop-return-oriented-programing/ {{#endref}}
Estouro de Heap
Um estouro não ocorrerá sempre na pilha, também pode ocorrer no heap, por exemplo:
{{#ref}} ../libc-heap/heap-overflow.md {{#endref}}
Tipos de Proteções
Existem várias proteções tentando prevenir a exploração de vulnerabilidades, confira-as em:
{{#ref}} ../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__/
:
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
- A primeira conversão (
%2s
) armazena com segurança dois bytes emversion
(por exemplo,"v1"
). - A segunda conversão (
%s
) não tem especificador de comprimento, portantosscanf
continuará copiando até o primeiro byte NUL. - 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:
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
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.