C 언어

[C언어] 버퍼 오버플로우(Buffer overflow) 예방법/ 스택 버퍼 오버플로우/ 힙 버퍼 오버플로우

Let it out 2024. 2. 24. 21:04

버퍼 오버플로우 개념

버퍼 오버플로우는 버퍼에 할당된 저장 영역보다, 더 많은 자료를 입력하여 데이터를 변경 할 수 있는 조건이다. 
 
공격자는 조건을 이용해 시스템 먹통으로 만들거나 코드를 삽입해서 시스템의 제어를 가진다.
 
버퍼 오버플로우는 스택 버퍼 오버플로우, 힙 버퍼 오버플로우 두 가지가 있다.
 

버퍼 오버플로우는 버퍼 오버런(buffer overrun), 버퍼 오버라이트(buffer overwrite)라고도 불린다. 

 

 

 

버퍼 오버플로우 예제

아래 c언어 코드를 실행 해보자.
 
strcpy_s(buffer, 20, input); 함수에서 문자열을 복사하는 예제다.
#include <stdio.h>
#include <string.h>

void vulnerableFunction(char* input) {
    char buffer[10];
    strcpy_s(buffer, 20, input);//4.copy하기
    printf("입력값: %s\n", buffer); //공백"\n" 포함 10자가 넘으면 오류 발생
}

int main() {
    char userInput[20];
    printf("문자열을 입력하세요: ");// 1.문자 입력
    gets(userInput); //2.문자열 입력 받기(공백"\n" 포함 )
    vulnerableFunction(userInput);//3.함수 가기
    return 0;
}

 

 

 
1234567891 을 입력해서 엔터를 누른다.
 
1234567891은 공백 까지 총 11글자다. (gets 함수는 문자열을 입력하는 함수인데 공백(\n)을 포함 한다.)
 
 
버퍼 오버플로우가 발생했다면서 에러가 발생한다.

 
 

오류가 발생하는 이유

buffer 10 바이트 보다 큰 11바이트를 복사해서 넣을려고 하니 버퍼 오버플로우가 발생해 오류가 났다.
 
 
 

gets 대신 fgets 함수 사용

버퍼 오버 플로우를 예방하려면 gets 함수 대신 fgets 함수를 사용해줘야한다.
 
fgets 함수는 최대  입력 수를 정할 수 있다.
fgets(userInput, 10);

 

 
fgets 함수에 인자에 10을 적으면 사용자가 문자열 10개만 입력이 가능하니 버퍼 오버플로우를 사전에 예방 할 수 있다.
 
따라서 c언어는 gets 함수 사용을 권장 하지 않는다.
 
 


 

스택 버퍼 오버플로우 예제

buffer[8] 보다 많은 8글자 이상 입력하면 오버플로우가 발생한다.
 
gets 함수를 fgets 함수로 바꿔 입력수를 제한해야 한다.
#include <stdio.h>

int main() 
{
    char buffer[8];
    printf("문자열을 입력하세요: ");
    gets(buffer);
    printf("입력값: %s\n", buffer);
}
 
 

힙 버퍼 오버플로우 예제

동적 할당을 한 buffer 보다 많은 10글자 이상 입력하면 오버 플로우가 발생한다.
 
gets 함수를 fgets 함수로 바꿔 입력수를 제한해야 한다.
 
또한 동적 할당 해제인 free를 꼭 해줘야 한다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void vulnerableFunction(char* input) 
{
    char* buffer = (char*)malloc(10);
    strcpy_s(buffer, 10, input);
    printf("입력값: %s\n", buffer);
    free(buffer);
}

int main() {
    char userInput[20];
    printf("문자열을 입력하세요: ");
    gets(userInput);
    vulnerableFunction(userInput);
    return 0;
}

 

 
 
 
 

버퍼 오버플로우 예방법

1. 프로그래밍 언어 선택
 
현대의 고급 프로그래밍 언어는 변수 타입, 허용되지 않는 연산 등에 대해 강력한 표기법을 제공한다.
 
이러면 프로그래머가 오버플로우를 따로 검증하는 코드를 안 작성해도 된다.
 
왜냐하면 컴파일러가 그 표기법은 안된다고 검증을 하라고 알려주기 때문이다.
 
 
 
 
2. 안전한 라이브러리 사용
 
검증된 라이브러리 같은 경우는 개발자들이 마음 놓고 쓴다.
 
하지만 어떠한 버퍼 오버플로우가 있을 지 모르는 일이다.
 
또한 사용 권장하지 않는 함수들은 사용 하면 안된다.
 
예를 들어 gets 함수대신 getsf 함수를 쓰는 것처럼 안전한 라이브러리 함수를 사용해야 한다.
반응형