본 문제는 Dreamhack을 통해서 풀어 보실 수 있습니다.

해답을 이해하며 생각을 해보면서 풀이 해보시길 바랍니다.

문제 내용

문제는 dreamhack.io를 들어가시면 확인할 수 있습니다.

접속 시 vuln page, memo, notice flag, flag 총 4개의 링크가 있는 것을 알 수 있다.

문제 풀이

vuln page

  • vuln(xss)page : 해당 URL을 보면 http://host3.dreamhack.games:20599/vuln?param=%3Cscript%3Ealert(1)%3C/script%3E로 되어 있다. 하지만, 어떠한 이유인지 스크립트가 작동하지 않는다. 그리고 <*>alert(1) 이라는 텍스트가 적혀 있는 것을 알 수 있다.
@app.route("/vuln")
def vuln():
    param = request.args.get("param", "").lower()
    xss_filter = ["frame", "script", "on"]
    for _ in xss_filter:
        param = param.replace(_, "*")
    return param

parameter로 받은 값은 frame, script, on필터링으로 인해 작동하지 않는 것을 알 수 있다.

memo

  • memo : 해당 페이지로 이동하게 되면 위와 같이 hello 문자열이 계속 입력되는 것을 알 수 있다.
memo_text = ""

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

단순히 접속할 때 마다 /memo?memo=hello에 해당하는 parameter 값을 덧붙혀 출력해주는 것을 알 수 있다.

notice flag

  • notice flag : Access Denied 문자열이 나오는데 어떠한 권한이 거절당한 것인지 알아본다.
@app.route("/admin/notice_flag")
def admin_notice_flag():
    global memo_text
    if request.remote_addr != "127.0.0.1":
        return "Access Denied"
    if request.args.get("userid", "") != "admin":
        return "Access Denied 2"
    memo_text += f"[Notice] flag is {FLAG}\n"
    return "Ok"

현재 접속자의 IP가 Local 접속이 아니라면 Access Denied를 출력하고, 이후 요청 시 GET parameter의 userid가 admin이 아니면 Access Denied2를 출력하고, 모두 해당했을 경우 global memo_text에 현재 FLAG를 덧붙혀주는 것을 알 수 있다.

그렇다면, /flag를 통해 파라미터를

def check_csrf(param, cookie={"name": "name", "value": "value"}):
    url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
    return read_url(url, cookie)

통해 로컬로 접속할 수 있게 하면 해결된다.

<img src = "/admin/notice_flag?userid=admin">