[memcpy 를 사용할 때 Buffer Overflow 를 막기 위한 방법]
1. Buffer Overflow?
버퍼 오버플로우란 사용자가 할당받은 버퍼의 크기보다 더 많은 크기의 데이터를 복사하게 되어, 다른 메모리 영역에 잘못된 값을 쓰게 되어 문제를 발생시키는 것이다.
단지 데이터가 손실되거나 파괴되는것이 아니라, 이 기법을 사용하면 프로그램의 실행 순서를 바꿀 수 있기 때문에, 굉장히 큰 문제를 초래할 수 있는 버그이다.
Buffer Overflow 는 매우 잘 알려진 보안 취약점 중 하나로, 이에 대한 자세한 내용은 서적, 인터넷 등을 찾아보면 쉽게 이해할 수 있다.
본 글에서는 이러한 내용까지 다룰 수 없기 때문에, Buffer Overflow에 대한 내용은 다른 참고자료들을 찾아보길 바란다.
2. memcpy?
memcpy 는 메모리를 복사하는 C 함수이다. 많은 사람들이 이 함수를 사용하게 되는데, 이 함수는 다음과 같이 사용한다.
memcpy(data, initdata, size);
즉, initdata 를 data 로 size 만큼 복사하라는 것이다.
좀 더 자세하기 memcpy 를 조사해 보자. 먼저, memcpy 의 정의는 다음과 같다.
void * __cdecl memcpy(void *, const void *, size_t);
모두 기본 자료형을 쓰고 있지만, size_t 는 기본 자료형이 아니다. 그렇다면 size_t 는 어떻게 정의되어 있을까?
typedef unsigned int size_t;
이와 같이 unsigned int 로 정의되어 있다.
3. Buffer Overflow in memcpy
이런 memcpy 에서 어떻게 문제가 발생할까?
문제는 다음과 같은 경우 발생한다.
int nSize = 0;
int nLimit = 100;
char szData[100];
char szInitData[100];
//
//
// nSize 를 입력받거나 대입하는 부분
//
//
if(nSize < nLimit) {
memcpy(szData, szInitData, nSize);
}
일반적으로 위와 같이 nSize 가 nLimit 을 넘지 않는 지만 확인한다.
하지만, nSize 가 음수인 경우에는 어떻게 될까?
nSize 와 nLimit 는 모두 signed 형 이므로, nSize < nLimit 은 true 가 되어 memcpy 로 넘어간다.
그렇다면 memcpy 에서는 어떻게 될까?
memcpy 에서는 size_t 로 받게 되고, 이것은 unsigned 형 이므로, 2147483648 보다 큰 수가 된다.
즉, 의도하지 않은 크기의 메모리를 더 복사하게 되는 것이다.
4. 해결 방법
이 문제를 피해가기 위한 방법은 여러가지가 있지만, 여기서는 3가지를 소개한다.
4.1. memcpy 의 Wrapper Function
다음과 같이 Wrapper Function 을 만들어서 사용한다.
BOOL safe_memcpy(void* data, void* source, int size)
{
if(size < 0) return FALSE;
memcpy(data, source, (size_t)size);
}
4.2. 확인 제어문 강화
if(nSize < nLimit) 만으로 검사하지 않고 다음과 같이 음수도 확인한다.
if(nSize > 0 && nSize < nLimit)
또한, 제어문에서 unsigned 값으로 변환하여 확인한다
if((unsigned int)nSize < (unsigned int)nLimit)
4.3. unsigned 형으로 변환하여 사용
nSize, nLimit 값을 항상 unsigned 값으로 사용한다.
[요약]
memcpy 를 사용할 때에는 항상 size 값이 unsigned 임을 유의하고, 음수 처리의 특성상 signed 값이 unsigned 값에 대입되어 기대하지 않은 효과를 낼 수 있다는 것에 유의하여야 한다.
Hacking & Security/System2008. 11. 25. 15:05