명령 주입(Command Injection)
우선 명령 주입 그 자체에 대해 살펴보겠습니다. 실제 공격이 어떻게 이루어지는지 쉽게 이해할 수 있도록 몇 가지 사례를 중심으로 다룰 예정입니다. 간단히 복습하자면, 명령 주입 취약점은 다음 함수처럼 사용자 입력값이 운영 체제 명령의 일부로 사용될 때 발생합니다.
let ip = request.params.ipAddress;
system("ping " + ip);
사용자가 IP 주소로 `8.8.8.8`을 입력하면, 실행되는 명령은 `ping 8.8.8.8`이 되어 예상대로 작동합니다. 하지만 사용자가 `8.8.8.8 && ls /etc/`를 입력하면, 이 명령은 단순히 IP 8.8.8.8에 핑을 보내는 것에 그치지 않고 `/etc/` 폴더에 대해 `ls` 명령까지 실행하게 됩니다.
완화 방법
명령 주입 공격의 심각성을 고려할 때, 시스템 명령을 다룰 때 반드시 스스로에게 물어봐야 할 중요한 질문들이 있습니다.
- 정말로 해당 명령을 호출해야 하나요? 가장 좋은 방어책은 시스템 명령을 아예 호출하지 않는 것입니다.
- 시스템 명령을 사용하지 않고도 동일한 효과를 낼 수 있는 라이브러리나 바인딩이 있나요?
- 명령어 자체에 데이터를 포함하는 대신 표준 입력(Standard In)을 통해 데이터를 전달할 수 있나요?
이러한 방법이 불가능하다면, 매개변수화(parameterization)가 중요합니다.
예시
실제 적용 사례를 이해하기 쉽게 다양한 언어로 된 몇 가지 예시를 살펴보겠습니다.
매개변수화를 사용하지 않으면 명령 주입 공격에 취약합니다.
string folder = "/tmp/ && ifconfig";
string cmd = "\"ls " + folder +"\"";
// 보안 취약: `ls`와 `ifconfig` 명령을 모두 실행함
System.Diagnostics.Process.Start("bash", "-c " + cmd);
C# - 보안 적용
명령을 매개변수 목록으로 제공하면 명령이 매개변수화되어 명령 주입으로부터 보호됩니다.
string folder = "/tmp/ && ifconfig";
List<string> arguments = new List<string>() {"-c", "ls", folder};
// 보안 적용: ifconfig 명령을 실행하지 않음
System.Diagnostics.Process.Start("bash", arguments);
Java - 취약함
매개변수화를 사용하지 않으면 명령 주입 공격에 취약합니다.
String folder = "/tmp/ && ifconfig";
// 보안 취약: `ls`와 `ifconfig` 명령을 모두 실행함
ProcessBuilder b = new ProcessBuilder("bash -c ls " + folder);
Process p = pb.start();
Java - 보안 적용
명령을 매개변수 목록으로 제공하면 명령이 매개변수화되어 명령 주입으로부터 보호됩니다.
String folder = "/tmp/ && ifconfig";
// 보안 적용: ifconfig 명령을 실행하지 않음
ProcessBuilder b = new ProcessBuilder("bash", "-c", "ls", folder);
Process p = pb.start();
Javascript - 보안 취약
매개변수화를 사용하지 않으면 명령 주입 공격에 취약합니다.
const { exec } = require("child_process");
const folder = "/tmp/ && ifconfig";
// 보안 취약: `ls`와 `ifconfig` 명령을 모두 실행함
const ls = exec("bash -c ls " + folder, (error, stdout, stderr) => {
console.log(`stdout: ${stdout}`);
});
Javascript - 보안 적용
const { spawn } = require("child_process");
const folder = "/tmp/ && ifconfig";
// 안전함: ifconfig 명령을 실행하지 않음
const ls = spawn("bash", ["-c", "ls", folder]);
ls.stdout.on("data", data => {
console.log(`stdout: ${data}`);
});
Python - 보안 취약
매개변수화를 사용하지 않으면 명령 주입(Command Injection) 공격에 취약합니다.
import subprocess
folder = "/tmp/ && ifconfig"
# 보안 취약: `ls`와 `ifconfig` 명령을 모두 실행함
subprocess.run("bash -c ls " + folder, shell=True)
Python - 보안 적용
명령어를 매개변수 목록으로 제공하면 매개변수화가 이루어져 명령 주입 공격으로부터 보호됩니다.
import subprocess
folder = "/tmp/ && ifconfig"
# 안전함: ifconfig 명령을 실행하지 않음
subprocess.run(["bash", "-c", "ls", folder])
실무에 바로 적용하는 보안 코딩
OWASP Top 10과 같은 소프트웨어 취약점을 이해하고 완화하기 위한 보안 코딩 가이드라인을 살펴보고, 실제 앱 시뮬레이션을 통해 실습할 수 있는 가이드형 교육 미션을 시작해 보세요.