Dreamhack/Web
[Dreamhack] command-injection-1
h34hg0
2023. 5. 11. 00:58
문제
문제 파일 : app.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)
풀이
ping 페이지에 8.8.8.8을 입력하니 ping 명령어가 입력한 8.8.8.8 로 실행된 것을 확인할 수 있다.
리눅스의 메타문자 중 ; 를 이용해서 ls 명령어가 되는지 입력해보자
( ; 는 명령어를 연결시켜주는 메타문자이다. 예 : ping 8.8.8.8; echo 123 )
입력 폼에 형식에 맞지 않는 문자를 사용하면 위와 같은 경고가 뜨면서 입력 값이 전송되지 않는다.
이는 html 단에서 형식을 정하는 것을 확인할 수 있고, 그 부분의 html을 없애버리면 해결된다.
;ls 를 입력 폼에 입력후 버튼을 누르면 위 화면이 나온다. 박스를 보면 ping -c 3 ";ls" 에서 ;ls 가 " 문자 때문에 문자열 처리가 되지 않았나 짐작할 수 있다.
host = request.form.get('host')
cmd = f'ping -c 3 "{host}"'
실제로 app.py 코드에서 위 부분을 보면 "{host}" 로 입력값을 "" 로 감싸서 문자열 처리가 되는 것을 알 수 있다.
따라서 ;ls 양옆에 " 문자를 넣어서 ;ls 가 문자열 처리가 되지 않도록 해서 입력해봤다.
입력 후 결과를 보니 ls 명령어가 정상적으로 동작하는 것을 확인할 수 있다. 이제 원하는 명령어가 사용 가능하므로 flag가 있는 flag.py 를 확인하자
";cat flag.py" 를 입력하여 플래그가 출력이 되도록 했다.