웹 애플리케이션을 개발하다보면, 어떤 기능에 대해서는 스스로 코드를 작성하기보다 이미 설치된 소프트웨어를 사용하는 것이 편리할 때가 있다. 예를 들어, 업로드 디렉토리에 있는 파일들의 이름을 출력하는 웹 애플리케이션을 만든다고 할 때, 디렉토리를 조회하고 파일들을 나열하고 출력하는 코드를 직접 작성하는 것보다 시스템에 내장되어 있는 ls 명령어를 사용하는 것이 훨씬 편리하다.

다양한 웹 애플리케이션 제작용 언어는 시스템에 내장되어 있는 프로그램들을 호출할 수 있는 함수를 지원한다. 각 언어별 시스템 함수로는 PHP의 system, Node JS의 child_process, 파이썬의 os.system이 있다. 이러한 함수는 전달된 인자를 셸 프로그램에 전달해 명령어를 실행한다. 예를 들어, system("cat /etc/passwd")를 호출하면, 셸 프로그램으로 cat /etc/passwd를 실행한 것과 같다.

시스템 함수를 사용하면 이미 설치된 소프트웨어들을 쉽게 이용할 수 있다는 장점이 있다. 그러나 함수의 인자를 셸의 명령어로 전달한다는 점에서 치명적인 취약점으로 이어지기도 한다.


Command Injection

Command Injection

**인젝션(Injection)**은 악의적인 데이터를 프로그램에 입력하여 이를 시스템 명령어, 코드, 데이터베이스 쿼리 등으로 실행되게 하는 기법을 말한다. 인젝션의 종류로는 SQL Injection도 존재한다. 이 중, 이용자의 입력을 시스템 명령어로 실행하게 하는 취약점을 Command Injection이라고 부른다.

Command Injection은 명령어를 실행하는 함수에 이용자가 임의의 인자를 전달할 수 있을 때 발생한다. 앞서 말한 시스템 함수를 사용하면 이용자의 입력을 소프트웨어의 인자로 전달할 수 있다. 파이썬으로 개발된 웹 애플리케이션에서 입력한 임의 IP에 ping을 전송하고 싶다면 os.system("ping [user-input]")을, 임의 파일을 읽고 싶다면 os.system("cat [user-input]") 등의 형태로 시스템 함수를 사용할 수 있다.

그러나 이러한 함수를 사용할 때, 이용자의 입력을 제대로 검사하지 않으면 임의 명령어가 실행될 수도 있다. 이는 리눅스 셸 프로그램이 지원하는 다양한 메타 문자 때문이다. 시스템 함수는 셸 프로그램에 명령어를 전달하여 실행하는데, 셸 프로그램은 다양한 메타 문자를 지원한다.

- 명령어 치환

안에 들어 있는 명령어를 실행한 결과로 치환된다.

$ echo `echo theori`
theori

$() - 명령어 치환

$() 안에 들어있는 명령어를 실행한 결과로 치환된다. 이 문자는 위와 다르게 중복 사용이 가능하다. (echo $(echo $(echo theori)))

$ echo $(echo theori)
theori

&& - 명령어 연속 실행