포맷스트링 공격 (Format String Attack)

 

1. 정의

포맷스트링 공격은 C/C++ 계열 프로그램에서 사용자 입력을 포맷 문자열 함수에 직접 전달할 때 발생하는 취약점으로, 메모리 노출·메모리 조작·원격 코드 실행 등을 유발하는 대표적 메모리 기반 공격기법이다. printf(), sprintf(), syslog() 등 포맷 문자열 함수에 사용자 입력이 그대로 전달될 때, 공격자가 %x, %n 등의 포맷 지정자를 삽입하여 메모리를 읽거나 수정하는 공격이다.

2. 발생 원인 및 영향

(1) 발생 원인

  • 포맷 문자열을 상수로 사용하지 않고, 사용자 입력을 그대로 포맷 인자로 전달
  • 스택 기반 포인터 참조 구조로 인해 외부 입력이 스택/힙 메모리 영역에 접근할 수 있게 됨.
  • 메모리 주소 보호 기법 미적용(ASLR, Stack Canary 등) 시 위험 증가.

(2) 영향

  • 프로그램 비정상 종료
  • 시스템 내부 정보 노출
  • 권한 상승 및 관리자 권한 획득
  • 원격 코드 실행 및 시스템 완전 장악 가능

3. 주요 공격 기법

지정자 공격 방식 목적
%x 스택에 저장된 데이터나 메모리 주소를 순차적으로 읽어 정보 유출 스택 내부의 비밀 정보(e.g., Return Address, Cookie 값) 획득
%n 현재까지 출력된 바이트 수를 특정 메모리 주소에 쓰기
이를 악용해 함수 포인터·리턴 주소를 원하는 값으로 덮어써 실행 흐름 조작
제어 흐름 변조 (e.g., Return Address 덮어쓰기)

 

4. 대응 방안

구분 주요 대책 상세 내용
안전한 포맷 사용 포맷 스트링 함수 사용 시 반드시 포맷 지정자인자를 명시 printf("%s", input)와 같이 안전한 형식으로 사용
정적/동적 분석 SAST(정적 분석 도구)를 활용하여 코드를 분석하고, DAST(동적 분석 도구)로 실제 취약점 발생 여부 테스트 개발 단계에서 취약 코드 사전 제거
컴파일러 보안 옵션 ASLR (Address Space Layout Randomization), DEP (Data Execution Prevention) 등 메모리 보호 기법 적용 공격자가 메모리 주소를 예측하여 공격하기 어렵게 만듦

 

 

5. 결론

포맷스트링 공격은 단순 입력 처리 실수로 발생하지만, 메모리 읽기·쓰기·실행 흐름 조작까지 가능한 고위험 취약점이다. 안전한 포맷 사용과 메모리 보호 기법 결합을 통해 예방이 필수적이다. 최근에는 안전성이 높은 메모리 안정 언어(Memory-safe Language)인 Rust, Go 등의 도입을 통해 컴파일 단계에서 메모리 관련 취약점 발생 가능성을 근본적으로 차단하려는 노력이 확대되고 있다.

+ Recent posts