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攻击, 客户端加密, 故意存在漏洞的系统, 时间侧信道攻击, 栈溢出, 漏洞利用演示, 返回地址劫持, 逆向工具