버퍼 오버플로우: 알고 넘어가야 할 보안 취약점
개념:
버퍼 오버플로우는 컴퓨터 프로그래밍 및 시스템 보안에서 중요한 개념 중 하나로, 프로그램이 할당된 버퍼를 넘어서 데이터를 쓰거나 복사할 때 발생하는 보안 취약점을 가리킨다. 버퍼는 일련의 데이터를 저장하기 위한 메모리 블록으로, 버퍼 오버플로우는 입력 데이터가 버퍼의 크기를 초과하여 인접한 메모리 영역을 덮어쓰게 되는 상황을 의미한다.
원리:
프로그램은 데이터를 처리할 때 메모리 버퍼를 사용하여 데이터를 임시로 저장하거나 조작한다. 하지만 프로그래머가 입력 데이터의 크기를 충분히 확인하지 않거나, 잘못된 방식으로 데이터를 복사하거나 이동시킬 때, 버퍼가 허용 가능한 크기를 초과할 수 있다. 이로 인해 메모리 영역을 넘어가게 되어 중요한 제어 데이터나 실행 코드를 덮어쓰게 되며, 공격자는 이를 악용하여 시스템 제어권을 획득할 수 있다.
부가개념:
- 스택과 힙: 버퍼 오버플로우는 스택과 힙 메모리 영역에서 주로 발생한다. 스택은 함수 호출 및 로컬 변수를 관리하며, 힙은 동적으로 할당된 데이터를 저장한다.
- NOP 슬레드: 악용을 위해 주입되는 악성 코드를 실행하기 위해 사용되는 일련의 무작위 명령(No-Operation, NOP)을 포함하는 슬레드이다.
버퍼 오버 플로우 공격 방식 중 하나인 NOP 슬레드는 다음 명령으로 넘어가는 것이 썰매같다 해서 Sled 라고 불리며 ASLR이 걸려 있어 주소값이 계속 변경되는 환경에서 return-to-shellcode 기법이나 heap Spray형태의 공격 코드들에서 반복구문과 NOP sled를 쓴다.
그 이유로는
- 임의의 메모리를 참조하게 되면 해당 위치에 무조건 악의적인 행위를 실행 하는 코드가 있을 수만은 없다.
- NOP sled를 이용하여 참조한 위치에 악의적인 행위 코드가 없으면 자연스럽게 실행 흐름을 타고 흘러감
- NOP명령어들을 타고 흘러가다 악의적인 행위 코드를 포함하고 있는 위치로 갈 수 있음.
- Shell Code의 주소를 정확히 알아내기 힘들 경우 큰 메모리를 확보하여 Shell Code의 주소의 오차 범위를 크게 만들 때 사용.
스택버퍼 오버플로우 코드예시:
#include <stdio.h>
#include <string.h>
void vulnerableFunction(char *input) {
char buffer[64];
strcpy(buffer, input); // 취약한 복사 함수 사용
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: %s <input>\n", argv[0]);
return 1;
}
vulnerableFunction(argv[1]);
return 0;
}
설명: vulnerableFunction 내부에서 strcpy 함수를 사용하여 입력된 문자열을 버퍼에 복사하는데, 이때 입력 데이터의 크기를 확인하지 않기 때문에 입력 데이터의 크기가 버퍼의 크기를 초과하면 버퍼 오버플로우가 발생한다.
힙 버퍼 오버플로우 코드 예시:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *buffer = (char *)malloc(16);
if (buffer == NULL) {
perror("Memory allocation error");
return 1;
}
strcpy(buffer, "Hello, buffer overflow!");
printf("%s\n", buffer);
free(buffer);
return 0;
}
NOP Sled 코드 예시:
NOP sled는 악성 코드 실행을 보다 정확하게 이끌기 위해 사용되는 일련의 무작위 명령(No-Operation, NOP)이다.
아래 코드는 x86 아키텍처에서 NOP sled를 구현한 예시:
section .text
global _start
_start:
jmp short payload ; NOP sled 이후 악성 코드로 점프
nopsled:
nop ; 여러 개의 NOP 명령
nop
nop
; 이하 생략
payload:
; 악성 코드 실행
설명: nopsled 섹션에는 여러 개의 NOP 명령이 나열되어 있다. 이후 payload 레이블에서 악성 코드를 실행하는데, 악성 코드의 주소는 NOP sled의 시작 지점으로부터 상대적인 위치로 설정되어 정확한 위치에서 악성 코드 실행이 시작될 수 있게 된다.
대응방법:
- 입력 검증: 입력 데이터의 크기를 확인하여 버퍼 오버플로우 공격을 방지한다.
- 보안 함수 사용: 안전한 문자열 복사 함수(예: strncpy) 사용을 통해 버퍼 오버플로우 가능성을 최소화한다.
- ASLR 활성화: ASLR을 활성화하여 메모리 주소의 예측을 어렵게 하여 공격자의 작업을 어렵게 만든다.
- 버퍼 크기 제한: 버퍼의 크기를 정확하게 할당하고 사용하는 것이 중요합니다. 데이터의 크기를 버퍼의 크기와 비교하여 오버플로우를 방지한다.
- 스택 가드 사용: 스택 가드(예: 스택 쉴드, 스택 캐노리)를 활용하여 스택의 오버플로우를 탐지하고 방지한다.
- 권한 및 접근 제어: 사용자 권한 및 접근을 제한하여 악의적인 코드가 시스템 또는 애플리케이션에 침입하지 못하도록 한다.
- 버퍼 오버플로우 방어용 라이브러리 사용: 버퍼 오버플로우를 방어하기 위한 특별한 라이브러리(예: libsafe, StackGuard, Buffer Overflow Protection)를 사용한다.
- 컴파일러 보안 옵션 활용: 컴파일러에서 제공하는 보안 옵션을 활용하여 버퍼 오버플로우와 같은 취약점을 예방한다.
- DEP(데이터 실행 방지) 활성화: DEP를 활성화하여 실행 가능한 메모리 영역을 제한하여 악성 코드 실행을 방지한다.
용어정리:
- 버퍼 오버플로우: 할당된 버퍼를 초과하여 데이터를 쓰거나 복사함으로써 메모리를 덮어쓰는 보안 취약점.
- 스택: 함수 호출과 로컬 변수 관리에 사용되는 메모리 영역.
- 힙: 동적으로 할당된 데이터를 저장하는 메모리 영역.
- NOP 슬레드: 악성 코드 실행을 위한 일련의 무작위 명령.
- ASLR: 주소 공간 배치 무작위화로 메모리 주소 예측을 어렵게 만듦.
- DEP: 데이터 실행 방지로 실행 가능한 메모리 영역을 제한하여 악성 코드 실행을 어렵게 만듦.
'시스템' 카테고리의 다른 글
[시스템] 커널? 알아볼게요 ( with. python ) (0) | 2023.08.18 |
---|---|
[시스템] 바인드 쉘 ? 알아볼게요 ( with. shell script ) (0) | 2023.08.18 |
[시스템] 리버스 쉘 ? 알아볼게요 ( with. python, shell script ) (0) | 2023.08.18 |
[시스템] 정적 라이브러리 ? 동적 라이브러리 ? ( with . code ) (0) | 2023.08.17 |
[시스템] 알기 쉬운 쉬프트 연산 (0) | 2023.08.07 |