CSS 1타 강사 · CONCEPT 23/25
사용자 입력이 system()에 도달하면 왜 데이터가 shell 명령이 될까요?
system()은 문자열을 shell command로 해석합니다. 사용자 입력을 문자열에 붙이면 shell metacharacter가 원래 명령의 구조를 바꿀 수 있습니다. 가장 좋은 방어는 shell을 거치지 않고 고정된 executable과 분리된 argument API를 사용하는 것입니다.
전문 용어를 보기 전에 이 장면부터 잡으세요
검색어를 직원에게 전달했는데 직원이 검색어 안의 문장을 새 업무 지시로 실행하는 상황입니다.
데이터가 shell 문법으로 다시 해석되는 순간
00
한 장면으로 문제를 시작해 봅시다
이번 페이지에서 끝까지 따라갈 예시
system('ping -c 1 ' + host) 형태에서 attacker가 host 뒤에 shell metacharacter와 새 명령을 붙이는 상황을 분석합니다.
비유와 실제 시스템을 정확히 연결하기
- 이름을 적는 칸원래는 data여야 하는 사용자 입력 `name`
- 문장 속 세미콜론을 새 지시로 읽는 직원shell parser
- 직원에게 문장 전체를 전달하는 확성기`system(cmd)`
이 예시에서 사람·장치·데이터·화살표를 먼저 찾습니다. 아직 용어를 완벽히 몰라도 “누가 무엇을 가지고, 어떤 처리를 거쳐, 무엇이 달라지는가”를 말할 수 있으면 출발점은 충분합니다.
01
긴 이름을 작은 용어로 분리하기
한 제목에 여러 단어가 들어 있어도 같은 기능을 뜻하지 않습니다. 아래 카드를 하나씩 읽고 각 용어의 대상과 역할을 따로 잡으세요.
system()과 shell command injection
system()은 문자열을 운영체제 shell에 명령으로 전달한다. 사용자 입력을 그 문자열에 직접 붙이면 세미콜론, 파이프, 명령 치환 같은 shell metacharacter가 데이터가 아니라 추가 명령으로 해석될 수 있다. 이것이 command injection이다. 가능하면 shell을 거치지 않고 허용된 프로그램과 argument를 분리해 실행해야 한다.
TERMS FROM ZERO
system()과 shell command injection 핵심 용어
아래 단어는 이미 안다고 가정하지 않습니다. 먼저 쉬운 뜻을 읽고, 본문에서 같은 단어가 나오면 이 정의로 다시 바꾸어 읽으세요.
Shell
명령 문자열을 해석해 program을 실행하고 pipe·redirection 같은 문법을 처리하는 command interpreter입니다.
`system()`
문자열을 shell에 넘겨 command로 실행하는 C library 함수입니다.
Metacharacter
`;`, `|`, `&&`처럼 shell에서 단순 글자가 아니라 문법 역할을 하는 문자입니다.
Command injection
공격자 data가 shell syntax로 해석되어 의도하지 않은 command를 실행하게 되는 취약점입니다.
02
실제 시스템에서는 이 순서로 움직입니다
예시를 단계별로 해체하기
- 1단계Attacker-controlled string이 application에 들어옵니다.
- 2단계프로그램이 고정 명령과 입력을 하나의 command string으로 연결합니다.
- 3단계system()이 문자열 전체를 shell parser에 전달합니다.
- 4단계Semicolon·substitution·redirection 같은 문법이 입력 일부를 새 명령으로 해석하게 합니다.
- 5단계프로그램 권한으로 arbitrary command execution이 발생할 수 있습니다.
- 6단계근본 방어는 shell을 제거하고 고정 executable과 분리된 argument API를 사용하는 것입니다.
이 단계들은 시험 답안에서 원인과 결과가 빠지지 않도록 만든 설명 순서입니다.
손으로 따라가는 초보 예제
이름 `Alice; whoami`가 두 개의 명령이 되는 순간
프로그램이 `sprintf(cmd, "echo Willkommen %s", name); system(cmd);`를 실행하고 사용자가 이름으로 `Alice; whoami`를 입력했다고 해 봅시다.
- 1단계정상 입력 `Alice`라면 만들어지는 문자열은 `echo Willkommen Alice`이고 shell은 한 명령으로 해석합니다.
- 2단계공격 입력 `Alice; whoami`를 연결하면 문자열은 `echo Willkommen Alice; whoami`가 됩니다.
- 3단계application은 이를 단순 문자열로 만들었지만 `system()`은 전체 문자열을 shell에 넘깁니다.
- 4단계shell은 `;`를 첫 명령의 끝으로 읽어 `echo Willkommen Alice`와 `whoami`라는 두 명령을 차례로 실행합니다.
- 5단계두 번째 명령은 공격자가 아니라 취약한 프로그램의 권한으로 실행되므로 service account나 root 권한이면 영향이 커집니다.
- 6단계`snprintf`는 길이 초과만 줄일 뿐 `;`의 shell 의미를 없애지 않습니다. 근본 방어는 직접 출력하거나 shell을 거치지 않는 argument-vector API로 고정 executable과 인자를 분리하는 것입니다.
그래서 무엇을 배웠나? Command injection은 위험한 글자가 존재해서가 아니라, 공격자 data가 shell이라는 두 번째 해석기(parser)에 도달해 command syntax로 재해석되기 때문에 생깁니다.
03
관련 개념도 하나씩 따로 이해하기
system()과 shell command injection
비유에서 실제 시스템으로 옮겨 보기
먼저 떠올릴 장면 · 배달 주소 칸에 ‘서울; 창고 문도 열어라’라고 썼는데 프로그램이 세미콜론 뒤 문장까지 새 업무 지시로 처리하는 상황이다.
정확한 뜻 · system()은 문자열을 운영체제 shell에 명령으로 전달한다. 사용자 입력을 그 문자열에 직접 붙이면 세미콜론, 파이프, 명령 치환 같은 shell metacharacter가 데이터가 아니라 추가 명령으로 해석될 수 있다. 이것이 command injection이다. 가능하면 shell을 거치지 않고 허용된 프로그램과 argument를 분리해 실행해야 한다.
- 1단계외부 입력 source를 찾는다.
- 2단계입력이 system, popen, shell=True 같은 command sink에 도달하는지 본다.
- 3단계Shell 문법 문자가 명령 구조를 바꿀 수 있는지 확인한다.
- 4단계Shell 없는 process API와 고정 allowlist argument를 사용한다.
- 5단계실행 계정 권한을 최소화한다.
04
강의 스크립트 원본과 연결하기
Code injection과 unsafe legacy functionality를 보여 주는 대표 슬라이드입니다. 먼저 위의 초보 설명을 읽고, 원본에서는 같은 개념이 어떤 기호와 독일어·영어 용어로 표현되는지 확인하세요.
Vorlesung/11_software-security 10.pdf · p.16, p.30 · Code injection과 unsafe legacy functionality11_software-security 10.pdf· p.16, p.30
05
시험 함정과 답안에 적용하기
- system()과 shell command injection · 일부 문자만 escape하는 방식은 shell 종류와 인코딩에 따라 우회될 수 있으므로 구조적으로 shell을 제거하는 편이 안전하다.
서술형 답안 골격
attacker input → string concatenation → shell parsing → command execution impact → shell 제거 순서로 답합니다.
정의 → 등장 주체 또는 입력 → 작동 순서 → 보안 효과 → 조건과 한계 순서로 쓰고, 위 단계별 예시에서 필요한 문장을 골라 붙이세요.
책을 덮고 “사용자 입력이 system()에 도달하면 왜 데이터가 shell 명령이 될까요?”에 대해 핵심 용어 두 개, 작동 단계 세 개, 대표 함정 하나를 말해 보세요.
다음 개념으로 넘어가기 전 확인
- `Alice; whoami`가 shell에서 몇 개의 명령으로 해석되는지 설명할 수 있나요?
- `snprintf`가 buffer overflow는 완화해도 command injection을 막지 못하는 이유는 무엇인가요?
- blacklist보다 shell을 제거하는 설계가 강한 이유를 말할 수 있나요?