에듀테크 프로젝트 대시보드
스택 버퍼 오버플로우
C 같은 언어에서 함수는 지역 변수를 스택이라는 메모리 영역에 크기를 정해 두고 저장한다. 입력값 길이를 검사하지 않고 그 칸에 더 많은 데이터를 복사하면, 넘친 바이트가 바로 옆에 있는 다른 값들(반환 주소 등)을 덮어쓴다. 이것이 40년 넘게 이어져 온 대표적인 보안 취약점이다. 아래에서 직접 버퍼를 넘치게 만들어 보자.
아래 함수는 크기 8바이트짜리 버퍼 char buf[8]에
입력 문자열을 그대로 복사한다(strcpy). 8글자를 넘기면 넘친 바이트가
스택 카나리 → 저장된 프레임 포인터(SFP) → 반환 주소 순서로 덮어써진다.
문제의 핵심은 "받는 그릇의 크기"를 무시하고 복사한다는 점이다. 길이를 제한하는 함수로 바꾸면 넘침 자체가 일어나지 않는다.
// ❌ 취약: 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++는 속도를 위해 검사를 프로그래머에게 맡긴다.
코드를 완벽히 고치지 못해도, 여러 겹의 방어가 공격을 어렵게 만든다.
| 방어 기법 | 하는 일 | 공격자가 겪는 어려움 |
|---|---|---|
| 스택 카나리 (Stack Canary) |
버퍼와 반환 주소 사이에 무작위 값을 심어 두고, 함수가 끝나기 직전 그 값이 변했는지 검사 | 반환 주소를 덮으려면 카나리도 지나가야 하는데, 값이 바뀌면 프로그램이 즉시 *** stack smashing detected *** 하고 종료 |
| DEP / NX 비트 (데이터 실행 방지) |
스택·힙 같은 데이터 영역을 "실행 불가"로 표시 | 스택에 넣은 셸코드를 CPU가 실행해 주지 않음 (그래서 ROP 같은 우회 기법이 등장) |
| ASLR (주소 공간 배치 무작위화) |
실행할 때마다 스택·라이브러리·힙의 시작 주소를 무작위로 바꿈 | "어디로 점프시킬지" 주소를 미리 알 수 없어 추측이 필요 |
| 경계 검사 API | strncpy, snprintf, fgets 등 길이 인자를 받는 함수 사용 |
애초에 넘침이 발생하지 않음 — 가장 근본적인 해결책 |
※ 이 페이지는 방어 개념을 이해하기 위한 교육용 시각화이며, 실제 공격에 쓸 수 있는 코드는 담고 있지 않다. 취약점 연구는 반드시 허가된 환경에서만 진행해야 한다.