1. os 인젝션의 정의
OS 명령 인젝션(OS Command Injection 또는 Shell Injection)은 웹 애플리케이션이 구동 중인 서버의 운영체제상에서 임의의 명령을 실행하도록 하는 웹 취약점입니다. 웹 애플리케이션은 HTML 폼, HTTP 헤더, 쿠키, GET 파라미터 등을 통해 사용자로부터 데이터를 입력받아 시스템 셸(Shell)에 제공할 수 있습니다. 이 때 사용자가 제공하는 입력값에 대한 유효성 검증이 구현되어있지 않거나 안전하지 않은 방식으로 검증을 한다면 OS 명령 인젝션 공격에 취약할 수 있습니다. OS 명령 인젝션을 통해 실행되는 명령은 루트나 관리자 권한의 계정이 아닌 웹 애플리케이션을 구동하는 계정의 권한으로 명령이 실행되므로 일반적으로 시스템 전체를 손상시키지 못하지만 공격자가 권한 상승이나 다른 취약점과 연계할 수 있다면 더 많은 권한을 획득할 수 있으며 취약한 웹 애플리케이션을 장악하거나 모든 데이터를 손상시킬 수 있습니다.
쉽게 정리하자면
OS 인젝션이란 공격자가 OS에 악성 코드를 주입하여 제어, 데이터 액세스 또는 무단 작업을 수행하는 보안 취약점입니다. 소프트웨어 버그, 구성 오류 또는 잘못된 코딩 관행으로 인해 발생하는 취약점을 말할수 있습니다!
2. os 명령 injection의 작동방식
웹 애플리케이션상에 구현된 일부 기능은 운영체제 및 파일시스템과 통신하기 위해 운영체제 명령을 실행하기도 합니다. 이와 같은 기능 구현을 위해 PHP, JAVA, PYTHON 등 대부분의 개발 언어들은 셸과 연동되는 내장함수를 제공하고 있습니다. 이러한 내장함수는 일반적으로 system(), exec()와 같은 함수이며, 셸 함수라 부르기도 합니다. 웹 애플리케이션은 바로 이러한 셸 함수를 활용해 시스템 셸로 운영체제 명령을 전달하고 실행 결과를 얻을 수 있게 됩니다. 하지만 단지 셸 함수를 사용한다는 이유만으로 OS 명령 인젝션에 취약한 것은 아닙니다. OS 명령 인젝션은 셸 함수를 통해 시스템 셸로 전달되는 명령에 사용자로부터 전달받은 입력값이 포함될 때 발생합니다. OS 명령 인젝션이 정상적으로 수행되기 위해서는 다음과 같은 조건이 충족되어야 합니다.
- 시스템 셸로 전달되는 명령에 사용자로부터 입력받은 데이터를 포함해야 합니다.
- 사용자 데이터는 이스케이프 또는 삭제 처리없이 정상적인 셸 명령어로 인식되어야 합니다.
- 웹 애플리케이션을 구동 중인 계정에 시스템 명령을 실행할 수 있는 권한이 있어야 합니다.
리눅스 환경에서 호스팅되고 있는 다음의 PHP 소스코드(ex.php)를 살펴봅시다.
<?php
echo "<p>filename 매개변수(GET)를 이용하여 조회할 파일의 이름을 입력하세요</p>";
$file = $_GET['filename'];
system("cat $file");
?>
위의 소스코드는 'filename'이라는 GET 파라미터의 값을 cat 명령의 인자로 사용하고 system() 함수를 통해 명령을 실행시키고 있습니다. 'filename' 파라미터에 정상적인 데이터가 입력된다면 이 소스코드는 개발자가 의도한대로 지정된 파일의 내용을 보여주는 동작을 수행할 것입니다.
위 소스코드를 통해 조회할 수 있는 아래와 같은 hello.html 이라는 파일이 서버상에 존재한다고 가정합시다.
<h2>Hello, Bug bounty club!</h2>
이 파일을 웹 브라우저에서 조회하면 다음과 같이 응답이 표시됩니다.

'filename' 파라미터로 전달된 hello.html 파일의 내용이 웹 브라우저에 표시됨
사용자가 입력한 hello.html이라는 데이터는 웹 애플리케이션 내부에서 아래의 과정을 통해 시스템 명령에 포함되게 됩니다.

