IgnatiusHeo

구현단계 보안약점 제거 기준-메모리 버퍼 오버플로우 본문

자격/SW보안약점진단원

구현단계 보안약점 제거 기준-메모리 버퍼 오버플로우

Ignatius Heo 2023. 7. 4. 18:41

작성일: 230704

 

※ 본 게시글은 학습 목적으로 행정안전부·KISA의 소프트웨어 보안약점 진단 가이드, 소프트웨어 개발보안 가이드를 참고하여 작성하였습니다.

 

정리 내용: 소프트웨어 보안약점 진단 가이드(303~308p)

구분 - 입력데이터 검증 및 표현
설계단계 - 허용된 범위내 메모리 접근
https://cryptocurrencyclub.tistory.com/96
개요
메모리 버퍼 오버플로우 보안약점은 연속된 메모리 공간을 사용하는 프로그램에서 할당된 메모리의 범위를 넘어선 위치에 자료를 읽거나 쓰려고 할 때 발생한다.

메모리 버퍼 오버플로우는 프로그램의 오동작을 유발시키거나, 악의적인 코드를 실행시킴으로써 공격자 프로그램을 통제할 수 있는 권한을 획득하게 한다.

메모리 버퍼 오버플로우에는 스택 메모리 버퍼 오버플로우와 힙 메모리 버퍼 오버플로우가 있다.

진단 세부사항
(설계단계)
 
① C나 C++ 같이 메모리를 프로그래머가 관리하는 플랫폼을 사용하는 경우 메모리 버퍼의 경계값을 넘어서 메모리를 읽거나 저장하지 않도록 경계 설정 또는 검사를 반드시 수행해야 한다. 설계산출물을 검토하여 배열의 값을 다른 배열로 복사하여 넣는 경우 길이 검사 수행 방식이나 공통 함수가 설계되어 있는지 확인한다.

  ㅇ  리눅스 환경에서 ASLR(Address Space Layout Randomization), StackGuard와 같은 메모리 보호를 위한 설정을 사용하도록 설계되어 있는지 확인
  ㅇ  배열의 값을 다른 배열로 복사하여 넣는 경우, 처리되는 데이터의 길이를 검사하고 사용하도록 코딩규칙을 정의하였는지 확인
  ㅇ  할당된 메모리보다 더 큰 입력값을 사용하여 버퍼오버플로우가 발생되는지 점검할 수 있는 테스트계획의 수립 여부 확인


② 개발시, 메모리 버퍼오버플로우를 발생시킬 수 있는 취약한 API를 사용하지 않도록 통제해야 한다. 취약한 API를 정의하고 있는지 확인한다.
  ㅇ  메모리 버퍼오버플로우를 발생시킬 수 있는 API를 정의하고 사용하지 않도록 하는 코딩 규칙이 개발가이드에 정의되어 있는지 확인

 
보안대책
(구현단계)

프로그램 상에서 메모리 버퍼를 사용할 경우 적절한 버퍼의 크기를 설정하고, 설정된 범위의 메모리 내에서 올바르게 읽거나 쓸 수 있게 통제하여야 한다.

특히, 문자열 저장시 널(Null) 문자로 종료하지 않으면 의도하지 않은 결과를 가져오게 되므로 널(Null) 문자를 버퍼 범위내에 삽입하여 널(Null) 문자로 종료되도록 해야 한다.

진단방법
(구현단계)

버퍼에 값을 기록하는 경우, 값의 크기가 대상 버퍼보다 작은지 확인한다. 버퍼의 크기나 데이터의
크기가 외부 입력 값에 의해 결정되는 경우 입력 값의 크기가 대상 데이터를 충분히 포함할 수 있는지
확인한다.

버퍼의 크기를 비교하거나 인덱싱으로 접근할 경우에는 데이터의 크기 비교 외에도 음수값이 포함 되
지 않도록 0보다 큰지 반드시 확인한다.

메모리 버퍼에 접근할 때 상수로 바로 접근하는 경우 해당 상수값을 확인해야하며, 상수를 이용하는 것보다 버퍼의 범위를 고려하여 접근을 하도록 코드의 수정이 이루어져야한다.

특히, 반복문으로 버퍼에 접근 할 때 반드시 경계값에 대한 확인이 필요하다.

또한 문자열을 처리하기 위해 버퍼를 사용할 경우 문자열의 마지막에 널(Null) 문자가 포함되는지 반드시 확인한다.

 

다. 코드예제

 

ㅇ 분석

1: typedef struct _charvoid {
2: char x[16];
3: void * y;
4: void * z;
5: } charvoid
6: void badCode() {
7: charvoid cv_struct
8: cv_struct.y = (void *) SRC_STR;
9: printLine((char *) cv_struct.y);
/* sizeof(cv_struct)의 사용으로 포인터 y에 덮어쓰기 발생 */
10: memcpy(cv_struct.x, SRC_STR, sizeof(cv_struct));
11: printLine((char *) cv_struct.x);
12: printLine((char *) cv_struct.y);
13:}

ㅇ 내용

1. cv_struct.x에 16바이트를 할당했는데, r10에서 cv_struct 전체 구조체 크기(sizeof(cv_struct))만큼의 메모리를 cv_struct에 할당해서 문제가 발생함

 

ㅇ 수정

1: typedef struct _charvoid {
2: char x[16];
3: void * y;
4: void * z;
5: } charvoid
6: static void goodCode() {
7: charvoid cv_struct
8: cv_struct.y = (void *) SRC_STR;
9: printLine((char *) cv_struct.y);
/* sizeof(cv_struct.x)로 변경하여 포인터 y의 덮어쓰기를 방지함 */
10: memcpy(cv_struct.x, SRC_STR, sizeof(cv_struct.x));
/* 문자열 종료를 위해 널 문자를 삽입함 */
11: cv_struct.x[(sizeof(cv_struct.x)/sizeof(char))-1] = '\0';
12: printLine((char *) cv_struct.x);
13: printLine((char *) cv_struct.y);
14:}

ㅇ 내용

1. r10에서 제대로 배열 메모리 파악해서 삽입함.

2. 배열 마지막에 null 문자 패딩함.(문자열 종료를 표시하기 위함)

 

 

 

 

 

 

 

끝.