버퍼 오버플로

위키백과 ― 우리 모두의 백과사전.

이 문서는 편집 지침에 맞춰 다듬어야 합니다.

버퍼 오버플로(buffer overflow) 또는 버퍼 오버런(buffer overrun)은 메모리를 다루는 데에 오류가 발생하여 잘못된 동작을 하는 프로그램 취약점이다.

버퍼 오버플로는 보통 데이터를 저장하는 과정에서 그 데이터를 저장할 메모리 위치가 유효한지를 검사하지 않아 발생한다. 이러한 경우 데이터가 담긴 위치 근처에 있는 값이 손상되고, 그 손상이 프로그램 실행에 영향을 미칠 수도 있다. 특히, 악의적인 공격으로 인해 프로그램에 취약점이 발생할 수도 있다.

목차

[편집] 기술적인 설명

버퍼 오버플로는 불충분한 바운드 확인에 의해 버퍼에 쓰인 데이터가 버퍼에 이미 할당된 근접한 메모리 주소에 있는 데이터 값을 오염시킬때 발생한다. 대부분 이는 캐릭터 스트링을 하나의 버퍼에서 다른 버퍼로 복사할 때 발생한다.

[편집] 기본 예제

아래의 예제에서, 프로그램은 메모리에서 인접해있는 두 아이템을 정의하였다: 8 바이트 길이 스트링 버퍼, A. 그리고 2 바이트 정수형, B. 우선, A 는 zero 바이트만 포함하고 B는 숫자 3을 포함한다. 문자들은 1바이트 크기이다.

A A A A A A A A B B
0 0 0 0 0 0 0 0 0 3

이제, 프로그램은 문자열 "excessive"를 A 버퍼에 저장한다. zero 바이트가 스트링의 끝임을 알리기 위해 따라온다. 스트링의 길이를 확인하지 않음으로 B의 값을 덮어쓴다.

A A A A A A A A B B
'e' 'x' 'c' 'e' 's' 's' 'i' 'v' 'e' 0

비록 프로그래머가 B가 바뀌는 것을 전혀 의도하지 않았다 하더라도, B의 값은 문자열의 한 부분은 구성하는 숫자로 바뀌었다. 이 예제에서 ASCII를 사용하는 빅 엔디언 시스템에서 zero byte가 따라붙는 "e"가 숫자 25836가 될 수 있다. 만약 B가 프로그램에 의해 정의된 다른 변수 아이템이었다면, B의 끝을 지나가는 긴 스트링을 쓰는 것은 세그먼트 오류, 프로세스 종료와 같은 오류를 발생시켰을 것이다.

[편집] 스택에서 버퍼 오버플로

상관없는 변수의 값을 바꾸는데다가, 버퍼 오버플로는 종종 실행하는 프로그램이 임의의 제공된 코드를 실행시키게 하는 공격자에 의해 쓰인다(착취당한다). 그 기술은 공격자가 버퍼가 적재되어있는 메모리 지역에 의존하는 프로세스의 제어를 찾는데 사용될 수도 있다, 예를 들어, 데어터가 임시로 "top"에 "pushed"되고 후에 변수의 값을 읽기위해 "popped"되는 스택 메모리 구역. 전형적으로 함수가 실행을 시작할 때, 오직 그 함수의 실행동안만 접근가능하도록 남아있는 임시 데이터 아이템(지역 변수)이 푸쉬된다.

아래의 예에서, "X"는 프로그램이 실행될 때 스택에 있게 되는 데이터이다; 프로그램은 그 다음 작은 양의 저장공간만 필요한 함수 "Y"를 호출한다. 그리고 "Y"는 그 다음 많은 버퍼를 필요로 하는 "Z"를 호출한다.

Z Z Z Z Z Z Y X X X
             : / / /

만약 함수 Z가 오버플로를 발생시키면, 그것은 함수 Y나 주 프로그램에 포함된 데이터를 덮어 쓸 수도 있다:

Z Z Z Z Z Z Y X X X
. . . . . . . . / /

이것은 대부분의 시스템에서 현재의 프로세스가 호출되기 전 실행되고 있던 프로그램 부분의 위치인 반환값을 스택이 갖고 있기 때문에 특히나 심각하다. 함수가 끝날 때, 임시 저장소는 스택에서 제거되고 실행은 반환 주소로 되돌아 간다. 그런데 만약, 반환 주소가 버퍼 오버플로에 의해서 덮혀 쓰여지면, 어떤 다른 위치를 가리킬 것이다. 처음 예제에서와 같은 버퍼 오퍼플로가 우연히 발생하는 경우, 거의 틀림없이 쓸모없는 위치일 것이다. 어떠한 프로그램 인스트럭션 위치가 아니고, 프로세스는 망가질 것이다. 하지만, 악의적인 공격자가 시스템 보안과 충돌할 수 있는 임의 위치로 반환 주소를 바꿀 수 있다.

[편집] 예제 소스 코드

아래의 C 소스 코드는 일반적인 프로그래밍 실수를 보여준다. 일단 컴파일 되면, 너무 긴 커맨드라인 인자 스트링을 가지고 실행하면 프로그램은 버퍼 오버플로 오류를 발생할 것이다. 왜냐하면 이 인자의 길이를 체크하지 않고 버퍼를 채우는데 사용하기 때문이다. [1]

/* overflow.c - demonstrates a buffer overflow */
 
#include <stdio.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
  char buffer[10];
  if (argc < 2)
  {
    fprintf(stderr, "USAGE: %s string\n", argv[0]);
    return 1;
  }
  strcpy(buffer, argv[1]);
  return 0;
}

9개 이하의 문자 스트링은 버퍼 오버플로를 일으키지 않는다. 10 이상의 문자들은 오버플로를 일으킨다. 이것은 언제나 부정확하지만 프로그램 오류나 세그먼트 폴트를 일으키지는 않는다. strncpy는 버퍼에 쓰여질 문자의 갯수를 제한할 수 있다.

이 프로그램은 strncpy를 이용해 아래와 같이 안전하게 다시 쓸 수 있다: [1]

/* better.c - demonstrates one method of fixing the problem */
 
#include <stdio.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
  char buffer[10];
  if (argc < 2)
  {
    fprintf(stderr, "USAGE: %s string\n", argv[0]);
    return 1;
  }
  strncpy(buffer, argv[1], sizeof(buffer));
  buffer[sizeof(buffer) - 1] = '\0';  /* explicitly write a string terminator */
  return 0;
}

[편집] 같이 보기

  • 컴퓨터 보안
  • Computer insecurity
  • Security focused operating systems
  • Static code analysis
  • 힙 오버플로
  • Return-to-libc attack
  • Self-modifying code
  • 셸코드

[편집] 참조

  1. 1.0 1.1 Safer C: Developing Software for High-integrity and Safety-critical Systems (ISBN 0-07-707640-0)

[편집] 외부 링크