문제
https://dreamhack.io/wargame/challenges/44
문제코드
#!/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)
코드 분석
@APP.route('/')
def index():
return render_template('index.html')
/로 접속하면 그냥 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')
여기가 핵심이다.
POST 요청일시, 폼에서 host 를 요청받는다.
그리고 subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5) 명령어를 실행하는데, 실행결과는 ping_result.html 을 실행하는 방식이다. Timeout되거나 CalledProcessError 의 예외처리도 있다.
명령어 확인
ping -c 3 {host} 의미를 분석해보면
{host} 주소에 ICMP(Internet Control Message Protocal} 패킷을 보내어 해당 호스트에 응답을 확인하는 것인데, -c 옵션은 보낼 패킷의 횟수 지정, 3은 패킷을 몇 번 보낼지 설정한 값인 것이다.
실제 127.0.0.1 에 ping! 을 누르면 이렇게 3번 보내진 것을 확인할 수 있다.
subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5) 을 확인해보면
subprocess 는 파이썬에서 사용하는 모듈로써 외부 명령어를 실행하는 코드이다.
check_output() 은 외부 명령어를 실행하고 해당 명령어의 출력을 반환하는 명령어이고, 그 안에 있는 ['/bin/sh" "-c, cmd] 가 실제 실행하는 명령어인 것이다. /bin/sh 는 셸 프로그램을 실행, -c는 셸에서 주어진 명령어를 실행할 것임을 알려주는 명령어이다.
timeout = 5는 실행된 명령어가 최대로 실행되는 시간 지정이다.
5초가 지나면 예외가 발생할 것이다.
풀이전략
플래그는 flag.py 에 존재한다고 하였고,
코드상에서 폼에서 그냥 입력받으면 되는 것이기에 Command Injection이 발생할 것이다.
그러므로 폼에다가 127.0.0.1" ; cat flag.py" 를 입력하면 되지 않을까 싶다.
해봤는데 안 된다.
{% extends "base.html" %}
{% block title %}ping{% endblock %}
{% block head %}
{{ super() }}
{% endblock %}
{% block content %}
<h1>Let's ping your host</h1><br/>
<form method="POST">
<div class="row">
<div class="col-md-6 form-group">
<label for="Host">Host</label>
<input type="text" class="form-control" id="Host" placeholder="8.8.8.8" name="host" pattern="[A-Za-z0-9.]{5,20}" required>
</div>
</div>
<button type="submit" class="btn btn-default">Ping!</button>
</form>
{% endblock %}
ping.html 코드를 살펴보면,
<input type="text" class="form-control" id="Host" placeholder="8.8.8.8" name="host" pattern="[A-Za-z0-9.]{5,20}" required>
이 부분에서 pattern 부분을 확인해보자.
대소문자 알파벳, 숫자, 마침표 문자를 허용하다는 것을 의미한다. 그리고 문자열의 길이 {5, 20} 만 허용한다고 적혀있다.
그러니까 ; 구분자 사용도 안 되는 거고, () 이것도 사용이 불가능한 것이다. '' 도 사용이 안 된다. 그리고 20글자가 넘어서인 것도 있다. 그러니까 작성할려면, 127.0.0.1을 일단 뺴야겠고, 개발자도구에서 저 pattern 부분을 아예 지워버려야겠다.
F12에서 저기 폼 입력구간을 찾고 pattern 부분을 지워버린다.
그리고 127.0.0.1 부분을 지우고 다시 시도한다.
";cat flag.py"
실행
정상적으로 잘 나오는 것을 확인할 수 있다.
왜 "; cat flag.py" 이렇게 입력하냐면 처음 따옴표에서 ip 입력부분을 지워버리고, ; 의 구분자로 cat flag.py 를 실행시키고, 마지막 "로 전체 명령어를 감싸버리는 것이다.
맨 뒤 따옴표가 안 붙었을 떄 이런상황인 것을 알 수 있다.
에필로그
beginner 문제인데 개어렵다
'보안 스터디 > 웹 해킹' 카테고리의 다른 글
[드림핵/워게임] file-download-1 (웹해킹) (0) | 2024.01.15 |
---|---|
[드림핵/웹해킹] ServerSide: File Vulnerability (0) | 2024.01.15 |
[드림핵/웹해킹] ServerSide: Command Injection (1) | 2024.01.15 |
[드림핵/워게임] Mango (웹 해킹) (0) | 2024.01.12 |
[드림핵/웹해킹] ServerSide: NoSQL Injection (3) | 2024.01.11 |