🧷 포맷스트링 삽입 시뮬레이터 KISA #17 · 포맷스트링 삽입

사용자 입력이 포맷 인자로 전달되면 — printf(user_input) — 공격자가 포맷 지정자를 제어합니다. %x/%s 는 스택·메모리를 유출하고 %n 은 메모리에 씁니다. 방어는 단순히 printf("%s", user_input) 입니다.

① 취약: printf(user_input) VULNERABLE

프로그램은 printf(buf)를 호출하고 buf는 당신의 입력입니다. 일반 텍스트는 정상 출력되지만, 포맷 지정자는 전달되지 않은 인자를 printf 가 읽거나 쓰게 만들어 스택을 훑습니다. 아래는 secret과 canary를 포함해 값이 심어진 mock 스택입니다.

② 안전: printf("%s", user_input) SECURE

수정본은 상수 포맷 문자열을 주고 사용자 입력을 데이터 인자로 전달합니다. 입력 안의 지정자는 이제 그냥 글자일 뿐 — 출력될 뿐 해석되지 않습니다. 스택 훑기도, %n 쓰기도 없습니다.

③ 취약 vs 안전 코드 (C)

VULNERABLE
// C — 사용자 입력이 포맷 문자열
void greet(char *name){
    printf(name);            // ← 위험
    fprintf(log, name);      // ← 동일하게 위험
    syslog(LOG_INFO, name);  // ← 동일하게 위험
}
// 입력 "%x %x %x" → 스택 값 유출
// 입력 "%n"       → 메모리 쓰기 → 임의코드 실행 가능
SECURE
// C — 포맷 문자열은 상수, 입력은 데이터
void greet(char *name){
    printf("%s", name);          // 안전
    fprintf(log, "%s", name);    // 안전
    syslog(LOG_INFO, "%s", name);// 안전
}
// 입력 "%x %n" → 그대로 "%x %n" 출력될 뿐
방어 핵심: 신뢰할 수 없는 데이터를 포맷 문자열로 넘기지 말 것 · 항상 상수 포맷을 쓰고 입력은 인자로 전달(printf("%s", x)) · -Wformat -Wformat-security(및 -Werror=format-security)로 컴파일러가 거부하게 할 것 · fprintf/sprintf/snprintf/syslog/vprintf에도 동일 규칙 적용.
⚠️ 교육용 시뮬레이션입니다. printf 와 스택은 페이지 내부 mock 모델이며 실제 메모리 읽기/쓰기나 코드 실행은 없습니다.