Code 감사
문제
독일어 원문
Identifizieren Sie den Fehler in Zeile 19 (`if (age - 21 < 0)`) und erklären Sie Auswirkung und Behebung.
한국어 해석
19행 `if (age - 21 < 0)`의 오류·영향·수정을 설명하시오.
실제 시험 Listing 1 보기
4 void build_message(char *name, char *dest) {
5 sprintf(dest, "echo Willkommen %s", name);
6 }
8 int main(void) {
9 char name[16];
10 char cmd[64];
11 unsigned int age;
14 fgets(name, 15, stdin);
17 scanf("%u", &age);
19 if (age - 21 < 0) {
20 printf("Zugriff verweigert\n");
21 return 1;
24 build_message(name, cmd);
25 system(cmd);
27 return 0;
28 }
출처: 실제 시험지 p17. 두 오류는 line 19의 unsigned underflow와 line 25의 command injection입니다.
실제 시험 코드 취약 줄 하이라이터
실제 WiSe 25/26 시험 코드에서 취약한 줄을 선택하고 영향과 수정법을 말해 보세요.
단계별 힌트
막혔을 때만 한 단계씩 여세요. 정답을 바로 읽는 것보다 기억을 꺼내는 시간이 중요합니다.
- 첫 힌트: 0 아래로 내려갈 수 없는 주행거리계에서 0-1이 아주 큰 숫자로 돌아가는 것과 같다.
- line 19와 unsigned type line 11을 연결한다.
- underflow/wraparound와 access-control bypass를 쓴다.
- `age < 21` 비교로 고친다.
- 함정: 현재 구체적 입력 길이에서 line 5 sprintf만 답하고 핵심 logic bug를 놓치지 않는다.
- 후속 점검: unsigned 0에서 1을 빼면 C에서 어떤 값이 되는가?
채점 기준으로 내 답안 점검하기
- line 19와 unsigned type line 11을 연결한다.
- underflow/wraparound와 access-control bypass를 쓴다.
- `age < 21` 비교로 고친다.
답안 슬롯 자가 점검 — 실제로 말하거나 쓴 항목만 체크하세요.
0/3 slots
정답과 핵심 해설 확인하기
`age`가 unsigned라 21보다 작으면 `age-21`이 큰 양수로 wraparound하고 21 이상이면 원래부터 0 이상이므로 `<0`은 모든 입력에서 항상 false다. 따라서 접근 거부가 우회된다. `scanf` 성공·범위를 확인하고 빼기 전에 `if (age < 21)`로 비교한다.
- line 19와 unsigned type line 11을 연결한다.
- underflow/wraparound와 access-control bypass를 쓴다.
- `age < 21` 비교로 고친다.
개념부터 다시 보는 상세 풀이
BEGINNER LESSON
Unsigned Underflow: `age - 21 < 0`이 어린 사용자를 막지 못하는 이유
ZERO-BASE START
정말 아무것도 모른다고 가정하고 시작합니다
전문 용어를 알고 있다고 가정하지 않습니다. 먼저 일상적인 장면을 보고, 그 장면의 사람과 행동에 실제 보안 용어를 하나씩 붙인 뒤, 시스템에서 일어나는 순서를 따라갑니다.
기초 개념 01
C의 buffer와 length 없는 sprintf
1타 강사식 시작: 이름은 잠시 가리고 장면부터 봅시다
10칸짜리 서랍에 30개 물건을 밀어 넣으면 옆 서랍의 물건까지 밀어내는 것과 같다. C는 자동으로 벽을 만들어 막아 주지 않는다.
지금은 이 비유를 완벽히 외울 필요가 없습니다. 누가 무엇을 가지고 있고, 무엇을 하려 하며, 어느 지점에서 문제가 생기는지만 찾으면 됩니다.
이제 실제 용어를 하나씩 붙여 봅시다
C의 char array는 정해진 크기의 연속된 memory 공간이다. Buffer에 들어갈 문자열 길이를 확인하지 않고 sprintf로 쓰면 경계를 넘어 인접 memory를 덮을 수 있다. 이를 buffer overflow라고 하며 crash, data corruption, 경우에 따라 code execution으로 이어질 수 있다. snprintf는 최대 길이를 받지만 반환값과 null termination 조건도 확인해야 한다.
TERMS FROM ZERO
전문 용어를 한 단어씩 풀기
아래 단어는 이미 안다고 가정하지 않습니다. 먼저 쉬운 뜻을 읽고, 본문에서 같은 단어가 나오면 이 정의로 다시 바꾸어 읽으세요.
Buffer
프로그램이 byte나 문자를 잠시 저장하도록 확보한 연속 memory 공간입니다.
Boundary / Bounds
Buffer가 합법적으로 사용할 수 있는 시작과 끝 범위입니다.
Null terminator
C 문자열의 끝을 표시하는 값 `\0`으로, 저장 공간 1바이트를 차지합니다.
Stack frame
한 함수 호출의 local variable, 저장된 register, return 관련 정보가 놓이는 stack 영역입니다.
Buffer overflow
확보한 buffer 범위를 넘어 write하여 인접 memory를 손상시키는 오류입니다.
프로그램이나 프로토콜 안에서는 다음 순서로 움직입니다.
- 목적지 buffer 크기를 확인한다.
- 공격자가 제어하는 문자열의 최대 길이를 확인한다.
- Format 후 필요한 길이가 buffer보다 큰지 계산한다.
- Bounded API와 반환값 검사, 명시적 길이 검증을 적용한다.
왜 여기서 많이 틀릴까요?
sprintf의 format string이 고정되어 있어도 출력 전체 길이가 제한되지 않으면 overflow가 생길 수 있다.
조건을 생략하거나 서로 다른 기능을 같은 것으로 취급했는지 확인하세요. 정답 문장을 외우는 것보다 틀린 이유를 말할 수 있어야 변형 문제를 풀 수 있습니다.
핵심부터 말하면 `age`가 unsigned이면 21보다 작은 값에서는 뺄셈이 큰 양수로 wraparound하고 21 이상에서는 원래부터 0 이상이므로 조건은 모든 입력에서 항상 거짓입니다. `scanf` 성공을 확인하고 뺄셈 전에 `age < 21`로 비교해야 합니다.
이 글에서 익힐 것
signed와 unsigned의 표현 범위를 구분한다.
숫자 예시로 wraparound를 따라간다.
오류·영향·수정을 한 묶음으로 답한다.
이 문제가 어려운 이유
수학에서는 18-21=-3이므로 조건이 참입니다. 하지만 C의 연산은 변수 type의 규칙을 따르며 unsigned 값은 음수를 표현하지 않습니다.
예제로 확인하기
상황 설정
설명을 단순화하기 위해 8-bit unsigned 값의 범위가 0..255라고 가정하고 `age = 18`을 넣습니다.
풀이 순서
수학 계산은 18-21=-3입니다.
8-bit unsigned에는 -3이 없으므로 modulo 256 규칙으로 253으로 wraparound합니다.
프로그램이 검사하는 식은 사실상 `253 < 0`이 됩니다.
unsigned 값은 0보다 작을 수 없으므로 조건은 거짓이고, 18세 사용자가 거부 분기로 들어가지 않을 수 있습니다.
실제 type 폭이 더 크면 wrap된 정확한 값은 달라져도 ‘매우 큰 양수’가 된다는 논리는 같습니다. 반대로 age가 21 이상이면 뺄셈 결과가 정상적인 0 이상 값이므로 전체 조건은 모든 unsigned age에서 false입니다.
안전한 비교는 뺄셈을 만들지 않는 `if (age < 21)`입니다.
해설
오류는 unsigned underflow/wraparound, 영향은 연령 기반 access-control bypass, 수정은 빼기 전 직접 범위 비교입니다.
정답까지 사고 과정
19행만 보지 말고 age가 선언된 11행의 type을 확인합니다.
경계값 18 또는 0을 넣어 식을 실제로 계산합니다.
21 미만은 wraparound, 21 이상은 정상적인 0 이상이므로 조건이 모든 값에서 false임을 일반화합니다.
보안 영향을 access-control bypass로 연결합니다.
수정은 `scanf` 반환값 확인, 입력 range validation, `age < 21` 직접 비교로 씁니다.
시험장에서는 이렇게 쓰기
최소 답안
Da `age` unsigned ist, ist `age - 21 < 0` für alle möglichen Werte falsch: unter 21 entsteht ein Wraparound, ab 21 ein nichtnegatives Ergebnis.
안전한 두 문장 답안
Dadurch kann die Altersprüfung umgangen werden. Der Rückgabewert von `scanf` muss geprüft und der Vergleich vor der Subtraktion ausgeführt werden, z. B. mit `if (age < 21)`.
채점 포인트
line 11의 unsigned type과 line 19를 연결했다.
underflow 또는 wraparound를 썼다.
access-control bypass 영향을 썼다.
`age < 21` 수정을 제시했다.
자주 틀리는 지점
수학 계산만 하고 C type 규칙을 무시하기
오류 이름만 쓰고 실제 조건 결과와 영향을 설명하지 않기
관련 없는 `sprintf` 문제만 답하기
한 줄로 기억하기
unsigned는 0 아래로 내려가지 않고 최대값 쪽으로 돌아간다.
스스로 확인하기
8-bit unsigned에서 0-1은 얼마인가?
왜 `age < 21`이 `age - 21 < 0`보다 안전한가?
AI 구두시험용 프롬프트
한 문항만 풀어라. 먼저 정답을 열지 말고 90초 안에 답안을 말한 뒤, css-ws2025-26-software-c-001의 채점 프레임으로 스스로 채점하라. 문제: 19행 `if (age - 21 < 0)`의 오류·영향·수정을 설명하시오.
학습 기록