소프트웨어 개발 보안 취약점 - 버퍼 오버플로, 포맷 스트링, 경로 조작
선수학습(1개)
요약
프로그래밍 결함으로 발생하는 대표적인 보안 취약점을 정리합니다. 버퍼 오버플로(스택·힙), 포맷 스트링, 정수 오버플로, 경로 조작의 원리와 대응 코딩 패턴, 시큐어 코딩 7대 원칙까지 정보처리기사 실기 대비용으로 살펴봅니다.
소프트웨어 개발 보안 취약점이란? 쌩기초
소프트웨어 개발 보안 취약점은 프로그래밍 과정의 실수로 코드에 남는 보안 결함입니다. 시스템 공격이 "운영 환경의 허점"을 노린다면, 소프트웨어 취약점은 "코드 자체의 허점"을 노립니다. 대표 분류 체계는 다음과 같습니다.
- OWASP: 웹 애플리케이션 보안 프로젝트. "OWASP Top 10" 같은 대표 취약점 목록을 발간
- CWE(Common Weakness Enumeration): 소프트웨어 취약점 유형을 번호로 목록화한 표준 (예: CWE-120 버퍼 오버플로)
- 국내 시큐어 코딩 가이드: 행정안전부·KISA가 제시한 7대 원칙 (본 문서 마지막 섹션)
| 취약점 | 원인 | 결과 | 핵심 대응 |
|---|---|---|---|
| 버퍼 오버플로 | 버퍼 경계 검사 누락 | 메모리 덮어쓰기, 임의 코드 실행 | 안전한 문자열 함수, Canary·ASLR·DEP |
| 포맷 스트링 | 사용자 입력을 형식 문자열로 사용 | 메모리 읽기/쓰기, 정보 유출 | 형식 문자열을 상수로 고정 |
| 정수 오버플로 | 자료형 표현 범위 초과 | 음수 전환, 작은 할당 → 힙 오버플로 | 연산 전후 범위 검사, 큰 타입 사용 |
| 경로 조작 | 사용자 입력을 파일 경로로 그대로 사용 | 의도하지 않은 파일 접근 | 입력 검증, 화이트리스트, canonical path 비교 |
버퍼 오버플로 (Buffer Overflow) 기초
버퍼 오버플로(BoF) 는 프로그램이 버퍼 크기를 넘어서는 데이터를 기록해 인접 메모리를 덮어쓰는 취약점입니다. 고전적이면서도 가장 위험한 취약점 중 하나로, 위치(스택·힙)에 따라 두 종류로 나뉩니다.
스택 버퍼 오버플로 기초
스택 영역에 할당된 지역 변수 버퍼가 넘치는 경우입니다. 스택 프레임에는 함수의 리턴 주소가 함께 저장되어 있어, 공격자가 오버플로를 이용해 리턴 주소를 자신의 악성 코드(셸코드) 주소로 덮어쓰면 임의 코드 실행이 가능합니다.
위험한 C 표준 함수 예:
strcpy(dst, src)- 길이 검사 없이 복사gets(buf)- 길이 검사 없이 표준 입력 받음sprintf(buf, fmt, ...)- 포맷 결과 길이 무제한
안전한 대체 함수:
strncpy(dst, src, n)- 최대 n 바이트까지만 복사fgets(buf, n, stdin)- 최대 n-1 바이트까지만 읽음snprintf(buf, n, fmt, ...)- 최대 n-1 바이트까지만 기록
힙 버퍼 오버플로 기초
malloc()·new로 할당한 힙 영역 버퍼가 넘치는 경우입니다. 스택만큼 "리턴 주소"가 명확하진 않지만, 인접한 할당 메타데이터나 함수 포인터를 덮어써 실행 흐름을 가로챌 수 있습니다.
버퍼 오버플로 대응 기초
- 코드 레벨: 안전한 문자열 함수 사용, 입력 길이 검증, 경계 검사 로직 추가
- 컴파일러·런타임:
- Stack Canary: 함수 호출 시 스택 프레임에 랜덤 값을 심고, 리턴 직전에 변조 여부 검사
- DEP(Data Execution Prevention) / NX bit: 데이터 영역(스택·힙)의 실행 권한 제거해 셸코드 실행 차단
- ASLR(Address Space Layout Randomization): 메모리 영역 주소를 실행 시마다 랜덤화해 셸코드 주소를 맞히기 어렵게 함
- 언어 선택: 경계 검사가 내장된 언어(Rust·Go·Java 등) 사용도 근본 대응
포맷 스트링 공격 (Format String Attack) 기초
포맷 스트링 취약점은 printf·fprintf·sprintf 같은 형식 문자열 함수에 사용자 입력을 그대로 넘길 때 발생합니다. 공격자는 형식 지정자(%s·%x·%n)를 문자열에 포함시켜 메모리를 읽거나 쓰게 할 수 있습니다.
위험한 패턴:
| 형식 지정자 | 공격 효과 |
|---|---|
%x | 스택 메모리를 16진수로 출력 → 메모리 정보 유출 |
%s | 스택에서 포인터를 꺼내 그 주소의 문자열 출력 → 크래시 또는 유출 |
%n | 지금까지 출력한 바이트 수를 해당 주소에 기록 → 메모리 쓰기 |
%n이 가장 위험한데, 공격자가 원하는 주소에 원하는 값을 기록할 수 있어 임의 코드 실행까지 연결될 수 있습니다.
포맷 스트링 대응 기초
- 형식 문자열은 반드시 상수로 고정. 사용자 입력은 인자로만 전달
- 정적 분석 도구로
printf(user_input)패턴 탐지 (-Wformat-security경고) %n비활성화 옵션이 있는 런타임 사용 (일부 리눅스 배포판 기본값)
정수 오버플로 (Integer Overflow) 기초
정수 오버플로는 정수형 변수가 자료형의 최대값(또는 최소값)을 넘어 예상과 다른 값으로 뒤바뀌는 현상입니다. 그 자체로는 수학 오류지만, 그 값이 메모리 할당 크기로 사용되면 힙 오버플로로 이어집니다.
전형적 패턴 (C):
| 유형 | 설명 |
|---|---|
| 부호 있는 오버플로 (Signed Overflow) | INT_MAX를 넘으면 음수로 랩어라운드. C 표준은 "정의되지 않은 동작"으로 취급 |
| 부호 없는 오버플로 (Unsigned Overflow) | UINT_MAX를 넘으면 0으로 랩어라운드 (정의된 동작이지만 논리 오류 유발) |
| 정수 언더플로 (Underflow) | 0에서 -1로 갈 때 부호 없는 타입은 아주 큰 값이 됨 |
| 부호 변환 (Sign Conversion) | 음수를 부호 없는 타입으로 넘기면 매우 큰 양수가 됨 |
정수 오버플로 대응 기초
- 연산 전에 범위 검사 (
if (count > MAX_ALLOWED) return;) - 가능한 한 큰 타입 사용 (
size_t·int64_t) - 언어·라이브러리가 제공하는 안전 산술 함수 사용 (C11
ckd_add()등)
경로 조작 기초
경로 조작(Path Manipulation, Path Traversal, Directory Traversal, 디렉터리 트래버설) 은 사용자 입력을 파일 경로로 그대로 사용할 때, 공격자가 ../ 같은 상위 디렉터리 이동 시퀀스를 삽입해 의도하지 않은 파일에 접근하는 취약점입니다. 일반 애플리케이션에서는 "경로 조작", 웹 환경에서는 "디렉터리 트래버설"로 부르지만 본질은 같습니다.
일반 애플리케이션의 위험한 패턴
웹 요청의 위험한 패턴
서버가 단순히 /var/www/files/ + file 파라미터를 이어붙이면 /var/www/files/../../etc/passwd = /etc/passwd가 되어 시스템 계정 목록이 노출됩니다.

