1.1.1 개요
Command Injection은 시스템 명령어를 호출하는 어플리케이션의 인자 값을 조작하여 의도하지 않은 시스템 명령어를 실행시키는 공격 기법입니다. 이는 웹 어플리케이션이 많이 발전하지 못했던 시절에 특정 데이터를 처리하기 위해서 시스템 명령어를 웹 어플리케이션에서 호출하여 사용하던 것으로 인해서 자주 발생합니다.
1.1.2 위협
- Command Injection을 이용하면 웹 어플리케이션을 구동하고 있는 시스템 계정의Shell 권한을 획득하는 것으로 볼 수 있어 시스템에 존재하는 다양하고 유익한 명령어들을 이용해서 시스템에 악성 스크립트나 파일들을 업 로드 할 수 있습니다. 만약 대상 시스템에 시스템적인 취약점이 존재한다면 공격자는 시스템 관리자 권한까지 획득이 가능합니다.
- 현재는 Java나 ASP, PHP등의 어플리케이션에서 이전의 시스템 명령어를 호출하여 처리하던 파일/디렉터리 핸들링이나 타 어플리케이션 호출 등의 기능들을 구현하고 있기 때문에 현저하게 줄어든 추세입니다. 하지만 개발자의 편의나 어플리케이션의 특성으로 인해서 여전히 사용되고 있는 곳이 있습니다. Command Injection에 취약한 CGI로 Perl이 자주 언급되는데 이는 시스템에 자주 접근하는 Perl 언어의 특성상 발생하는 경우입니다. 어플리케이션 별로 Command Injection에 취약한 함수들은 다음과 같습니다.
구분 | 취약한 함수 |
Java(Servlet, JSP) | System.*(특히 System.Runtime) |
Perl | open() sysopen() system() glob() |
PHP | exec() system() passthru() popen() require() include() eval() preg_replace() |
1.1.3 취약성 판단
- Command Injection의 예제로 자동화된 공격 코드 생성으로 인해서 문제가 되었던 Santy 웜을 들 수 있습니다. phpBB2.0.10의 viewtopic.php의 경우 preg_replace()를 사용하고 있는데 이를 통해서 공격자는 SQL Injection 공격과 Command Injection 공격을 수행할 수 있습니다.
http://xxx.com/viewtopic.php?t=298040&highlight=%2527%252esystem(cat%20/etc/passwd)%252e%2527; |
‘%2527’은 urldecode와 magic quotes의 작용으로 인해서 ‘%25’가 퍼센트로 변환되고 ‘%27’이 다시 단일 인용 부호(‘)로 변환됩니다. 이를 통해서 취약한 함수를 사용하고 있는 highlight 인자에 주입하여 어플리케이션의 정상적인 작동을 중단시키고 system() 함수를 이용해서 악의적인 시스템 명령어를 실행할 수 있게 됩니다. 이러한 취약점을 이용해서 Santy 웜이라는 자동화 공격 도구가 제작되었고, 동일한 취약점을 이용하지만 그 패턴은 지속적으로 변화되었다. Santy 웜 A형의 경우 다음과 같은 패턴을 가지고 있습니다.
viewtopic.php?t=[topicnumber]&highlight=%2527%252esystem(“.$cmd.” )%252E%2527 |
1.1.4 대응방법
- Command Injection 공격은 그 첫 번째가 취약한 함수를 사용함으로 인해서 발생된다고 할 수 있습니다. 개발 단계에서 특별한 사유가 아니라면 앞서 언급한 함수들의 사용은 회피하는 것이 바람직합니다. 만약 반드시 사용해야 하는 것이라면 입력 값을 검증하는 필터에 파이프(|), 앰퍼샌드(&), 세미콜론(;) 등 시스템상에서 멀티라인을 지원하는 특수 문자에 대한 검증을 실시하여 해당 함수에 유해한 값이 전달되지 못하도록 해야 합니다.
다음의 예제와 같이 미리 정의된 인자값의 배열을 만들어 놓은 후 외부의 입력에 따라 적절한 인자값을 선택하도록 하여 외부의 부적절한 입력이 명령어로 사용될 가능성을 배제하여야 합니다.
1: …… 2: props.load(in); 3: String version[] = {"1.0", "1.1"}; 4: int versionSelection = Integer.parseInt(props.getProperty("version")); 5: String cmd = new String("cmd.exe /K \"rmanDB.bat \""); 6: String vs = ""; 7: if (versionSelection == 0) 8: vs = version[0]; 9: else if (versionSelection == 1) 10: vs = version[1]; 11: else 12: vs = version[1]; 13: Runtime.getRuntime().exec(cmd + " c:\\prog_cmd\\" + vs); 14: …… |