적절한 검증절차를 거치지 않은 사용자 입력값이 운영체제 명령어의 일부 또는 전부로 구성되어 실행되는 경우, 의도하지 않은 시스템 명령어가 실행되어 부적절하게 권한이 변경되거나 시스템 동작 및 운영에 악영향을 미칠 수 있다.
일반적으로 명령어 라인의 파라미터나 스트림 입력 등 외부 입력을 사용하여 시스템 명령어를 생성하는 프로그램이 많이 있다. 하지만 이러한 경우 외부 입력 문자열은 신뢰할 수 없기 때문에 적절한 처리를 해주지 않으면, 공격자가 원하는 명령어 실행이 가능하게 된다.
웹 인터페이스로 서버 내부로 시스템 명령어를 전달시키지 않도록 응용프로그램을 구성
외부에서 전달되는 값을 검증 없이 시스템 내부 명령어로 사용하지 않는다.
외부 입력에 따라 명령어 를 생성하거나 선택이 필요한 경우에는 명령어 생성에 필요한 값 들을 미리 지정해 놓고 외부 입력에 따라 선택하여 사용한다.
public static void main(String args[]) throws IOException {
// 해당 프로그램에서 실행할 프로그램을 제한하고 있지 않아 파라미터로 전달되는 모든 프로그램이
실행될 수 있다.
String cmd = args[0];
Process ps = null;
try {
ps = Runtime.getRuntime().exec(cmd);
...
Runtime.getRuntime().exec()명령어로 프로그램을 실행하며, 외부에서 전달 되는 인자값은 명령어의 생성에 사용된다.
그러나 해당 프로그램에서 실행할 프로그램을 제한하지 않고 있기 때문에 외부의 공격자는 가능한 모든 프로그램을 실행시킬 수 있다.
public static void main(String args[]) throws IOException {
// 해당 어플리케이션에서 실행할 수 있는 프로그램을 노트패드와 계산기로 제한하고 있다.
List<String> allowedCommands = new ArrayList<String>(); “
allowedCommands.add("notepad"); allowedCommands.add("calc");
String cmd = args[0];
if (!allowedCommands.contains(cmd)) {
System.err.println("허용되지 않은 명령어입니다.");
return;
}
Process ps = null; try {
ps = Runtime.getRuntime().exec(cmd);
......
다음의 예제와 같이 미리 정의된 파라미터의 배열을 만들어 놓고,
외부의 입력에 따라 적절한 파라미터를 선택하도록 하여, 외부의 부적절한 입력이 명령어로 사용될 가능성을 배제하여야 한다.
//외부로부터 입력받은 값을 검증 없이 사용할 경우 안전하지 않다.
String date = request.getParameter("date");
String command = new String("cmd.exe /c backuplog.bat");
Runtime.getRuntime().exec(command + date);
아래 코드는 외부입력값을 검증하지 않고 그대로 명령어로 실행하기 때문에 공격자의 입력에 따라 의도하지 않은 명령어가 실행될 수 있다
String date = request.getParameter("date");
String command = new String("cmd.exe /c backuplog.bat");
//외부로부터 입력 받은 값을 필터링으로 우회문자를 제거하여 사용한다.
date = date.replaceAll("|","");
date = date.replaceAll(";","");
date = date.replaceAll("&","");
date = date.replaceAll(":","");
date = date.replaceAll(">",""); Runtime.getRuntime().exec(command + date);
운영체제 명령어 실행 시에는 아래와 같이 외부에서 들어오는 값에 의하여 멀티라인을 지원하는 특수문자(| ; & :)나 파일 리다이렉트 특수문자(> >>)등을 제거하여 원하지 않은 운영체제 명령어가 실행될 수 없도록 필터링을 수행한다.
//외부 입력값이 프로세스가 실행할 파일 이름을 지정하고 있다.
string fileName = PgmTextBox.Text;
ProcessStartInfo proStartInfo = new ProcessStartInfo();
proStartInfo.FileName = fileName;
Process.Start(proStartInfo);
다음 C# 코드는 외부 입력값을 프로세스가 실행할 파일 이름에 직접 사용하고 있다. 이는 공격자의 입력에 따라 의도하지 않은 명령어가 실행될 수 있다.
string fileName = PgmTextBox.Text;
//외부 입력값에 대해 정규식 등을 이용하여 검증해야 한다.
if (Regex.IsMatch(fileName, "properRegexHere"))
{
ProcessStartInfo proStartInfo = new ProcessStartInfo();
proStartInfo.FileName = fileName;
Process.Start(proStartInfo);
}
적절한 정규식이나, white list 등을 이용하여 검증을 한 후 사용하도록 한다.
😂C#
int main(int argc, char* argv[]) {
char cmd[CMD_LENGTH];
if (argc < 1 ) {
// error
}
// 외부 입력값으로 커맨드를 직접 수행
cmd_data = argv[1];
snprintf(cmd, CMD_LENGTH, “cat %s”, cmd_data);
system(cmd);
……
}
공격자의 입력에 따라 의도하지 않은 명령어가 실행될 수 있다.
int main(int argc, char* argv[]) {
char cmd[CMD_LENGTH]; int len = 0;
if (argc < 1 ) {
// error
}
// 외부 입력값으로 커맨드를 직접 수행 cmd_data = argv[1];
len = strlen(cmd_data);
for (int i = 0; I < len; i++) {
if (cmd_data[i] == ‘|’ || cmd_data[i] == ‘&’ ||
cmd_data[i] == ‘;’ || cmd_data[i] == ‘:’ || cmd_data[i] == ‘>’) {
// 멀티라인을 지원하는 특수문자나 파일 리다이렉트 특수문자가 존재하여 안전하지 않음
return -1;
}
}
snprintf(cmd, CMD_LENGTH, “cat %s”, cmd_data);
system(cmd);
……
}
운영체제 명령어 실행 시에는 아래와 같이 외부에서 들어오는 값에 의하여 멀티라인을 지원하는 특수문자(| ; & :)나 파일 리다이렉트 특수문자(> >>)등을 제거하여 원하지 않은 운영체제 명령어가 실행될 수 없도록 필터링을 수행한다