우회 기법
- URL 인코딩:
..%2F..%2Fetc%2Fpasswd - 이중 URL 인코딩:
%252e%252e%252f - 유니코드 치환:
../ - NULL 바이트 삽입:
../../etc/passwd%00.jpg
경로 조작 대응 기초
- 입력 검증:
..·/·\·NULL 바이트 등 금지 문자 필터링 - 화이트리스트: 허용 파일 목록(또는 다운로드용 파일 ID)과 정확히 일치하는 입력만 허용
- Canonical Path 비교: 실제 접근 직전 경로를 정규화(
realpath·getCanonicalPath)한 뒤, 허용된 기준 디렉터리의 하위인지 검사 - Chroot / 샌드박스: 프로세스가 접근 가능한 루트 자체를 제한
시큐어 코딩 7대 원칙 심화
행정안전부·KISA의 소프트웨어 개발보안 가이드는 취약점을 7개 영역으로 분류하고 각 영역의 코딩 원칙을 제시합니다. 정보처리기사 실기에서 항목 암기형으로 자주 나옵니다.
| 원칙 | 핵심 | 대표 취약점 |
|---|---|---|
| 입력 데이터 검증·표현 | 입력을 신뢰하지 말 것 | SQL Injection, XSS, 버퍼 오버플로, 경로 조작 |
| 보안 기능 | 인증·권한·암호를 올바르게 구현 | 부적절한 인가, 하드코딩된 비밀번호 |
| 시간 및 상태 | 동시성·순서 문제 관리 | 레이스 컨디션(TOCTOU), 세션 고정 |
| 에러 처리 | 오류 메시지·예외 노출 방지 | 스택 트레이스 노출, 예외 처리 누락 |
| 코드 오류 | 런타임 오류 유발 코드 방지 | Null 참조, 정수 오버플로, 메모리 누수 |
| 캡슐화 | 객체·데이터 은닉 | 제어되지 않은 외부 접근, 디버그 코드 잔존 |
| API 오용 | 표준 API를 의도된 방식으로 사용 | 위험한 문자열 함수(strcpy), 금지된 API 사용 |
본 페이지에서 다룬 버퍼 오버플로는 "입력 데이터 검증" + "API 오용", 포맷 스트링은 "입력 데이터 검증", 정수 오버플로는 "코드 오류", 경로 조작은 "입력 데이터 검증"에 해당합니다. 원칙과 취약점을 연결해서 외우면 단답형·서술형에 모두 대응할 수 있습니다.
정보처리기사 실기 대비 문제
해당 영역 기출 문제가 축적되는 대로 연결합니다. 현재는 본문 내용만 참고하세요.