Post

Stack Overflow vs Stack Buffer Overflow

자라나는 방향의 차이

Stack Overflow vs Stack Buffer Overflow

블로그 글 스타일을 변경하고 AI 생성 이미지를 실험적으로 도입중입니다. 관련 내용은 이전 글을 참조해주시면 감사합니다.

요약

 스택 오버플로스택 버퍼 오버플로
무엇이 넘치나스택 전체스택 위의 배열 하나
넘치는 방향아래 (낮은 주소)위 (높은 주소)
원인깊은 재귀, 큰 지역 변수범위 밖 쓰기, 길이 미확인 복사
결과OS가 즉시 감지해 크래시조용히 데이터 손상, 나중에 크래시
보안 문제거의 없음대표적인 취약점

방향

  • 스택은 높은 주소 → 낮은 주소로 자람
  • 배열 인덱스는 낮은 주소 → 높은 주소로 증가
  • 이 방향 차이가 두 문제를 가르는 핵심

스택 오버플로

  • 스택 전체가 최대 크기를 넘는 것
  • 스택은 0번지까지가 아니라 정해진 한계까지만 자람
  • 원인
    • 너무 깊은 재귀
    • 큰 지역 배열 (int a[10000000];)
  • 한계를 넘어 가드 페이지를 건드리면 발생

가드 페이지

  • Windows: 커밋된 영역 바로 아래에 붙어서 스택과 함께 이동
    • 최대 크기만큼 reserve, 필요한 만큼만 commit
    • 가드 페이지 접근 시 OS가 커밋하고 가드를 한 칸 아래로 옮김
    • 예약 영역 끝에서 더 못 옮기면 스택 오버플로
  • Linux pthread 스택: 맨 아래 경계에 고정, 접근 시 SIGSEGV
  • 큰 지역 배열은 가드 페이지를 건너뛸 수 있어서 컴파일러가 스택 프로브(MSVC __chkstk)를 삽입

스택 버퍼 오버플로

  • 스택 위 배열 하나의 범위를 넘어 쓰는 것
  • 스택 공간이 남아 있어도 발생
  • 배열은 위로 넘치므로 이미 쌓인 데이터를 덮음
    • 저장된 레지스터 → 복귀 주소 → 호출한 함수의 프레임 순
    • 가드 페이지는 반대쪽이라 막지 못함

  • 원인
    • 범위 검사 없는 쓰기, off-by-one (i <= N)
    • strcpy, sprintf, gets 등 길이 미확인 함수
    • memcpy 크기 오류
  • 증상
    • 쓰는 순간이 아니라 return 시점에 크래시
    • 콜스택이 깨져 보임
    • VS Debug 빌드의 “Stack around the variable … was corrupted”
  • 방어
    • 스택 카나리 (/GS, -fstack-protector)
    • ASLR, DEP
    • 경계를 지키는 도구 (std::array, std::vector, std::string)

scanf

  • scanf("%s", buf)는 버퍼 크기를 모르고 길이 제한 없이 씀
  • %[^\n]도 동일, gets는 같은 이유로 표준에서 삭제
  • VS C4996 경고의 이유, _CRT_SECURE_NO_WARNINGS는 경고만 끌 뿐
  • 해결
    • scanf("%15s", buf) (널 문자 자리 1칸 제외)
    • scanf_s("%s", buf, 16) (MSVC)
    • fgets(buf, sizeof(buf), stdin)
  • scanf("%d", &n)은 오버플로 없음, 단 & 누락 시 다른 메모리 손상

int 배열

  • 타입 무관, 스택의 모든 배열에서 발생 (int는 한 칸당 4바이트 손상)
  • 입력받은 개수만큼 배열에 넣는 코드에서 흔한 실수
  • 함수 매개변수 int a[]는 실제로 포인터
    • sizeof(a)는 포인터 크기(8)
    • 길이를 몰라 범위 초과가 쉬움
    • C는 길이를 함께 전달, C++은 std::array, std::vector, std::span

오류 코드

  • 둘 다 C++ 예외가 아님 → try/catch로 못 잡음
  • Windows
    • 스택 오버플로: 0xC00000FD
    • /GS 감지 스택 버퍼 오버플로: 0xC0000409
    • 감지 못 하고 망가진 주소로 점프: 보통 0xC0000005
    • 0xC00000FD는 SEH로 잡을 수는 있으나 복구가 어려움
    • 0xC0000409는 SEH도 거치지 않고 즉시 종료, __fastfail 공용 코드라 다른 원인일 수도 있음
    • “Run-Time Check Failure #2”는 예외 코드가 아니라 /RTC 메시지

정리

  • 스택 오버플로: 스택 전체가 아래로 넘침, 재귀·큰 지역 변수, 가드 페이지로 즉시 감지
  • 스택 버퍼 오버플로: 배열 하나가 위로 넘침, 복귀 주소 손상, 보안 취약점
  • 핵심은 스택은 아래로, 배열 인덱스는 위로
  • 전역 배열은 스택이 아니므로 어느 쪽도 아님
This post is licensed under CC BY 4.0 by the author.