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
- hw 바이너리 로드
(gdb) file ./hw
Reading symbols from ./hw...
- TUI 어셈블리 레이아웃 설정
(gdb) tui 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 분석
- 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 실행 전 스택 확인
(gdb) s
CheckPassword () at hw.c:12
(gdb) n
(gdb) ni 5
- 0x7fffffffe8a0 위치에 복귀 주소 저장
BOF
- 오버플로우 발생을 위해 40개의 임의 4바이트 문자와 0x69와 0x11에 해당하는 문자 입력
- 0x69 == 알파벳 'i'
- 0x11 == DC1 (Device Control 1).
- 키보드를 사용하여 입력 불가
- 붙여넣기 실패 (ssh로는 불가능한 것으로 예상)
0x11 입력
-
0x11을 포함한 암호 문자열을 입력하기 위해, redirection을 사용
-
Hex Editor을 사용하여 0x11이 포함된 암호 문자열 입력 후 저장
- gdb에서 input redirection으로 바이너리 실행
(gdb) run < bofpasswd.txt
Starting program: /home/cmanixli/BOF/hw < bofpasswd.txt
...
Password: Welcome!
Program received signal SIGSEGV, Segmentation fault.
- 직접 enter키를 입력하지 않아 "Welcome!"이 줄바꿈 없이 출력됨
결론
- scanf 함수는 입력 길이를 검사하지 않아 버퍼 오버플로우가 발생할 수 있음
- scanf 대신 scanf_s를 사용
- MSVC에서만 지원하는 것으로 알고 있었지만, C언어 표준 문서에 등재되어 있었음
- 키보드로 입력할 수 없는 문자도 redirection을 통해 입력 가능
사실 그냥 echo -e "\x69\x11" 하면 됨