본문 바로가기

KERT/HackHeat

Command Injection

서론

시스템 함수란? 시스템에 내장된 프로그램들을 호출할 수 있는 함수

  • 다양한 웹 애플리케이션 제작용 언어는 시스템 함수를 지원한다.
    • 예를 들어, PHP 의 system, NodeJS의 child_process, 파이썬의 os.system 이 있다.
  • 시스템 함수를 사용하면 이미 설치된 소프트웨어들을 쉽게 이용할 수 있다는 장점이 있습니다.

시스템 함수는 전달된 인자를 셸 프로그램에 전달해 명령어를 실행한다.

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

즉, 이용자의 입력을 시스템 명령어로 실행하게 하는 취약점을 command injection 이라고 한다.

따라서, 공격자는 메타 문자를 통해 임의 명령어를 실행하여 셸을 획득할 수 있습니다.

메타 문자 (특수한 의미를 가진 문자)
`` 명령어 치환
``안에 들어있는 명령어를 실행한 결과로 치환됩니다.
$() 명령어 치환
$()안에 들어있는 명령어를 실행한 결과로 치환됩니다. 이 문자는 위와 다르게 중복 사용이 가능합니다. (echo $(echo $(echo theori)))
&& 명령어 연속 실행
한 줄에 여러 명령어를 사용하고 싶을 때 사용합니다. 앞 명령어에서 에러가 발생하지 않아야 뒷 명령어를 실행합니다. (Logical And)
|| 명령어 연속 실행
한 줄에 여러 명령어를 사용하고 싶을 때 사용합니다. 앞 명령어에서 에러가 발생해야 뒷 명령어를 실행합니다. (Logical Or)
; 명령어 구분자
한 줄에 여러 명령어를 사용하고 싶을 때 사용합니다. ;은 단순히 명령어를 구분하기 위해 사용하며, 앞 명령어의 에러 유무와 관계 없이 뒷 명령어를 실행합니다.
| 파이프
앞 명령어의 결과가 뒷 명령어의 입력으로 들어갑니다.

 

실습

모듈로 id 명령어를 실행해보아라.

 

코드

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

코드를 보면 ip 값을 ping 명령어의 인자로 전달한다.

이 때 입력값으로 command injection을 시도할 수 있다.

ip를 입력하면 ping 명령어가 실행되는 것을 확인할 수 있다.

풀이

ping -c 3 뒤에 아무 ip를 쓰고 메타문자 &&, |, ; 중 하나를 씀으로써

한 줄에 명령어 여러 개를 실행할 수 있다.

 

이런 식으로 command injection 을 막기 위해 개발자는 입력 값에 대해 메타 문자의 유무를 검사하거나, 되도록 system 함수의 사용을 자제해야 한다.

 

dreamhack 문제

https://dreamhack.io/wargame/challenges/44

 

command-injection-1

특정 Host에 ping 패킷을 보내는 서비스입니다. Command Injection을 통해 플래그를 획득하세요. 플래그는 flag.py에 있습니다. Reference Introduction of Webhacking

dreamhack.io

문제 설명

특정 Host에 ping 패킷을 보내는 서비스입니다.
Command Injection을 통해 플래그를 획득하세요. 플래그는 flag.py에 있습니다.

코드

#!/usr/bin/env python3
import subprocess

from flask import Flask, request, render_template, redirect

from flag import FLAG

APP = Flask(__name__)


@APP.route('/')
def index():
    return render_template('index.html')


@APP.route('/ping', methods=['GET', 'POST'])
def ping():
    if request.method == 'POST':
        host = request.form.get('host')
        cmd = f'ping -c 3 "{host}"'
        try:
            output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
            return render_template('ping_result.html', data=output.decode('utf-8'))
        except subprocess.TimeoutExpired:
            return render_template('ping_result.html', data='Timeout !')
        except subprocess.CalledProcessError:
            return render_template('ping_result.html', data=f'an error occurred while executing the command. -> {cmd}')

    return render_template('ping.html')


if __name__ == '__main__':
    APP.run(host='0.0.0.0', port=8000)

링크를 열면 Welcome this is ping playground! 이 적혀있는 index.html 이 뜨고

 

/ping 페이지는 이렇게 뜬다

def ping():
    if request.method == 'POST':
        host = request.form.get('host')
        cmd = f'ping -c 3 "{host}"'

host 를 입력값으로 받아 쌍따옴표로 둘러싸여 cmd 변수에 저장된다.

 

문제의 목적은 flag.py 에 있는 플래그를 획득하는 것이므로

입력값에 cat 명령어를 넣을 것이다.

 

먼저, 0.0.0.0 을 입력하면 이렇게 뜬다.

cat 명령어를 삽입하면 여기에 flag 가 뜰 것이다.

0.0.0.0";"cat flag.py를 입력하면 형식에 맞지 않다고 뜬다.

자세히 알아보기 위해 f12 개발자도구를 사용했다.

<input type="text" class="form-control" id="Host" placeholder="8.8.8.8" name="host" pattern="[A-Za-z0-9.]{5,20}" required>

입력값 부분을 보면 pattern 으로 입력 형식이 정해져 있다.

 

pattern="[A-Za-z0-9.]{5,20}"

개발자도구를 통해 이 pattern 부분을 삭제 해주면 injection이 가능할 것이다.

삭제

삭제하고 나서

0.0.0.0"; cat "flag.py 또는

0.0.0.0"&& cat "flag.py 을 입력하면

cmd = ping -c 3 "0.0.0.0"; cat "flag.py"

이런 식으로 들어간다.

 

 

 

 

 

 

'KERT > HackHeat' 카테고리의 다른 글

SSRF(Server-side Request Forgery)  (0) 2023.09.18
파일 취약점(File Vulnerability)  (0) 2023.08.14
NoSQL Injection  (0) 2023.07.27
NoSQL 개념과 MongoDB 기본 문법  (0) 2023.07.26
SQL Injection  (0) 2023.07.21