힙 오버플로우와 메모리 손상 취약점 방어
힙 오버플로우의 발생 조건과 메타데이터 손상, 인접 객체 오염 위험을 정리하고 메모리 보호 및 분석 도구 기반의 방어 방법을 다룬다.
2026-08-14 · 최초 발행 2025-05-26
동적 메모리의 경계를 넘을 때 생기는 문제
힙 오버플로우는 동적 메모리 할당 영역인 힙에서 발생하는 버퍼 오버플로우다. 스택과 달리 힙은 프로그램 실행 중에 할당과 해제가 반복되며, 이 과정에서 발생한 메모리 손상은 심각한 보안 취약점이 될 수 있다.
공격자는 손상된 메모리를 이용해 악의적인 코드를 실행하거나, 권한을 높이거나, 데이터를 유출하려 할 수 있다. 문제의 핵심은 할당된 블록의 범위를 넘어선 쓰기다.
힙 메모리가 관리되는 방식
힙은 실행 중 필요한 크기의 메모리를 확보하는 영역이다. malloc(), calloc(), realloc()으로 할당하고 free()로 해제한다. 블록은 항상 연속적으로 배치되지 않으며, 필요한 경우 크기도 바뀔 수 있다. 구체적인 관리 방식은 운영체제와 언어 런타임의 구현에 따라 달라진다.
경계 검증 실패가 메모리 손상으로 이어지는 과정
힙 오버플로우는 확보한 메모리보다 많은 데이터를 쓰려고 할 때 발생한다. 경계 검사가 없거나 충분하지 않으면 가능성이 커진다. 직접 메모리를 관리하는 C/C++에서 흔히 나타나며, 버퍼 크기 계산 오류, 문자열 처리 실수, 포인터 조작 오류가 주요 원인이다.
아래 코드는 64바이트를 할당한 뒤 입력 길이를 검사하지 않고 복사한다. 입력이 64바이트보다 크면 할당 범위를 넘어선 쓰기가 일어난다.
#include <stdlib.h>
#include <string.h>
void vulnerable_function(char *input) {
char *buffer = (char *)malloc(64); // 64바이트 힙 메모리 할당
strcpy(buffer, input); // 입력 길이 검사 없이 복사 - 취약점!
// 입력이 64바이트보다 크면 오버플로우 발생
free(buffer);
}
int main(int argc, char *argv[]) {
if (argc > 1) {
vulnerable_function(argv[1]);
}
return 0;
}
손상된 힙이 악용되는 지점
힙 메타데이터 손상
할당 블록 앞뒤의 크기나 상태 정보 같은 메타데이터가 변조될 수 있다. 메모리 할당자의 내부 자료구조가 손상되면 공격자가 원하는 위치에 데이터를 쓰는 상황으로 이어질 수 있다. 메모리 관리 알고리즘에 따라 Unlink 공격이나 Use-After-Free 등을 포함한 여러 공격 기법이 존재한다.
인접 객체 오염
힙에서 연속적으로 할당된 객체의 데이터를 덮어쓰는 방식이다. 포인터나 인증 정보처럼 민감한 값을 바꾸면 제어 흐름이 달라질 수 있다. 객체 지향 프로그램에서는 vtable 포인터 조작을 통해 코드 실행 권한 획득으로 이어질 가능성도 있다.
함수 포인터 조작
힙에 보관된 함수 포인터를 악의적인 코드 주소로 변경하는 경우다. 콜백 함수나 이벤트 핸들러가 호출될 때 공격자의 코드가 실행될 수 있다. 복잡한 애플리케이션에서는 특히 위험하고 탐지도 어렵다.
알려진 취약점에서 본 영향
Microsoft Internet Explorer CVE-2014-0322
IE의 힙 스프레이(Heap Spray) 취약점과 결합된 힙 오버플로우 사례다. Flash 객체를 조작해 메모리 레이아웃을 예측 가능하게 만든 뒤 공격했으며, 원격 코드 실행이 가능해 제로데이 공격에 활용됐다.
Android Stagefright CVE-2015-1538
안드로이드 미디어 서버의 MPEG4 파싱 과정에서 발생한 힙 오버플로우다. 특수하게 조작된 미디어 파일을 처리할 때 경계 검사 부재로 발생했으며, MMS로 전송된 미디어 파일만으로도 공격할 수 있었던 심각한 취약점이다.
OpenSSL Heartbleed (CVE-2014-0160)
Heartbleed는 순수한 힙 오버플로우는 아니지만 유사한 메커니즘으로 메모리를 노출한 취약점이다. TLS heartbeat 확장 기능 구현에서 입력 길이를 검증하지 않아 서버 메모리의 개인키, 세션 토큰, 패스워드 같은 민감한 정보가 유출됐다.
코드와 시스템에서 겹쳐 적용하는 방어선
메모리 사용을 안전하게 만드는 코드
경계 검사가 내장된 문자열 및 메모리 함수를 사용하고, 동적 메모리 할당 시 크기 계산 로직을 검증해야 한다. strncpy(), strlcpy(), memcpy_s() 같은 크기 제한 함수를 활용할 수 있다. C++에서는 RAII(Resource Acquisition Is Initialization) 패턴도 적용 대상이다.
실행 환경의 메모리 보호
ASLR(Address Space Layout Randomization)은 메모리 주소를 무작위화한다. DEP/NX(Data Execution Prevention/No-eXecute)는 데이터 영역에서의 코드 실행을 막는다. 힙 쿠키(Heap Cookies)는 메타데이터에 무작위 값을 넣어 변조를 탐지하며, 세그멘테이션(Segmentation)은 힙 영역을 분리해 손상 범위를 제한한다.
분석 도구로 결함을 찾는 방법
정적 분석에는 Coverity, Fortify, Clang Static Analyzer 등을 사용할 수 있다. 동적 분석 도구로는 AddressSanitizer(ASAN), Valgrind, Dr. Memory 등이 있다. AFL, libFuzzer 등을 이용한 퍼징(Fuzzing)도 취약점 발견에 활용된다.
메모리 안전성을 제공하는 언어와 기능
Rust, Go, Java, C#처럼 메모리 안전성이 보장된 언어를 사용하는 방법이 있다. C++에서는 shared_ptr, unique_ptr 같은 스마트 포인터를 활용할 수 있으며, 가비지 컬렉션 언어가 제공하는 장점도 고려할 수 있다.
함께 관리해야 하는 힙 취약점
힙 스프레이(Heap Spray)
대량의 동일한 데이터로 힙을 채워 메모리 레이아웃을 예측 가능하게 만드는 기법이다. ASLR을 우회하기 위해 사용되며, JavaScript를 통한 대량 객체 생성처럼 웹 브라우저 공격에 활용된다.
유즈 애프터 프리(Use-After-Free)
해제된 메모리를 참조하는 취약점이다. 힙 오버플로우와 결합하면 위험이 커진다. 메모리가 해제된 뒤 다른 객체에 재할당되면 타입 혼동(Type Confusion)이 발생할 수 있으며, 최근 브라우저와 커널 등에서 자주 발견되는 유형이다.
더블 프리(Double Free)
이미 해제한 메모리를 다시 해제하는 오류다. 힙 메모리 관리자의 내부 자료구조를 손상시켜 메모리 손상을 일으킬 수 있으며, 일반적으로 힙 오버플로우보다 탐지가 어려운 경우가 있다.
힙 정보 유출(Heap Information Leakage)
힙의 주소값이나 메타데이터 같은 민감한 정보를 노출하는 취약점이다. ASLR 같은 보호 메커니즘을 우회하기 위한 선행 공격으로 활용될 수 있다. 메모리 초기화 부재와 경계 검사 오류 등이 발생 원인이다.
보호 기능과 개발 프로세스의 연결
크롬, 파이어폭스 등 최신 브라우저는 힙 보호 기법을 강화하고 있다. PartitionAlloc, tcmalloc 같은 보안 강화 메모리 할당자와 Microsoft의 Control Flow Guard(CFG), Intel의 Control-flow Enforcement Technology(CET) 같은 제어 흐름 보호 기법도 대응 수단에 포함된다.
개발 단계에서는 CERT C, MISRA C 등의 보안 코딩 표준을 준수하고, 지속적인 보안 교육과 코드 리뷰를 운영할 수 있다. DevSecOps 방식으로 개발 초기부터 보안을 통합하며, 제3자 라이브러리 의존성 관리와 패치 적용도 필요하다.
조직 차원에서는 보안 개발 수명주기(SDL), 정기적인 취약점 스캔과 패치 관리, 보안 인시던트 대응 프로세스, 제로 트러스트 보안 모델을 함께 검토할 수 있다. 메모리 안전 언어가 근본적인 해결책이 될 수 있지만 레거시 시스템에서는 적용에 제한이 있다. 따라서 다층적 방어(Defense in Depth)와 지속적인 교육, 도구 활용, 새 공격 기법에 대한 연구 및 패치 적용으로 위험을 낮춰야 한다.