TeamH4C

[빡공팟 5기] W4 : Web Hacking 로드맵 - STAGE 6 - Command Injection

이유갬 2022. 10. 17. 12:56

ServerSide: Command Injection

 

다양한 웹 애플리케이션 제작용 언어는 시스템에 내장되어 있는 프로그램들을 호출할 수 있는 함수를 지원한다.

 

<각 언어별 시스템 함수>

PHP : system

Node JS : child_process

Python : os.system

 

위와 같은 함수들은 전달된 인자를 셸 프로그램에 전달해서 명령어를 실행한다.

system("cat /etc/passwd") 를 호출할 때, 셸 프로그램으로 cat /etc/passwd 를 실행한 것과 같다.

시스테 함수를 사용하면 이미 설치된 소프트웨어를 쉽게 이용할 수 있지만,

함수의 인자를 셸의 명령어로 전달하면 치명적인 취약점으로 이어진다. 이를 Command Injection 취약점이라고 한다.

 

Command Injection

이용자의 입력을 시스템 명령어로 실행하게 하는 취약점이다.

명령어를 실행하는 함수에 이용자가 임의의 인자를 전달할 수 있을 때 발생한다.

 

<Python>
- os.system("ping [user-input]") - 사용자가 입력한 임의의 IP 주소에게 Ping 을 전송할 때 사용한다.
- os.system("cat [user-input]") - 임의 파일을 읽고 싶을 때 사용한다.

 

이용자의 입력을 제대로 검사하지 않는다면 임의의 명령어가 실행될 수도 있다.

이는 리눅스 셸 프로그램이 지원하는 다양한 메타 문자 때문이다.

시스템 함수는 셸 프로그램에 명령어를 전달하여 실행하는데, 이때 셸 프로그램은 다양한 메타 문자를 지원한다.

공격자는 이 메타 문자를 통해서 임의의 명령어를 실행하여 셸을 획득한다.


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

2. $() (명령어 치환) : $() 안에 들어있는 명령어를 실행한 결과로 치환되며 중복 사용이 가능하다. (echo $(echo $(echo theori)))

3. && (명령어 연속 실행) : 한 줄에 여러 명령어를 사용하고 싶을 때 사용한다. (Logical AND)

4. || (명령어 연속 실행) : 한 줄에 여러 명령어를 사용하고 싶을 때 사용한다. 앞 명령어에서 에러가 발생해야 뒷 명령어를 실행한다.(Logical OR)

5. ; (명령어 구분자) : 한 줄에 여러 명령어를 사용하고 싶을 때 사용한다. ; 은 단순히 명령어를 구분하고 앞 명령어 에러 유무와 관계 없이 뒤의 명령어를 실행한다.

6. | (파이프) : 앞 명령어의 결과가 뒷 명령의 입력으로 들어간다.


(간단한 실습)

@app.route('/ping')
def ping():
	ip = request.args.get('ip')
    return os.system(f'ping -c 3 {ip}')

id 명령어를 실행하는 방법에는,

1. 127.0.0.1 | id

2. 127.0.0.1 && id

3. 127.0.0.1 ; id

 

(command-injection-1)

단순히 메타 문자를 이용해서 명령어를 입력하는 문제인 줄 알았는데 툴을 사용해야 가능했다.

입력하는 곳에서 정규 표현식 검사가 있었기 때문이다.

내 머리로는 정규 표현식 검사를 피해서 메타 문자를 사용하여 Command Injection 하는 건 불가능했다.

툴을 언제 써먹어보나 했는데 정확히 사용법을 알고 활용하니까 뿌듯했당!

결론

 

Command Injection 은 이용자의 입력을 적절한 검사 없이 명령어로 사용할 때 발생한다.

 

보안

 

이러한 취약점을 막기 위해서는 개발자는 입력 값에 대해 메타 문자의 유무를 확실하게 검사하거나

시스템 메타 문자를 해석 하지 않고 그대로 사용하는 함수를 사용해야 한다.