한양과학기술고등학교

에듀테크 프로젝트 대시보드

스택 버퍼 오버플로우

스택 버퍼 오버플로우 — 정해진 칸을 넘치면 생기는 일

C 같은 언어에서 함수는 지역 변수를 스택이라는 메모리 영역에 크기를 정해 두고 저장한다. 입력값 길이를 검사하지 않고 그 칸에 더 많은 데이터를 복사하면, 넘친 바이트가 바로 옆에 있는 다른 값들(반환 주소 등)을 덮어쓴다. 이것이 40년 넘게 이어져 온 대표적인 보안 취약점이다. 아래에서 직접 버퍼를 넘치게 만들어 보자.

1 스택에 문자열 복사해 보기

아래 함수는 크기 8바이트짜리 버퍼 char buf[8]에 입력 문자열을 그대로 복사한다(strcpy). 8글자를 넘기면 넘친 바이트가 스택 카나리 → 저장된 프레임 포인터(SFP) → 반환 주소 순서로 덮어써진다.

정상적으로 채워진 바이트 버퍼를 넘쳐 흘러든 바이트 카나리 값
문자열을 입력하면 스택이 실시간으로 채워집니다.

2 취약한 코드와 고친 코드

문제의 핵심은 "받는 그릇의 크기"를 무시하고 복사한다는 점이다. 길이를 제한하는 함수로 바꾸면 넘침 자체가 일어나지 않는다.

// ❌ 취약: buf 크기와 무관하게 input 전체를 복사
void greet(char *input) {
    char buf[8];
    strcpy(buf, input);   // input이 8자를 넘으면 스택이 깨진다
    printf("Hi, %s\n", buf);
}
// ✅ 안전: 최대 7자 + 널 문자, 넘치면 잘라 버림
void greet(char *input) {
    char buf[8];
    snprintf(buf, sizeof buf, "%s", input);
    printf("Hi, %s\n", buf);
}

파이썬·자바·러스트·Go 등 대부분의 현대 언어는 배열 접근 시 경계를 자동으로 검사하거나 문자열을 알아서 늘려 주기 때문에 이런 식의 스택 오버플로우가 발생하지 않는다. 반대로 C/C++는 속도를 위해 검사를 프로그래머에게 맡긴다.

3 운영체제·컴파일러의 방어막

코드를 완벽히 고치지 못해도, 여러 겹의 방어가 공격을 어렵게 만든다.

방어 기법하는 일공격자가 겪는 어려움
스택 카나리
(Stack Canary)
버퍼와 반환 주소 사이에 무작위 값을 심어 두고, 함수가 끝나기 직전 그 값이 변했는지 검사 반환 주소를 덮으려면 카나리도 지나가야 하는데, 값이 바뀌면 프로그램이 즉시 *** stack smashing detected *** 하고 종료
DEP / NX 비트
(데이터 실행 방지)
스택·힙 같은 데이터 영역을 "실행 불가"로 표시 스택에 넣은 셸코드를 CPU가 실행해 주지 않음 (그래서 ROP 같은 우회 기법이 등장)
ASLR
(주소 공간 배치 무작위화)
실행할 때마다 스택·라이브러리·힙의 시작 주소를 무작위로 바꿈 "어디로 점프시킬지" 주소를 미리 알 수 없어 추측이 필요
경계 검사 API strncpy, snprintf, fgets 등 길이 인자를 받는 함수 사용 애초에 넘침이 발생하지 않음 — 가장 근본적인 해결책

※ 이 페이지는 방어 개념을 이해하기 위한 교육용 시각화이며, 실제 공격에 쓸 수 있는 코드는 담고 있지 않다. 취약점 연구는 반드시 허가된 환경에서만 진행해야 한다.