Skip to content

Buffer Overflow

  • 아래 C 소스 코드를 컴파일한 바이너리에는 scanf 함수 사용으로 인한 버퍼 오버플로(BOF) 취약점이 존재한다.
  • 64비트 리눅스 환경에서 GDB 및 BOF 취약점을 이용하여 Welcome! 메시지가 화면에 출력되도록 하는 과정을 보이는 포스트를 작성하시오.
  • 올바른 패스워드를 입력하여 나오는 Welcome! 메시지는 인정하지 않는다.
  • 32비트 환경이나 바이너리도 인정하지 않는다.
#include <stdio.h>
#include <string.h>

void ShowWelcomeMessage (void)
{
    puts ("Welcome!");
}

int CheckPassword (void)
{
    char aBuffer [32];
    printf ("Password: ");
    scanf ("%s", aBuffer);
    return strcmp (aBuffer, "tltmxpaqhdkstlftmq");
}

int main (int argc, char * argv [])
{
    CheckPassword () ? puts ("Access Denied.") : ShowWelcomeMessage ();

    return 0;
}

GDB 초기화

  • 바이너리를 분석하기 위해 GDB 실행, 초기화
$ gdb
GNU gdb (GDB) 15.2
...
(gdb) tui enable

tui

  • hw 바이너리 로드
(gdb) file ./hw
Reading symbols from ./hw...
  • TUI 어셈블리 레이아웃 설정
(gdb) tui layout asm

layout_asm

잘 모르는 AT&T 어셈블리 형식으로 나온다..

정적 분석

  • 리눅스 환경이므로 x86-64 System V ABI 사용
    • 순서: rdi, rsi, rdx, rcx, r8, r9
  • Gnu Assembly (AT&T) Syntax 사용
    • mov $32, %rbx; (AT&T) == mov rbx, 32; (Intel)
    • 오퍼랜드 순서 반대, 상수/레지스터 표현 차이

CheckPassword 분석

checkPassword

  • scanf 함수 사용
    • 버퍼 오버플로우 발생 가능
  • scanf([rdi], [rsi]);
    • rdi == $rip (CheckPassword+42) + 0xe6f
    • rsi == rsp ~ rbp (rbp-0x20 == rsp) == 32바이트

동적 분석

  • hw 바이너리 실행, 일시정지
(gdb) start
...
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe9e8) at hw.c:19

주소 분석

  • main: 0x1000011ce
  • CheckPassword: 0x10000117f
  • ShowWelcomeMessage: 0x100001169

  • CheckPassword 함수 내부 scanf의 첫번째 매개변수 확인

(gdb) x/s CheckPassword+42+0xe6f
0x100002018:    "%s"

scanf_rdi

scanf 실행 전 스택 확인

(gdb) s
CheckPassword () at hw.c:12
(gdb) n
(gdb) ni 5

x_16a x_16x

  • 0x7fffffffe8a0 위치에 복귀 주소 저장

BOF

  • 오버플로우 발생을 위해 40개의 임의 4바이트 문자와 0x69와 0x11에 해당하는 문자 입력
  • 0x69 == 알파벳 'i'
  • 0x11 == DC1 (Device Control 1).
    • 키보드를 사용하여 입력 불가
    • 붙여넣기 실패 (ssh로는 불가능한 것으로 예상)

0x11 입력

  • 0x11을 포함한 암호 문자열을 입력하기 위해, redirection을 사용

  • Hex Editor을 사용하여 0x11이 포함된 암호 문자열 입력 후 저장 hex_editor

  • gdb에서 input redirection으로 바이너리 실행
(gdb) run < bofpasswd.txt
Starting program: /home/cmanixli/BOF/hw < bofpasswd.txt
...
Password: Welcome!

Program received signal SIGSEGV, Segmentation fault.

complete

  • 직접 enter키를 입력하지 않아 "Welcome!"이 줄바꿈 없이 출력됨

결론

  • scanf 함수는 입력 길이를 검사하지 않아 버퍼 오버플로우가 발생할 수 있음
  • scanf 대신 scanf_s를 사용
    • MSVC에서만 지원하는 것으로 알고 있었지만, C언어 표준 문서에 등재되어 있었음
  • 키보드로 입력할 수 없는 문자도 redirection을 통해 입력 가능
    • 사실 그냥 echo -e "\x69\x11" 하면 됨