728x90

Buffer Overflow란 무엇인가?

Buffer Overflow(버퍼 오버플로우)는 메모리에서 고정된 크기의 버퍼(임시 데이터 저장 공간)에 예상보다 많은 데이터를 써서 인접한 메모리 영역을 덮어쓰는 취약점입니다.

 

조금 더 구체적으로:

  • 프로그램에서 문자열, 배열, 입력 데이터를 처리할 때, 미리 지정된 메모리 공간(예: char buf[16])이 있는데 여기에 버퍼 크기보다 큰 데이터를 넣으면 버퍼를 넘어선 메모리 공간까지 덮어써 버립니다.
  • 이때 덮어쓰는 메모리에는 프로그램의 제어 흐름을 관리하는 정보(예: 반환 주소, 함수 포인터, 변수 등)가 있을 수 있어, 공격자가 이걸 조작하면 임의의 코드 실행, 시스템 권한 상승, 서비스 거부(Denial of Service, DoS) 같은 보안 사고로 이어질 수 있습니다.

예시 (C 코드)

#include <stdio.h>
#include <string.h>

void vulnerable(char *input) {
    char buffer[16];
    strcpy(buffer, input);
    printf("You entered: %s\n", buffer);
}

int main(int argc, char *argv[]) {
    vulnerable(argv[1]);
    return 0;
}
이 프로그램은 argv[1]로 길이가 16자를 초과하는 문자열을 넣으면 buffer 뒤의 메모리 영역까지 덮어쓰게 됩니다. 만약 공격자가 여기에 특수 제작한 페이로드를 넣으면 프로그램의 흐름을 공격자가 원하는 방향으로 바꿀 수 있습니다.

 

 Buffer Overflow의 위험

  • 코드 실행: 공격자가 셸코드(shellcode)를 심어 시스템에서 임의 명령 실행
  • 서비스 다운: 프로그램이 크래시하거나 멈춤
  • 권한 상승: 일반 사용자 권한에서 root 권한 탈취
  • 정보 유출: 메모리에서 비밀 데이터(비밀번호, 토큰 등) 노출

 

Buffer Overflow 예방 방법

1. 안전한 함수 사용

  • C의 strcpy, sprintf, gets 같은 길이 제한 없는 함수 대신:
    • strncpy, snprintf, fgets처럼 길이를 제한할 수 있는 함수 사용

2. 경계 검사(bound checking)

  • 배열, 버퍼에 접근할 때 항상 길이 검사를 하고, 입력값 검증을 철저히 할 것

3. 스택가드(StackGuard)

  • 함수가 호출될 때, 스택 프레임의 반환 주소 앞에 ‘카나리(canary)’ 값이라는 특별한 값을 삽입합니다.
  • 함수가 리턴할 때, 이 카나리 값을 검사해서 값이 변조되었는지 확인합니다.
    • 변조되었다면 → 버퍼 오버플로우 발생 → 프로그램 강제 종료 (공격 차단)
    • 변조되지 않았다면 → 정상 리턴

즉, 공격자가 스택을 넘쳐쓰기 위해 반환 주소를 덮으려고 하면, 카나리 값도 함께 덮어써야 하므로 탐지될 가능성이 매우 높습니다.

 

  • 소스 코드 수정 없이 컴파일 옵션(-fstack-protector)만으로 적용 가능
  • 주요 보호 대상: 반환 주소
  • 함수 포인터, longjmp buffer, 구조체 내부 포인터 등 다른 메모리 공격은 방어하지 못함

 StackGuard 종류

  • 일반 StackGuard: 고정된 카나리 값 사용
  • Random Canary: 실행 시마다 랜덤 값 사용
  • Terminator Canary: 널 문자나 개행 문자 같은 문자열 종료용 값 포함 (strcpy 같은 함수 공격 차단)
  • Random XOR Canary: 랜덤 값과 반환 주소 XOR 처리

 

4. StackShield

StackShield는 StackGuard보다 더 넓은 범위를 보호하도록 설계된 보안 기법입니다.
이 방식은 스택의 반환 주소를 별도로 복사하여 보관하고, 함수 리턴 시 원래의 복사본을 사용하여 반환하는 방식으로 동작합니다.

 

동작 원리

  • 함수 진입 시, 반환 주소를 스택 밖의 안전한 메모리 영역(예: 글로벌 변수 공간)에 복사합니다.
  • 함수가 리턴할 때, 스택의 반환 주소가 아닌 복사해 둔 안전한 반환 주소를 사용합니다.
  • 따라서 공격자가 스택의 반환 주소를 덮어써도, 실제로 리턴에 쓰이는 주소는 안전하므로 공격이 실패합니다.

특징

  • 반환 주소를 스택에서 완전히 분리하므로 오버플로우 공격이 거의 불가능
  • 스택 이외의 다른 코드 포인터나 함수 포인터는 여전히 보호하지 못함
  • 성능 오버헤드가 더 크고, 적용이 제한적이며 유지보수가 어려운 경우도 있음

 

4. 주소 공간 배치 난수화(Address Space Layout Randomization, ASLR)

  • 운영체제에서 메모리 주소를 랜덤화하여 공격자가 정확한 메모리 주소를 예측하지 못하게 함

 

5. 실행 방지 영역(Non-Executable Stack, NX bit)

  • 스택 메모리 영역을 실행 불가능하게 설정해, 스택에 심은 셸코드가 실행되지 못하게 함

6. 컴파일러 보안 옵션 활용

  • 최신 컴파일러 옵션:
    • -D_FORTIFY_SOURCE=2 (glibc 기반)
    • RELRO (Relocation Read-Only)
    • PIE (Position Independent Executable)
728x90

+ Recent posts