CSS 1타 강사 · CONCEPT 22/25
sprintf는 왜 출력 형식이 맞아도 destination buffer를 넘칠 수 있을까요?
sprintf는 결과 길이를 목적 buffer 크기에 맞춰 제한하지 않습니다. snprintf처럼 최대 크기를 전달하고 return value로 truncation을 확인하거나 동적 크기 계산을 사용해야 합니다.
전문 용어를 보기 전에 이 장면부터 잡으세요
주소 라벨 프린터에 종이 폭을 알려 주지 않고 무한히 긴 주소를 인쇄시키는 것과 같습니다.
출력 문자열보다 목적 buffer가 작을 수 있습니다
00
한 장면으로 문제를 시작해 봅시다
이번 페이지에서 끝까지 따라갈 예시
char out[16]에 사용자 이름과 고정 문구를 sprintf(out, 'Hello %s', name)로 작성하는 코드를 검사합니다.
비유와 실제 시스템을 정확히 연결하기
- 폭이 16칸인 라벨`out[16]` destination buffer
- 미리 인쇄된 `Hello `format string의 고정 출력 6바이트
- 라벨 폭을 모르는 프린터destination 크기를 인자로 받지 않는 `sprintf`
이 예시에서 사람·장치·데이터·화살표를 먼저 찾습니다. 아직 용어를 완벽히 몰라도 “누가 무엇을 가지고, 어떤 처리를 거쳐, 무엇이 달라지는가”를 말할 수 있으면 출발점은 충분합니다.
01
긴 이름을 작은 용어로 분리하기
한 제목에 여러 단어가 들어 있어도 같은 기능을 뜻하지 않습니다. 아래 카드를 하나씩 읽고 각 용어의 대상과 역할을 따로 잡으세요.
C의 buffer와 length 없는 sprintf
C의 char array는 정해진 크기의 연속된 memory 공간이다. Buffer에 들어갈 문자열 길이를 확인하지 않고 sprintf로 쓰면 경계를 넘어 인접 memory를 덮을 수 있다. 이를 buffer overflow라고 하며 crash, data corruption, 경우에 따라 code execution으로 이어질 수 있다. snprintf는 최대 길이를 받지만 반환값과 null termination 조건도 확인해야 한다.
TERMS FROM ZERO
C의 buffer와 length 없는 sprintf 핵심 용어
아래 단어는 이미 안다고 가정하지 않습니다. 먼저 쉬운 뜻을 읽고, 본문에서 같은 단어가 나오면 이 정의로 다시 바꾸어 읽으세요.
Buffer
프로그램이 byte나 문자를 잠시 저장하도록 확보한 연속 memory 공간입니다.
Boundary / Bounds
Buffer가 합법적으로 사용할 수 있는 시작과 끝 범위입니다.
Null terminator
C 문자열의 끝을 표시하는 값 `\0`으로, 저장 공간 1바이트를 차지합니다.
Stack frame
한 함수 호출의 local variable, 저장된 register, return 관련 정보가 놓이는 stack 영역입니다.
Buffer overflow
확보한 buffer 범위를 넘어 write하여 인접 memory를 손상시키는 오류입니다.
02
실제 시스템에서는 이 순서로 움직입니다
예시를 단계별로 해체하기
- 1단계Destination buffer가 저장할 수 있는 총 byte 수를 확인합니다.
- 2단계고정 문자열·사용자 입력·마지막 null terminator의 최대 길이를 더합니다.
- 3단계sprintf는 destination 크기를 전달받지 않으므로 긴 결과를 계속 씁니다.
- 4단계인접 memory가 덮여 crash나 exploit 가능성이 생깁니다.
- 5단계snprintf에 실제 buffer size를 전달하고 return value가 size 이상인지 확인합니다.
- 6단계가능하면 필요한 길이를 계산해 동적으로 할당하거나 더 안전한 string abstraction을 사용합니다.
이 단계들은 시험 답안에서 원인과 결과가 빠지지 않도록 만든 설명 순서입니다.
손으로 따라가는 초보 예제
`Hello ` 여섯 글자도 buffer 자리를 차지합니다
`char out[16]; sprintf(out, "Hello %s", name);`에서 `name = "Christopher"`라고 해 봅시다. 초보자는 사용자 이름 길이만 세기 쉽지만 결과 문자열 전체와 마지막 null terminator를 세어야 합니다.
- 1단계`Hello `는 H, e, l, l, o, 공백으로 이미 6바이트를 사용합니다.
- 2단계`Christopher`는 11바이트이므로 화면에 보이는 내용만 합쳐도 6 + 11 = 17바이트입니다.
- 3단계C 문자열 끝을 표시하는 `\0`도 1바이트 필요하므로 실제 필요한 공간은 18바이트입니다.
- 4단계`out`은 16바이트뿐이므로 2바이트가 경계를 넘어 인접 memory에 쓰입니다. `sprintf`는 `out`의 크기를 모르므로 스스로 중단할 수 없습니다.
- 5단계`snprintf(out, sizeof out, "Hello %s", name)`는 최대 크기를 전달하지만, 반환값이 `sizeof out` 이상이면 잘렸다는 뜻이므로 그 결과도 처리해야 합니다.
- 6단계가장 안전한 설계는 필요한 길이를 먼저 계산하거나 크기를 관리하는 문자열 abstraction을 쓰고, truncation이 프로그램 의미를 깨지 않는지도 확인하는 것입니다.
그래서 무엇을 배웠나? buffer 계산식은 ‘고정 출력 길이 + 변하는 입력의 최대 길이 + null terminator 1’입니다. 함수 이름만 `snprintf`로 바꾸는 것이 아니라 반환값과 잘림의 의미까지 검사해야 합니다.
03
관련 개념도 하나씩 따로 이해하기
C의 buffer와 length 없는 sprintf
비유에서 실제 시스템으로 옮겨 보기
먼저 떠올릴 장면 · 10칸짜리 서랍에 30개 물건을 밀어 넣으면 옆 서랍의 물건까지 밀어내는 것과 같다. C는 자동으로 벽을 만들어 막아 주지 않는다.
정확한 뜻 · C의 char array는 정해진 크기의 연속된 memory 공간이다. Buffer에 들어갈 문자열 길이를 확인하지 않고 sprintf로 쓰면 경계를 넘어 인접 memory를 덮을 수 있다. 이를 buffer overflow라고 하며 crash, data corruption, 경우에 따라 code execution으로 이어질 수 있다. snprintf는 최대 길이를 받지만 반환값과 null termination 조건도 확인해야 한다.
- 1단계목적지 buffer 크기를 확인한다.
- 2단계공격자가 제어하는 문자열의 최대 길이를 확인한다.
- 3단계Format 후 필요한 길이가 buffer보다 큰지 계산한다.
- 4단계Bounded API와 반환값 검사, 명시적 길이 검증을 적용한다.
04
강의 스크립트 원본과 연결하기
Unsafe language features와 fortified library alternatives를 보여 주는 대표 슬라이드입니다. 먼저 위의 초보 설명을 읽고, 원본에서는 같은 개념이 어떤 기호와 독일어·영어 용어로 표현되는지 확인하세요.
Vorlesung/11_software-security 10.pdf · p.19, p.30 · Unsafe language features와 fortified library alternatives11_software-security 10.pdf· p.19, p.30
05
시험 함정과 답안에 적용하기
- C의 buffer와 length 없는 sprintf · sprintf의 format string이 고정되어 있어도 출력 전체 길이가 제한되지 않으면 overflow가 생길 수 있다.
서술형 답안 골격
취약 호출, buffer 크기, 가능한 초과 길이, bounded API와 return-value check를 씁니다.
정의 → 등장 주체 또는 입력 → 작동 순서 → 보안 효과 → 조건과 한계 순서로 쓰고, 위 단계별 예시에서 필요한 문장을 골라 붙이세요.
책을 덮고 “sprintf는 왜 출력 형식이 맞아도 destination buffer를 넘칠 수 있을까요?”에 대해 핵심 용어 두 개, 작동 단계 세 개, 대표 함정 하나를 말해 보세요.
다음 개념으로 넘어가기 전 확인
- `out[16]`에 `Hello `를 붙일 때 이름에 쓸 수 있는 최대 바이트 수를 계산할 수 있나요?
- `sprintf`가 destination 크기를 알 수 없는 이유를 함수 인자 관점에서 말할 수 있나요?
- `snprintf`의 반환값을 확인하지 않으면 어떤 문제를 놓칠 수 있나요?