본 문서는 드림핵 커리큘럼 강의를 수강하고 요약한 문서입니다.
스택은 그 크기가 동적으로 확장될 수 있다. 스택 오버플로우는 확장이 너무 많이된 경우에 발생하는 버그다. 반면 스택 버퍼 오버플로우는 스택에 위치한 버퍼보다 큰 데이터가 입력되어 발생하는 버그다.
스택 버퍼 오버플로우는 스택의 버퍼에서 발생하는 오버플로우다.
버퍼는 데이터가 목적지로 이동되기 전에 보관되는 임시 저장소다. 현대에서는 데이터가 저장될 수 있는 모든 단위를 버퍼라고 한다.
버퍼 오버플로우는 문자 그대로 버퍼가 넘치는 것을 의미한다. 일반적으로 버퍼는 메모리상에서 연속해서 할당되므로 임의의 버퍼에서 오버플로우가 발생하면, 뒤의 버퍼가 조작될 위험이 있다.
아래는 예시로 주어진 코드다.
// 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 auth = 0;
char temp[16];
strncpy(temp, password, strlen(password));
if(!strcmp(temp, "SECRET_PASSWORD"))
auth = 1;
return auth;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: ./sbof_auth ADMIN_PASSWORD\n");
exit(-1);
}
if (check_auth(argv[1]))
printf("Hello Admin!\n");
else
printf("Access Denied!\n");
}
위에서 auth는 temp버퍼 뒤에 존재하므로, temp 버퍼에 오버플로우를 발생시키면 auth의 값을 임의의 값으로 바꿀 수 있다.
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() {
char secret[16] = "secret message";
char barrier[4] = {};
char name[8] = {};
memset(barrier, 0, 4);
printf("Your name: ");
read(0, name, 12);
printf("Your name is %s.", name);
}
// Name: sbof_ret_overwrite.c
// Compile: gcc -o sbof_ret_overwrite sbof_ret_overwrite.c -fno-stack-protector
#include <stdio.h>
#include <unistd.h>
void win() {
printf("You won!\n");
}
int main(void) {
char buf[8];
printf("Overwrite return address with %p:\n", &win);
read(0, buf, 32);
return 0;
}
위 코드에서 buf이후에는 RBP 값이 있다.(이건 메인 함수를 호출하면서, 스택프레임을 설정할때 ave 된 것이다.) 즉 여기에 win()주소를 넣을 수 있게 만들면 된다.