버퍼 오버플로우 (Buffer Overflow)
쉽게 풀면
컵에 물을 따르는 상황을 생각해봅시다. 컵의 용량은 정해져 있는데 그보다 많은 물을 부으면 물이 넘쳐서 옆에 있는 다른 물건까지 젖게 됩니다. 프로그램의 "버퍼"도 이런 컵과 같습니다. 예를 들어 이름을 저장할 공간을 10글자로 잡아뒀는데, 사용자가 20글자를 입력하면 나머지 10글자가 원래 다른 데이터나 실행 코드가 있던 메모리 영역을 덮어쓸 수 있습니다. 공격자는 이 원리를 악용해서 넘치는 데이터 자리에 악성 코드를 몰래 심어 실행시키기도 하는데, 이것이 버퍼 오버플로우 공격입니다.
왜 중요한가
버퍼 오버플로우는 소프트웨어 보안 분야에서 가장 오래되고 근본적인 취약점 유형 중 하나로, 원격 코드 실행이나 권한 상승 같은 심각한 공격으로 이어질 수 있어 시스템 보안 연구에서 꾸준히 다뤄집니다. 그래서 이를 탐지하는 정적·동적 분석 기법, 취약점을 자동으로 찾아내는 퍼징(fuzzing) 기법, 메모리 안전성을 보장하는 프로그래밍 언어와 런타임 방어 기법 연구가 모두 이 개념과 맞닿아 있습니다. 임베디드 시스템이나 운영체제 커널처럼 성능 때문에 여전히 C/C++을 쓰는 영역에서는 지금도 실무적으로 중요한 문제로 남아 있습니다.
논문에서는 이렇게 쓰입니다
이 문장은 프로그램 코드를 실행하지 않고도 분석해서(정적 분석), 배열이나 메모리 공간의 크기를 제대로 확인하지 않는 위험한 코드 구간을 자동으로 찾아냈다는 뜻입니다.
이 문장은 실제로 프로그램을 실행시키면서(동적 분석) 다양한 입력값을 무작위로 넣어보는 방식(퍼징)으로, 임베디드 기기에 들어가는 저수준 프로그램에서 버퍼 오버플로우가 발생하는 지점을 찾아냈다는 뜻입니다.
이 문장은 프로그램이 실행되기 전인 컴파일 단계에서부터 언어 차원의 규칙(소유권 시스템)으로 메모리를 잘못 다루는 코드 자체를 막아, 버퍼 오버플로우가 일어날 여지를 없애는 접근을 설명한 것입니다.
조금 더 깊게 보면
버퍼 오버플로우는 넘치는 위치에 따라 흔히 스택 오버플로우와 힙 오버플로우로 구분되며, 특히 스택 위에서 함수의 반환 주소를 덮어써 공격자가 원하는 코드를 실행시키는 방식이 고전적으로 많이 연구되었습니다. 이를 막기 위한 방어 기법으로는 스택에 임의의 값(카나리)을 심어두고 함수 종료 시 값이 바뀌었는지 확인하는 스택 카나리, 메모리 주소를 매번 무작위로 배치해 공격을 어렵게 만드는 주소 공간 배치 난수화(ASLR), 데이터 영역을 실행 불가능하게 만드는 실행 방지(DEP/NX) 등이 논문에서 자주 함께 언급됩니다. 취약점 탐지 논문을 읽을 때는 정적 분석과 동적 분석(퍼징)이 서로 다른 장단점을 가진 상호보완적 접근이라는 점을 함께 알아두면 도움이 됩니다.
주의할 점
버퍼 오버플로우는 C, C++처럼 메모리를 직접 다루는 저수준 언어에서 특히 흔하며, Java나 Python처럼 메모리 경계를 자동으로 검사하는 언어에서는 상대적으로 드뭅니다. SQL 인젝션처럼 입력값 검증이 부실할 때 발생한다는 공통점이 있지만, 버퍼 오버플로우는 데이터베이스가 아니라 메모리 공간 자체를 침범한다는 점에서 다릅니다.