4 min to read
Secure Coding)Buffer Overflow
시큐어 코딩
@
Buffer Overflow란?
프로그램이 입력(사용자, 파일, 네트워크를 통하거나 또는 다른 방법)을 요구할 때마다, 부적절한 데이터를 받을 가능성이 있다. 입력 데이터가 예약된 공간보다 큰 경우 이것을 자르지 않는다면 그 데이터는 다른 데이터를 덮어 쓰게 될 것이다. 이 경우를 Buffer Overflow라고 한다.
Buffer Overflow의 특징
Buffer Overflow는 어플리케이션에 충돌을 일으키거나 데이터를 손상 시킬 수 있다. 그리고 어플리케이션이 작동하는 시스템에 손상을 입힐 수 있는 추가적인 권한 상승을 위한 공격 벡터를 제공할 수 있다.
모든 응용 프로그램 또는 시스템 소프트웨어는 적어도 일시적으로 사용자로부터의 입력, 파일로부터의 입력, 네트워크로부터의 입력을 저장할 수 있다. 특별한 경우를 제외하고 대부분의 어플리케이션 메모리는 두 장소 중 하나에 저장된다. 따라서 두 장소를 공격하는 Stack Overflows, Heap Overflows가 있다.
- stack-A : 특정 함수, 메서드, 블록 또는 다른 동등한 구조에 대한 단일 호출을 하는 특정 데이터를 저장하는 어플리케이션의 주소 공간의 일부분
- heap : 일반적인 목적은 어플리케이션을 저장, 어플리케이션이 작동하는 동안 (또는 명시적으로 어플리케이션이 더 이상 데이터를 필요로 하지 않는 운영체제를 알려줄 때 까지) 힙에 저장된 데이터는 사용 가능한 상태로 남아있다. 클래스 인스턴스, malloc 으로 할당된 데이터, 핵심 기반 개체 그리고 다른 어플리케이션 데이터는 힙에 상주하고 있다. ( 참고. 그러나 실제 데이터를 가리키는 지역변수는 스택에 저장된다.)
Buffer Underflow란?
입력된 데이터가 있거나 예약된 공간(잘못된 가정, 잘못된 길이 값 또는 C 문자열과 같은 원시 데이터 복사로 인한)보다 짧게 나타날 때를 Buffer Underflow라고 한다. 이것은 오작동부터 현재 스택 또는 힙에 있는 데이터 유출까지 여러 문제가 발생할 수 있다.
해결 방안1. String Handling
많은 문자열 처리 함수는 문자열 길이에 대한 확인을 하지 않고 있기 때문에 문자열은 자주 익스플로잇 가능한 버퍼 오버플로우 소스이다. 위의 그림은 세 개의 문자열 복사 함수가 길이를 초과하는 동일한 문자열을 처리하는 다른 방법을 나타낸 것이다.
- strcpy 함수는 단순하게 전체 문자열을 메모리에 쓴다. 그리고 그 뒤에 무엇이 오든지 간에 덮어써버린다.
- strncpy 함수는 정확한 길이로 문자열을 자른다. 하지만 종료 null 문자 없이 자른다. 이 문자열을 읽을 때, 메모리에서 모든 바이트는 다음 null 문자까지를 문자열의 부분으로 읽을 수 있다. strncpy 를 안전하게 사용하기 위해, 당신은 strncpy 호출 후 명시적으로 버퍼의 마지막 바이트를 0으로 맞추거나 버퍼를 0 이전으로 맞추어야 한다. 즉, 최대 길이에 버퍼 사이즈보다 1바이트 작은 사이즈를 전달해야 한다.
- 오직 srtlcpy 함수는 버퍼 사이즈보다 1 바이트 작게 문자열을 자르고 끝에 null 문자를 추가하므로 완전히 안전하다.
이외에도 주의해야할 함수들이 많이 존재한다. 그것들을 모두 다루는 것은 다소 무리가 있다. Objective-C에선 NSString, CFString을 사용하는 것이 위의 문제들을 해결한 API이기에 특별한 경우가 없다면 Core Foundation을 사용하자.
해결 방안2. Calculating Buffer Sizes
고정된 길이의 버퍼로 작업을 할 때, 버퍼의 사이즈를 계산하기 위해 항상 sizeof 를 사용해야 한다. 그리고 보유할 수 있는 것보다 더 많은 데이터를 버퍼에 넣지 않았는지 확인해야 한다. 원래 버퍼에 정적 크기를 할당하더라도, 당신 또는 나중에 당신의 코드를 유지하는 어떤 사람 중 누군가 버퍼 사이즈를 변경할 수 있지만, 버퍼에 기록하는 모든 경우를 변경하는 것은 실패 할 수 있다.
해결 방안3. Avoiding Integer Overflows and Underflows
버퍼에 들어간 데이터의 크기와 버퍼의 크기를 계산할 때, 항상 size_t와 같은 unsigned 변수를 사용해야 한다. 음수는 큰 정수로 저장되기 때문에, 만약 signed 변수를 사용하는 경우 프로그램에 큰 수를 써서 공격자는 데이터 또는 버퍼의 크기에서 잘못된 계산을 일으킬 수 있다.
해결 방안4. Detecting Buffer Overflows
Buffer Overflow를 테스트하기 위해, 프로그램에서 입력 허용하는 데이터보다 더 많은 데이터가 들어가는 것을 허용해야 한다. 또한, 만약 프로그램이 그래픽 또는 오디오 데이터와 같은 표준형 데이터를 허용하는 경우, 잘못된 데이터를 전달하는 것을 시도해야 한다. 이 과정은 퍼징으로 알려져 있다.
해결 방안5. Avoiding Buffer Underflows
근본적으로 버퍼의 사이즈 또는 버퍼에서 데이터에 대해 코드의 두 가지 부분이 맞지 않는 경우 Buffer Underflow는 발생한다. 예를 들어 고정된 길이의 C 문자열 변수는 256 바이트 공간을 갖게 될 것이다. 그러나 단지 12 바이트 길이 문자열을 포함할 수 있다.
다음 규칙을 따를 경우, 대부분의 언더플로우 공격을 피할 수 있을 것이다.
- 사용하기 전 모든 버퍼를 0으로 채워라. 단지 0만 포함하는 버퍼는 오래된 민감한 정보를 포함할 수 없다.
- 항상 반환값과 실패를 적절히 확인해라.
- 할당 또는 초기화 함수를 호출을 실패하는 경우(예: AuthorizationCopyRights) 오래된 것일 수 있으므로 결과 데이터를 평가하지 마라.
- 얼마나 많은 데이터가 실제로 읽혔는지 정하기 위해 read 시스템 호출과 다른 유사한 호출로부터 반환된 값을 사용해라.
- 미리 정의된 상수를 사용하는 대신에 얼마나 많은 데이터가 존재하는지 확인하기 위한 결과로 사용하거나 함수가 예상된 데이터양을 반환하지 않는 경우 실패로 나타낸다.
- 모든 데이터를 작성하지 않고 write, printf 또는 다른 출력 호출이 반환하는 경우, 특히 나중에 그 데이터를 다시 읽을 수 있는 경우 에러를 표시하고 실패로 나타내라.
- 길이 정보를 포함한 데이터 구조 작업을 할 때, 항상 그 데이터가 예상된 크기인지 검증해라.
- 가능한 C 문자열이 아닌 문자열(CFStringRef 객체, NSString 객체, Pascal 문자열 기타 등등)을 C 문자열로 변경하는 것을 피해라. 대신 원본 형태로 문자열 작업을 해라. 이게 불가능한 경우, 항상 C 문자열에 대한 길이 검사를 수행하거나 또는 소스 데이터의 null 바이트를 확인해라.
- 버퍼 연산과 문자열 연산을 혼합하는 것을 피해라. 이게 불가능한 경우, 항상 C 문자열에 대한 길이 검사를 수행하거나 또는 소스 데이터의 null 바이트를 확인해라.
- 악의적인 조작 또는 잘라내기를 방지하는 방식으로 파일을 저장해라.
- 정수형 오버플로우와 언더플로우를 피해라.
Comments