드림핵 내용을 기반으로 내 방식으로 이해한 내용을 정리했다. (잘못된 내용이 있다면 댓글로 알려주세요..!)
스택 버퍼 오버플로우
- 스택의 버퍼에서 발생하는 오버플로우
버퍼
- 데이터가 목적지로 이동되기 전에 보관되는 임시 저장소
- 데이터가 저장될 수 있는 모든 단위를 뜻하기도 함
- 스택 버퍼
- 스택에 있는 지역변수
- 힙 버퍼
- 힙에 할당된 메모리 영역
- 스택 버퍼
버퍼가 필요한 이유
- 데이터의 처리속도 차이 때문
- 처리 속도가 다른 두 장치 사이의 데이터 전달 시 abcdefg를 전달했지만 받는 쪽에서는 abcd만 받을 수 있음 → 이를 방지하기 위해 수신 측과 송신 측 사이에 버퍼 둠
버퍼 오버플로우
- 버퍼가 넘치는 것
버퍼는 일정한 크기를 가지고 있다.
- int로 선언한 지역변수 = 4bytes
- char[10] = 10bytes
10바이트 크기의 버퍼에 20바이트를 넣으려 하면 오버플로우가 발생한다.
일반적으로 버퍼는 메모리상에 연속해서 할당되어 있으므로, 버퍼 오버플로우가 발생하면 뒤에 있는 버퍼들의 값이 조작될 수 있다.
이로 인해 일어나는 보안 위협에 대해 살펴보자.
보안 위협1 - 중요 데이터 변조
// Name: sbof_auth.c
// Compile: gcc -o sbof_auth sbof_auth.c -fno-stack-protector
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_auth(char *password)
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: ./sbof_auth ADMIN_PASSWORD\n");
exit(-1);
}
if (check_auth(argv[1])) //argv[1]을 check_auth의 인자로 전달
printf("Hello Admin!\n");
else
printf("Access Denied!\n");
}
int check_auth(char *password) {
int auth = 0; //스택에 auth 생성 (스택 [...,auth])
char temp[16]; //스택에 16바이트 크기의 temp 버퍼 생성 (스택 [..,temp,auth])
strncpy(temp, password, strlen(password));//argv[1]을 temp에 복사 **오버플로우 가능**
if(!strcmp(temp, "SECRET_PASSWORD"))
auth = 1;
return auth;
}
auth는 temp 버퍼 뒤에 존재하므로, temp 버퍼에 오버플로우를 발생시키면 auth값을 임의의 값으로 바꿀 수 있다. 따라서 인증 여부와 상관없이 main함수의 if(check_auth(argv[1]))
은 항상 참이 된다.
더 자세히 한줄한줄 보면 다음과 같다.
int auth를 실행하면 스택에 auth가 들어가게 된다. 이제 다음줄을 실행해보자.
temp는 auth앞에 존재하게 된다. 이때 argv[1]으로 16byte보다 큰 값이 전달되면 아래의 그림처럼 auth자리를 덮어쓰게 된다.
auth의 값이 0이 아닌 값으로 바뀌게 되면서 main함수의 if(check_auth(argv[1]))
은 항상 참이게 된다.
보안 위협2 - 데이터 유출
c언어에서 정상적인 문자열은 널바이트로 종결되 문자열 끝을 인식한다. 버퍼 오버플로우로 널바이트를 덮어쓰게 되면, 해당 버퍼를 출력시켜 다른 버퍼의 데이터를 읽을 수 있게된다. 다음의 예시 코드를 보고 이해해보자.
// Name: sbof_leak.c
// Compile: gcc -o sbof_leak sbof_leak.c -fno-stack-protector
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(void) {
char secret[16] = "secret message";
char barrier[4] = {}; //barrier 시작 위치부터 4byte를 0x00으로 세팅
char name[8] = {};
memset(barrier, 0, 4);
ㄴ
printf("Your name: ");
read(0, name, 12);
printf("Your name is %s.", name);
}
위에부터 한줄씩 실행하면서 스택의 변화를 그림으로 보면 다음과 같다. secret[16]을 선언하고 메시지를 넣었을 때 결과이다.
이후 차례로 변수선언과 초기화를 하면 다음과 같다.
이제 read()명령어로 사용자 입력을 읽어와 name에 넣는 과정을 보자. name은 8byte버퍼로 설정되어있다. 만약 5byte의 이름이 들어오게 된다면 e0mh4
까지만 출력되어 아무 문제가 없다.
만약 8byte가 넘는 10byte의 이름이 들어오게 된다면, barrier에 의해 e0mh4 good
까지 출력되고 문제가 없게 된다. 하지만 여기서도 barrier을 0x00(\0)이 아닌 다른 문자로 초기화했으면 문제가 일어났을 것이다.
12byte의 입력이 들어오게된다면 barrir에 의한 널문자가 없어지게되고, secret message까지 하나의 문자열로 인식된다. 따라서 e0mh4 tstorysecret message
가 출력된다. 이로 인해 memory leak(secret[16])이 일어나게 된다.
보안위협3 - 실행 흐름 조작
스택프레임에서의 반환주소(RET-return addr)를 조작해, 돌아갈 위치를 바꿔 실행의 흐름을 조작할 수 있다. 이를 보기 전에 함수의 스택프레임, 프롤로그, 에필로그에 대해 알고 있어야 한다.
[system] 함수 프롤로그 & 에필로그 (Prologue & Epilogue)
우선 함수의 프롤로그와 에필로그에 들어가기 전 스택프레임을 알아야한다. 스택프레임이란? 스택 세그먼트 내부의 단위를 스택 프레임(stack frame)이라고 한다. 이 스택프레임은 함수가 호출될
3omh4.tistory.com
예제코드
// Name: sbof_ret_overwrite.c
// Compile: gcc -o sbof_ret_overwrite sbof_ret_overwrite.c -fno-stack-protector
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buf[8];
printf("Overwrite return address with 0x4141414141414141: ");
gets(buf);
return 0;
}
gdb를 이용해 스택의 내용을 확인하면서 보자.
우선 get(buf)부분에 브레이크보인트를 걸어준다.
이후 실행을 해주고 현재 위치와 스택을 확인해보자.
이제 return addr을 변조해보자. 입력값으로 aaaaaaaaAAAAAAAABBBBBBBB
을 줘보면 스택에는 다음과 같은 변화가 일어난다.
그럼 RET가 0x4242424242424242로 바뀌게된다. 만약 이 주소에 쉘을 실행할 수 있는 코드가 있다면 쉘 실행이 가능해진다.
wargame 문제
[DreamHack] exploit tech : Return Address Overwrite
드림핵을 기반으로 작성한 내용이다. 버퍼오버플로우에 대한 익스 테크이므로 아래의 글을 참고하면 좋다. [system][hacking] stack buffer overflow - 스택 버퍼 오버플로우 드림핵 내용을 기반으로 내 방
3omh4.tistory.com
[DreamHack] basic_exploitation_000 Write Up — 3omh4
3omh4.tistory.com
[DreamHack] basic_exploitation_001 Write Up — 3omh4
3omh4.tistory.com
'CS > system' 카테고리의 다른 글
[System][Dreamhack] wargame - ssp_001 스택 순서 (0) | 2022.08.24 |
---|---|
[System][Dreamhack] bypass canary (0) | 2022.08.10 |
[System][Dreamhack] 메모리 보호 기법 memory mitigation - Stack Canary (0) | 2022.08.09 |
[System] 레이스 컨디션(Race Condition) (0) | 2022.05.09 |
[System] 함수 프롤로그 & 에필로그 (Prologue & Epilogue) (0) | 2022.05.08 |