사용자 데이터(hello.html)를 사용해 셸 명령을 구성하고 cat hello.html 명령을 실행함
웹 애플리케이션에서 OS 명령이 어떤 방식으로 실행되는지 간단한 PHP 소스코드를 통해 살펴 보았습니다.
이제 이 소스코드를 통해 실험을 해 볼 수 있습니다. 'filename' GET 파라미터는 사용자에 의해 직접 조작이 가능합니다. 즉, 정상적인 파일 이름이 아닌 어떤 다른 데이터로 얼마든지 변경할 수 있다는 의미입니다. 또한 소스코드를 보시면 아시겠지만 어떠한 보안 조치도 구현되어있지 않기 때문에 OS 명령 인젝션에 취약한 코드입니다. 그럼 ex.php 웹 페이지에서 OS 명령 인젝션을 해봅시다. OS 명령 인젝션을 수행하기 위해 사용되는 특수문자들이 있습니다. 먼저 어떤 특수문자들이 사용되는지 알아보죠. 아래의 표에 있는 특수문자들은 셸 인터프리터에서 어떤 특정한 기능을 수행하는 메타문자들이며 웹 애플리케이션에서 이러한 문자들에 대해 안전한 필터링이 구현되어있지 않다면 공격자는 메타문자를 이용해 기존의 명령 구문에 임의의 명령을 주입하고 실행시킬 수 있게 됩니다.
메타문자 | 기 능 | 사용 예 |
cmd1 | cmd2 | 왼쪽 명령의 결과를 오른쪽 명령의 입력으로 전달합니다. | $ whoami | grep 'b' bbc |
cmd1 && cmd2 | 왼쪽 명령을 성공적으로 실행하면 오른쪽 명령을 실행합니다. | $ whoami && pwd bbc /home/bbc |
cmd1 || cmd2 | 왼쪽 명령의 실행에 실패하면 오른쪽 명령을 실행합니다. | $ whoareyou || pwd whoareyou: 명령을 찾을 수 없습니다. /home/bbc |
cmd1 ; cmd2 | 한 줄에 여러 명령을 사용할 때 각각의 명령을 구분하기 위해 사용됩니다. (리눅스/유닉스 전용) | $ whoami; pwd bbc /home/bbc |
`cmd` | 백틱(`) 사이의 명령을 실행한 결과를 반환합니다. (리눅스/유닉스 전용) | $ echo `whoami` bbc |
$(cmd) | $() 안의 명령을 실행한 결과를 반환합니다. (리눅스/유닉스 전용) | $ echo $(whoami) bbc |
cmd > /your_file | 왼쪽 명령의 결과를 오른쪽 파일에 기록합니다. (리눅스/유닉스 전용) | $ whoami > /path/to/file/whoami.txt |
/your_file < cmd | 오른쪽 명령의 결과를 왼쪽 파일에 기록합니다. (리눅스/유닉스 전용) | $ /path/to/file/whoami.txt < whoami |
OS 명령 인젝션에 사용되는 메타문자들
그럼 먼저 살펴보았던 '/ex.php?filename=hello.html' 뒤에 세미콜론(;)과 id 명령어를 추가하여 요청했다고 생각해봅시다. 요청 URL은 다음과 같을 것입니다.
http://www.example.com/ex.php?filename=hello.html;id
방금 전에 보았던 메타문자표에서 세미콜론(;)은 한 줄에 포함된 여러 개의 명령어를 구분한다고 배웠습니다. 위 요청이 있을 때 ex.php 소스코드의 처리 과정을 다시 살펴보면 보시다시피 마지막 단계에서 세미콜론(;)에 의해 명령어가 두 개로 구분되고 각 명령어들이 순차대로 실행되게 됩니다.

'filename' 파라미터에 추가된 ;id에 의해 명령이 분리되고 id 명령이 추가됨
요청에 대한 응답은 당연히 아래의 화면과 같이 id 명령 실행결과가 추가되어 나타나겠죠.

OS 명령 인젝션으로 인해 id 명령도 함께 실행됨
세미콜론(;) 외에 앞서 소개된 다른 메타문자들도 각 기능에 맞게 구성한다면 임의의 명령을 주입할 수 있습니다. 만일 악의적인 공격자가 id 명령처럼 시스템에 직접적인 손상을 가하지 않는 무해한 명령어 대신 rm -rf /와 같은 명령을 주입한다면 웹 애플리케이션은 상당한 손상을 받게 됩니다. 또한 wget을 통해 웹셸과 같은 다른 악성 파일을 서버에 다운로드하여 후속공격을 하거나 조직 내 다른 시스템으로 공격을 확장할 수도 있습니다.
3. os injection의 유형
1. 직접 명령 인젝션 (Direct Command Injection)
앞서 OS 명령 인젝션의 동작 방식을 설명드릴 때 등장했던 예제(ex.php)처럼 사용자가 입력한 데이터가 OS 명령의 인자로 직접 포함되는 경우입니다.
2. 간접 명령 인젝션 (Indirect Command Injection)
파일이나 환경변수를 통해 웹 애플리케이션의 시스템 셸로 OS 명령이 전달되는 경우입니다. 보통 윈도우 시스템에서 나타나며 Forfiles, pcalua.exe 등과 같이 CMD를 사용하지 않고 명령을 호출할 수 있도록 지원하는 유틸리티를 통해 가능합니다.
3. 블라인드 명령 인젝션 (Blind Command Injection)
직접 명령 인젝션과 같이 사용자의 입력 데이터가 OS 명령에 포함되어 시스템 셸로 전달되지만 HTTP 응답 메시지에 명령의 실행 결과가 표시되지 않는 경우입니다. 일반적인 명령 인젝션처럼 주입된 명령이 즉각 HTTP 응답 메시지에 출력되면 취약점을 식별하기 쉽겠지만 실제로는 그렇지 않은 경우가 상당히 많습니다. 만일 이런 경우에 직접 명령 인젝션 기술만을 고집하며 응답에 명령 실행 결과가 출력되는지만 확인한다면 명령 인젝션 취약점을 눈 앞에 두고도 놓칠 수가 있습니다. 따라서 '시간 지연', '출력 리다이렉팅' 또는 '대역외(Out-Of-Band) 기술'과 같은 블라인드 명령 인젝션 기술이 주로 사용됩니다.
4. os injection의 예방조치
OS 명령 인젝션을 예방하기 위해 가장 좋은 방법은 웹 애플리케이션에서 system(), exec()와 같은 셸 함수를 사용하여 명령을 실행하지 않는 것입니다. 하지만 웹 애플리케이션을 통해 OS 명령을 실행해야 할 부득이한 이유가 있다면 가급적 사용자가 임의로 조작할 수 있는 입력값이 명령에 직접 포함되지 않도록 해야 합니다. 만일 사용자 입력을 OS 명령에 포함시켜야 하는 경우에는 사용자 입력에 대해 엄격한 검증을 수행해야 합니다. 이를 위해 가장 좋은 방식은 화이트리스트 방식으로 허용되는 입력값 목록을 만들고 허용되지 않는 입력값에 대한 필터링을 수행해야 합니다. 화이트리스트 방식의 필터링이 더 안전하지만 블랙리스트 방식을 사용해야 한다면 서버의 운영체제 종류에 따라 아래의 특수문자들에 대해 이스케이프 처리하거나 요청을 차단해야 합니다.
- 윈도우의 경우: ( ) < > & * ' | = ? ; [ ] ^ ~ ! . ” % @ / \ : + , ` 문자들 앞에 '^'를 추가하여 이스케이프하거나 요청을 차단합니다.
- 리눅스 또는 유닉스의 경우: { } ( ) < > & * ' | = ? ; [ ] $ – # ~ ! . ” % / \ : + , ` 문자들 앞에 '\'를 추가하여 이스케이프하거나 요청을 차단합니다.
'seKUCTF' 카테고리의 다른 글
[seKUCTF] forcelogin1 (0) | 2023.04.09 |
---|---|
[seKUCTF] forcelogin 2 (1) | 2023.04.09 |
[seKUCTF] Ping! (0) | 2023.03.22 |
linux 와일드카드란? (0) | 2023.03.21 |
[seKUCTF] NewAPI (0) | 2023.03.15 |