GrossmanOri/vulnerable-http-server
GitHub: GrossmanOri/vulnerable-http-server
一个用于安全工程教学的故意存有漏洞的 ARM64 HTTP 服务器,演示变量溢出、栈溢出、返回地址劫持和时序侧信道四类经典漏洞的利用与防御。
Stars: 0 | Forks: 0
# 存在漏洞的 HTTP 服务器 — 安全漏洞利用演示
这是一个故意留有漏洞的 HTTP 服务器,使用 C 语言编写,旨在针对 Apple Silicon (ARM64) 上的真实运行进程演示四类经典安全漏洞。
本项目是 Shenkar 学院安全工程课程的一部分。每次漏洞利用都针对真实的二进制文件 —— 没有 CTF 脚手架,也没有人为包装的测试环境。
## 演示的漏洞
### 1. 变量溢出 — `check_auth`
结构体在内存中将 `char password_buffer[16]` 紧挨在 `volatile int is_authenticated` 之前。拷贝循环的上限是 `sizeof(struct)` (20) 而不是缓冲区大小 (16),因此写入 17 个字节就会在完全不需要知道密码的情况下覆盖身份验证标志。
### 2. 栈缓冲区溢出 — `do_login` / `write_creds`
`write_creds` 会执行无边界拷贝,将数据写入一个 16 字节的栈缓冲区。在跳过占位数据后发送 48 个字节,就会覆盖栈上保存的返回地址(在 ARM64 上为 `x30`)。
### 3. 返回地址劫持 → 后门数据库转储
利用漏洞 #2 的溢出将 `x30` 重定向到 `dump_user_database`,这是一个在正常执行流程中从未被调用的函数。它会读取 `passwords.txt` 并将全部内容发送到客户端 socket,然后调用 `exit(0)` 以避免由于栈帧被破坏而导致崩溃。
### 4. 时序侧信道 — `slow_strcmp`
密码比较操作在每匹配到一个字符时,会在继续执行之前调用 `usleep(2000)`。这会导致每个正确字符产生约 2ms 的可测量 RTT 增加。该攻击通过对每个候选字符测量 30 次样本的中位响应延迟,从而一次恢复一个字符的密码。
## 技术细节
**目标:** ARM64 Apple Silicon (macOS),使用 Clang 编译
**栈帧验证方式:** `otool -tV` 反汇编 + LLDB `disassemble --name do_login`
### `do_login` 栈帧布局(由反汇编确认)
```
sub sp, sp, #0x40 ; 64-byte frame
stp x29, x30, [sp, #0x30] ; saved x29 at sp+48, x30 at sp+56
add x0, sp, #0x10 ; password_buf at sp+16
sp+16 .. sp+31 password_buf[16] ← overflow starts here
sp+32 .. sp+55 padding, stored args, x29
sp+56 .. sp+63 saved x30 (return addr) ← hijack target
```
从 `password_buf` 到保存的 `x30` 的距离:**40 字节**
Payload:`fill(16) + bridge(24) + addr(8)` = 在跳过占位数据后为 48 字节
### 为什么禁用保护机制
| 标志 | 移除的保护 | 效果 |
|---|---|---|
| `-fno-stack-protector` | Stack canary | Canary 会在 `ret` 之前捕获溢出 |
| `-mbranch-protection=none` | ARM64 PAC | PAC 会在 `ret` 之前验证 `x30`;被劫持的地址将触发异常 |
| `-O0` | 编译器优化 | 保持栈布局确定 |
## 构建
```
make clean && make
```
要求:`gcc`、`make`、macOS 以及 Xcode Command Line Tools。
## 运行攻击
### 攻击 1 — 变量溢出(绕过身份验证)
```
./server &
python3 attack1.py
# 预期: [+] ACCESS GRANTED
```
### 攻击 2+3 — 返回地址劫持 + 数据库转储
```
# Terminal 1
lldb ./server
(lldb) settings set target.disable-aslr true
(lldb) run
(lldb) image lookup -n dump_user_database # note the address
(lldb) continue
# Terminal 2
python3 attack2.py
# 预期: [+] ACCESS GRANTED 然后 === BACKDOOR: PASSWORD DATABASE DUMP ===
```
### 攻击 4 — 时序侧信道
```
./server &
python3 timing_attack.py
# 逐字符恢复 'secret123'(约 5 分钟)
```
## 时序攻击的工作原理
`slow_strcmp` 每匹配到一个字符就会休眠 2ms。对每个候选字符测量 30 次样本的中位 RTT,会在每个位置的正确字符上产生约 2ms 的稳定差距:
```
Position 0: 's' 2.95 ms gap: +1.96 ms
Position 1: 'e' 5.47 ms gap: +2.11 ms
Position 2: 'c' 7.79 ms gap: +1.90 ms
Position 3: 'r' 10.11 ms gap: +2.22 ms
Position 4: 'e' 13.31 ms gap: +2.41 ms
Position 5: 't' 14.74 ms gap: +2.15 ms
Position 6: '1' 16.97 ms gap: +2.08 ms
Position 7: '2' 19.96 ms gap: +2.11 ms
→ [+] PASSWORD FOUND: 'secret123'
```
脚本使用 `statistics.median()` 对 30 次样本进行处理,并设置 1.2ms 的最小差距阈值,以过滤 OS 抖动并防止单个错误字符引发连锁反应导致失败。
## 缓解措施(在生产环境中阻止这些攻击的方法)
| 攻击 | 缓解措施 |
|---|---|
| 变量溢出 | 将拷贝循环限制在缓冲区大小内,而不是 `sizeof(struct)` |
| 栈缓冲区溢出 | 使用有边界的拷贝函数(`strncpy`、带有大小检查的 `memcpy`) |
| 返回地址劫持 | Stack canary (`-fstack-protector`) + ARM64 PAC (`-mbranch-protection=standard`) |
| 时序侧信道 | 恒定时间比较(对固定长度缓冲区使用 `memcmp`,或使用 `CRYPTO_memcmp`) |
## 项目结构
```
├── main.c entry point
├── httpd.c fork-based server loop, HTTP dispatch
├── http_protocol.c HTTP parser
├── router.c route handlers + all four vulnerabilities
├── httpd.h shared types and macros
├── Makefile
├── passwords.txt sample credential store
├── attack1.py Attack 1 — variable overflow
├── attack2.py Attack 2+3 — return address hijack
└── timing_attack.py Attack 4 — timing side-channel
```
标签:ARM64, HTTP服务器, XXE攻击, 客户端加密, 故意存在漏洞的系统, 时间侧信道攻击, 栈溢出, 漏洞利用演示, 返回地址劫持, 逆向工具