버퍼 오버플로우(BOF, Buffer Overflow)


버퍼 오버플로우는 할당된 버퍼 크기 이상의 데이터가 삽입되었을 때 다른 데이터 영역까지 침범하는 취약점이다. 공격하는 메모리 버퍼의 종류에 따라 스택 기반 버퍼 오버플로우 혹은 힙 기반 버퍼 오버플로우라고 불린다. 이 취약점은 사용자의 입력 값의 크기를 제한하지 않을 때 발생한다.



스택 기반 버퍼 오버플로우


스택 기반 버퍼 오버플로우 공격에 취약한 예제 프로그램을 이용하여 설명한다(모든 예제는 어떤 보호기법도 적용되지 않음을 가정한다).


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

int main(int argc, char* argv[])
{
    char buffer[16];
    strcpy(buffer, argv[1]);
    printf(“%s\n”, buffer);
    return 0;
}


위 코드는 입력된 첫 번째 매개변수를 버퍼에 담아서 출력하는 코드이다. 여기서 strcpy 함수는 복사할 매개변수(argv[1])의 크기를 확인하지 않고 복사될 매개변수(buffer)에 복사하기 때문에 strcpy 함수가 취약하다.


위 그림에서 첫 번째 그림은 매개변수(argv[1])를 ‘A’ 11개, 두 번째 그림은 ‘A’ 15개, 세 번째 그림은 ‘A’ 23개를 입력했을 경우이다. 19개까지 입력해도 아무 이상 없지만 20개를 넘으면 버퍼를 넘어서 SFP(Saved Frame Pointer)와 Return Address를 덮어 쓰여져 의도치 않은 코드를 실행할 가능성이 있다.



힙 기반 버퍼 오버플로우


힙 기반 버퍼 오버플로우 공격에 취약한 예제 프로그램을 이용하여 설명한다.


#include <stdio.h>
#include <stdlib.h>

int main()
{
    unsigned int addrdif;
    char* buf1 = (char*)malloc(sizeof(char) * 8);
    char* buf2 = (char*)malloc(sizeof(char) * 8);

    addrdif = (unsigned int)buf2 - (unsigned int)buf1;
    memset(buf2, ‘A’, 7);
    buf2[7] = ‘\0’;
    printf(“buf2: %s\n”, buf2);

    memset(buf1, ‘B’, (unsigned int)(addrdif + 4));
    printf(“buf2: %s\n”, buf2);

    return 0;
}


위 코드는 각각 8 byte 동적 할당하고 두 번째 할당 받은 메모리를 ‘A’ 7개할당 받은 주소의 차를 구한다. 그리고 두 번째 할당 받은 메모리를 ‘A’ 7개로 초기화하고, 첫 번째 할당 받은 메모리에 주소 차에 4을 더한 만큼 ‘B’를 채운다.




첫 번째 그림은 위 코드가 실행되는 동안의 스택이고, 두 번째 그림은 첫 memset 함수가 실행되고 다음 줄까지 실행한 힙, 세 번째 그림은 다음 memset 함수가 실행되었을 때의 힙의 모습이다. 첫 번째 memset 함수와 마지막 바이트를 NULL로 채우고 출력하면 ‘A’가 7개가 출력이 되고, 두 번째 memset 함수를 실행하면 buf2의 크기인 8을 넘어서 buf1까지 침범하여 ‘A’ 7개가 아닌 ‘BBBBAAA’가 출력된다. 즉, memset 함수를 사용할 때 메모리 크기를 확인하지 않았기 때문에 이처럼 메모리를 침범하는 문제가 발생한다.



대응 방안


버퍼 오버플로우를 대응하기 위한 방법으로는 DEP, ASLR 등이 있다. DEP(Data Execution Prevention)는 실행되지 말아야 하는 메모리 영역에서 코드의 실행을 방지하여 임의의 코드가 실행되는 것을 방지하는 방어 기법이다. Windows에서 사용되며 Linux의 NX-bit와 같은 것이다. 그리고 ASLR(Address Space Layout Randomization)은 PE 파일(exe, dll 등)이 실행될 때마다 즉, 메모리에 로딩될 때마다 Image Base값을 계속 변경해주는 기법이다.





참고

해커스쿨에서 출간한 버퍼 오버플로우에 관한 책(리눅스 상에서의 BOF)

'Buffer Overflow 보호 기법 및 우회 기법' NSHC 문서

정보 보안 개론과 실습 - 시스템 해킹과 보안


Written by dinger from SecurityInsight Research Group.

  1. 캐논볼 2015.10.31 17:38 신고

    memset(buf1, ‘B’, (unsigned int)(addrdif + 4));

    에서 -4가 아닐까요?

    • dinger 2015.11.03 19:58 신고

      memset(buf1, ‘B’, (unsigned int)(addrdif + 4)); 가 맞습니다만 제가 그림을 잘못 그려서 그렇게 이해하신 것 같습니다.
      스택은 새로운 데이터가 추가될수록 큰 주소에서 작은 주소로 할당되는 반면에, 힙은 작은 주소에서 큰 주소로 할당 받게 됩니다.
      지적해주셔서 감사합니다.

+ Recent posts