인젝션(Injection)은 악의적인 데이터를 프로그램에 입력하여 이를 시스템 명령어, 코드, 데이터베이스 쿼리 등으로 실행되게 하는 기법을 말한다.
인젝션의 종류로는 SQL Injection도 존재한다. 이 중, 이용자의 입력을 시스템 명령어로 실행하게 하는 취약점을 Command Injection이라고 부른다.
Command Injection은 명령어를 실행하는 함수에 이용자가 임의의 인자를 전달할 수 있을 때 발생한다.
-> 시스템 함수를 사용하면 이용자의 입력을 소프트웨어의 인자로 전달할 수 있다.
-> 파이썬으로 개발된 웹 애플리케이션에서 입력한 임의 IP에 ping을 전송하고 싶다면, os.system("ping [user-input]")을, 임의 파일을 읽고 싶다면, os.system("cat [user-input]")등의 형태로 시스템 함수를 사용할 수 있다.
그러나 이러한 함수를 사용할 때, 이용자의 입력을 제대로 검사하지 않으면 임의 명령어가 실행될 수도 있다.
-> 이는 리눅스 셸 프로그램이 지원하는 다양한 메타 문자 때문이며, 시스템 함수는 셸 프로그램에 명령어를 전달하여 실행하는데, 셸 프로그램은 다양한 메타 문자를 지원한다.
코드를 입력하세요
주목해야 할 것은, &&, ;, | 등을 사용하면, 여러 개의 명령어를 연속으로 실행시킬 수 있다는 것이다.
-> 따라서, 공격자는 메타 문자를 통해 임의 명령어를 실행하여 셸을 획득할 수 있다.
아래 예제를 보면, Command Injection이 발생하는 예제 코드이며, 코드를 살펴보면, URL 쿼리를 통해 전달되는 ip 값을 ping 명령어의 인자로 전달된다.
아래의 예제를 실행한 후 모듈에서 127.0.0.1을 입력하면, 의도한대로 프로그램이 작동하는 것을 확인할 수 있으며, 공격자는 입력값이 명령어의 일부로 실행되는 것을 확인하고, Command Injection을 시도할 수 있다.
# Command Injection Code
@app.route('/ping')
def ping():
ip = request.args.get('ip')
return os.system(f'ping -c 3 {ip}')
id 명령어를 실행하기 위해서는 메타 문자를 사용해야 한다.
위의 예제에 명령줄을 삽입해보면, id 명령어가 주입된 모습을 확인할 수 있다.
1 $ ping -c 3 127.0.0.1; id
2 $ ping -c 3 127.0.0.1 && id
3 $ ping -c 3 127.0.0.1 | id