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

Analysis

문제 VM에 접속 후 다음 세 엔드포인트를 발견할 수 있었다.

def vuln():
    param = request.args.get("param", "")
    return param

첫번째 vuln 페이지의 URL은 해당 사항과 같았고, 이는 해당 페이지의 형태처럼 /vuln?param=으로 XSS가 가능하다는 것을 보여주었다.

해당 부분에서 문제점이 발생했다. /render_template()를 사용 시 전달된 템플릿 변수를 기록할 때 HTML 엔티티코드로 변환하기에 XSS가 발생할 수 없는데, 현재 상태로는 이용자가 입력한 값을 그대로 출력할 수 있기 때문에 <scripts> 삽입이 가능 할 것으로 보인다.

두번째 memo 페이지에서는 쿼리에 있는 memo의 값을 바꿔가며 들어갔더니 페이지에 memo 변수의 값이 출력되었다. 아마 플래그 값을 출력시키는 곳으로 쓰이는건가 싶다.

@app.route("/memo")
def memo():
    global memo_text
    text = request.args.get("memo", "")
    memo_text += text + "\n"
    return render_template("memo.html", memo=memo_text)

세번째 flag 페이지에서는 친절하게 XSS를 실행시키는 URL을 간편하게 만들어두었다. Path와 parameter만 지정하면 될 것 같다.

@app.route("/flag", methods=["GET", "POST"])
def flag():
    if request.method == "GET":
        return render_template("flag.html")
    elif request.method == "POST":
        param = request.form.get("param")
        if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
            return '<script>alert("wrong??");history.go(-1);</script>'
        return '<script>alert("good");history.go(-1);</script>'

즉 XSS를 위한 URL를 짜야하는 형태이고, 이는 Reflected XSS로 파악 할 수 있는 것 같다. URL의 형태는 첫번째 페이지와 세번째 페이지를 토대로 다음과 같이 작성하면 될 것같다.

http://127.0.0.1:8000/vuln?param=<script> *exploit codes* </script>

나는 VM 서버에서 풀긴 해서 Host 주소가 로컬이 아니긴 했는데, 문제풀이를 위해선 로컬 서버로 지정을 해야 한다고 한다.. flag 페이지에서도 로컬 서버로 호스트 주소가 지정되어 있긴 했다.

문제 설명에서 플래그는 flag.txt 파일과 FLAG 변수에 있다고 했으니, 페이로드 코드를 짜서 실행시켜 보았다.

<script> alert(FLAG) </script>

<script> console.log(FLAG) </script>