[1] λ¬Έμ νμ΄μ§ νμ
- vuln(xss) page
λ¬Έμ μ 첫 νλ©΄μ΄λ€.
vuln(xss) pageμ λ€μ΄κ°λ³΄μλ€.
vuln νμ΄μ§μ param κ°μΌλ‘ <script>alert(1)</script>μ΄ μ λ¬λμ΄ "1"μ΄λΌλ λ΄μ©μ νμ μ°½μ΄ λ¨λ κ²μ νμΈν μ μλ€.
μμ€μ½λ λν νΉμ΄μ μ΄ μμλ€.
- memo
memo νμ΄μ§μ λ€μ΄κ°λ³΄μλ€.
λ€μ΄κ° νμλ§νΌ "hello"λΌλ λ΄μ©μ λ©λͺ¨κ° λνλ¬κ³ , url μ£Όμμμλ /memo νμ΄μ§μ memo κ°μΌλ‘ helloκ° μ λ¬λλ κ²μ νμΈν μ μλ€.
μ΄λ κ² memo νλΌλ―Έν°μ μμμ κ°μ λ£μ μ£Όμλ‘ μ΄λνλ©΄ κ·Έ κ°μ΄ νμ΄μ§μ μ λ¬μ΄ λλ κ²μ λ³Ό μ μλ€.
μ΄ νμ΄μ§μ μμ€μ½λλ₯Ό νμΈν΄λ³΄μλ€.
- flag
/flag νμ΄μ§λ₯Ό νμΈν΄λ³΄μλ€.
μ΄ νμ΄μ§μ μμ€μ½λλ₯Ό νμΈν΄λ³΄μλ€.
[2] λ¬Έμ νμΌ νμ
λ€μ΄λ‘λ λ°μ νμΌ
app.py νμΌμ λ΄μ©
1) μ΄κΈ° μ μΈ λΆλΆ
#!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import urllib
import os
app = Flask(__name__)
app.secret_key = os.urandom(32)
try:
FLAG = open("./flag.txt", "r").read()
except:
FLAG = "[**FLAG**]"
2) read_url ν¨μ
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"})
try:
service = Service(executable_path="/chromedriver")
options = webdriver.ChromeOptions()
for _ in [
"headless",
"window-size=1920x1080",
"disable-gpu",
"no-sandbox",
"disable-dev-shm-usage",
]:
options.add_argument(_)
driver = webdriver.Chrome(service=service, options=options)
driver.implicitly_wait(3)
driver.set_page_load_timeout(3)
driver.get("http://127.0.0.1:8000/")
driver.add_cookie(cookie)
driver.get(url)
except Exception as e:
driver.quit()
# return str(e)
return False
driver.quit()
return True
3) check_xss ν¨μ
def check_xss(param, cookie={"name": "name", "value": "value"}):
#check_xssλ read_urlν¨μ νΈμΆνμ¬ vuln μλν¬μΈνΈ μ μ
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
4) app.route("/")
#render_template : flaskμμ μ 곡νλ ν¨μλ‘ templatesμ μ μ₯λ htmlμ λΆλ¬μ¬ λ μ¬μ©νλ ν¨μ
@app.route("/")
def index():
return render_template("index.html")
5) app.route("/vuln")
#μ¬μ©μκ° μ
λ ₯ν param κ°μ μΆλ ₯
#νν° μμ΄ κ·Έλλ‘ μμ² λ°μ λ΄μ©μ κ·Έλλ‘ μΆλ ₯
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
return param
6) app.route("/flag", methods=["GET", "POST"])
@app.route("/flag", methods=["GET", "POST"])
def flag():
#μ΄μ©μμκ² URLμ μ
λ ₯λ°λ νμ΄μ§λ₯Ό μ 곡
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param")
#νλΌλ―Έν° κ°κ³Ό μΏ ν€μ FLAGλ₯Ό ν¬ν¨ν΄ check_xss ν¨μ νΈμΆ
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>'
7) app.route("/memo")
memo_text = ""
#μ¬μ©μκ° μμ²ν λ΄μ©μ λ©λͺ¨λ‘ μμ±νμ¬ μΆλ ₯
#μ¬κΈ°λ render_templateλ₯Ό ν΅ν΄ μΆλ ₯νκΈ° λλ¬Έμ μ·¨μ½νμ§ μμ
@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)
8) μλΉμ€ μ€ν
app.run(host="0.0.0.0", port=8000)
templates ν΄λ λ΄μ html νμΌλ€
1) base.html
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/non-responsive.css') }}">
<title>{% block title %}{% endblock %} XSS-1</title>
{% block head %}{% endblock %}
</head>
<body>
<!-- Fixed navbar -->
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">XSS-1</a>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
{% block content %}{% endblock %}
</div> <!-- /container -->
<!-- Bootstrap core JavaScript -->
<script src="{{ url_for('static', filename='js/jquery.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
</body>
</html>
2) index.html
νμ΄μ§λ₯Ό λΆκΈ°νλ μμ€λ‘ vul(xss) pageλ₯Ό ν΄λ¦νμμλ μ€ν¬λ¦½νΈκ° μ€νλμ΄ alert(1) μ°½μ λμ΄λ€.
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<p class="important"><a href="/vuln?param=<script>alert(1)</script>">vuln(xss) page</a></p>
<p class="important"><a href="/memo?memo=hello">memo</a></p>
<p class="important"><a href="/flag">flag</a></p>
{% endblock %}
3) memo.html
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<pre>{{ memo }}</pre>
{% endblock %}
4) flag.html
νλΌλ―Έν°λ₯Ό μ λ ₯λ°λ νμ΄μ§μ΄λ€.
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<form method="POST">
http://127.0.0.1:8000/vuln?param=<input type="text" name="param"/><br/>
<input type="submit"/><br/>
</form>
{% endblock %}
[3] λ¬Έμ νμ΄
β vuln(xss) pageκ° κ°μ§ μ·¨μ½μ μ μ΄μ©νκΈ°
μ΄ URLμ ν΄λ¦νλ©΄ λΈλΌμ°μ κ° ν΄λΉ URLμ μ΄κ³ , 쿼리 맀κ°λ³μμ κ°μ΄ ν΄μλλ€.
λ°λΌμ <script>alert(1)</script>λΌλ JavaScript μ½λκ° μ¬μ©μμ λΈλΌμ°μ μμ μ€νλλ€.
μ΄ κ²½μ°, JavaScript μ½λλ λ¨μν κ²½κ³ μ°½μ νμν λΏμ΄μ§λ§, μ
μμ μΈ κ³΅κ²©μκ° μ΄λ₯Ό μ
μ©νμ¬ μ¬μ©μμ λΈλΌμ°μ μμ λ μ¬κ°ν μμ
μ μνν μ μλ€. μλ₯Ό λ€μ΄, μ¬μ©μμ μΈμ
μΏ ν€λ₯Ό νμΉκ±°λ λ€λ₯Έ μ
μμ μΈ λμμ μνν μ μλ€.
XSS 곡격μ μ¬μ©μλ‘λΆν° μ λ ₯ λ°λ λΆλΆμμ μ μ ν μ λ ₯ κ²μ¦κ³Ό μ΄μ€μΌμ΄ν μ²λ¦¬κ° μ΄λ£¨μ΄μ§μ§ μμ λ λ°μνλ€. μ΄λ° μ·¨μ½μ μ΄ μ‘΄μ¬νλ©΄ μ μμ μΈ μ€ν¬λ¦½νΈκ° μ€νλ μ μλ€.
ν΄λΉ λ¬Έμ μμλ λ³λμ νν°λ§μ΄ μ‘΄μ¬νμ§ μλ λ―νλ©°, <script>, alert() λ± νκ·Έμ κΈ°λ₯μ΄ μ λΆ μ μμ μΌλ‘ μλνκ³ μλ€.
>> λ°λΌμ μμ νμ΄μ§λ param νλΌλ―Έν°λ‘ xss κ³΅κ²©μ΄ κ°λ₯νλ€.
β‘ flag νμ΄μ§ μλ λ°©μ
/flagμ μ μνλ©΄ localhostμ /vuln νμ΄μ§λ‘ param νλΌλ―Έν°λ₯Ό μ μ‘ν μ μλ ꡬμ±μ΄λ€.
μ΄ μ½λλ "/flag" κ²½λ‘μμ GET μμ²μ λ°μΌλ©΄ flagλ₯Ό 보μ¬μ£Όκ³ ,
POST μμ²μ λ°μΌλ©΄ check_xss ν¨μλ₯Ό νΈμΆν΄μ "param" νΌ λ°μ΄ν°λ₯Ό νμΈνμ¬ XSS 곡격μ κ²μ¬νκ³ κ·Έμ λ°λ₯Έ μλ΅μ λ°ννλ€.
check_xss()λ₯Ό 보면 127.0.0.1:8000μ λμμΌλ‘ flagκ° ν¬ν¨λ μΏ ν€λ₯Ό read_url()μ μΈμλ‘ μ€ννλ€.
1. cookie.update()λ‘ domainμ 127.0.0.1λ‘ μ€μ νλ€.
2. chromedriverλ₯Ό μ€ννκ³ 127.0.0.1:8000λ₯Ό μ€ννλ€.
3. μΈμλ‘ λ°μ μΏ ν€λ₯Ό chromedriver μΏ ν€μ μΆκ°νλ€.
4. 127.0.0.1:8000/vuln?param=[μ λ ₯κ°]μΌλ‘ μΏ ν€μ ν¨κ» μμ²μ μ μ‘νλ€.
μλ리μ€λ₯Ό μ€λͺ νλ©΄,
chromedriverμ μ μ₯λ flagλ 곡격λμμ μΈμ
μ΄κ³ XSSλ‘ μΈμ
(μΏ ν€)μ νμ·¨νλ€.
flagλ₯Ό μ»λ κ²μ΄ λͺ©νμ΄λ―λ‘ 127.0.0.1:8000/vulnλ₯Ό μ΄μ©ν΄μ 곡격λμ ν΄λΌμ΄μΈνΈμμ μ
μ± μ€ν¬λ¦½νΈκ° μ€νλλλ‘ XSS payloadλ₯Ό μ μ‘ν΄μΌνλ€.
β’ memo νμ΄μ§ μλ λ°©μ
μ΄ μ½λλ κ°λ¨ν λ©λͺ¨μ₯μ ꡬννλ€.
text = request.args.get("memo", ""): μ¬μ©μλ "/memo" κ²½λ‘λ‘ μ μνμ¬ URLμμ "memo"λΌλ μΈμλ₯Ό λ°μμ¨λ€.
μλ₯Ό λ€μ΄, "/memo?memo=λ΅μ΄λ체λμΌ"κ³Ό κ°μ΄ μμ²μ΄ μ€λ©΄ "λ΅μ΄λ체λμΌ"λ₯Ό κ°μ Έμ¨λ€. (λ§μ½ "memo" μΈμκ° μλ€λ©΄ λΉ λ¬Έμμ΄("")μ κΈ°λ³Έκ°μΌλ‘ μ¬μ©νλ€.)
memo_text += text + "\n": κ°μ Έμ¨ ν μ€νΈλ₯Ό μ μ λ³μμΈ memo_textμ μΆκ°νλ€. μ΄λ κ°κ°μ λ©λͺ¨λ μ μ€λ‘ ꡬλΆλλ€.
return render_template("memo.html", memo=memo_text): "memo.html" ν νλ¦Ώμ λ λλ§νκ³ , νμ¬κΉμ§μ λ©λͺ¨λ₯Ό ν¨κ» μ λ¬νλ€. μ΄λ₯Ό ν΅ν΄ μ¬μ©μλ νλ©΄μμ λ©λͺ¨λ₯Ό νμΈν μ μλ€.
>> μ¬μ©μλ "/memo" κ²½λ‘λ‘ μ μνμ¬ ν μ€νΈλ₯Ό μ λ ₯νκ³ , μ΄μ μ μ λ ₯ν λ©λͺ¨λ€μ νμΈν μ μλ€.
μμ½
1. /vuln
:param νλΌλ―Έν°μμ XSS μ·¨μ½μ λ°μ
2. /memo
:memo νλΌλ―Έν°λ‘ νμ΄μ§μ λ°μ΄ν° μ μ₯ κ°λ₯
3. /flag
:check_xss(url,cookie) → read_url(url, cookie) → flagλ₯Ό μΏ ν€μ μ μ₯ → 127.0.0.1:8000/vuln?param=[μ λ ₯κ°]λ₯Ό 곡격 λμ λ΄μ΄ μμ²
/memoλ μμ² μ νλΌλ―Έν°λ₯Ό ν΅ν΄μ νΉμ κ°μ μ μ₯ν μ μλ κΈ°λ₯μ μννλ€.
κ·Έλ λ€λ©΄, botμ΄ 127.0.0.1:8000/memo?memo=[μΏ ν€] μ κ°μ΄ μμ²νλλ‘ XSS payloadλ₯Ό μ μ‘νλ©΄, /memoμ μΏ ν€μ λ΄κΈ΄ flagκ° μ μ₯λ κ²μ΄λ€.
곡격 μμλ₯Ό μ 리νλ©΄
1. /flagλ₯Ό ν΅ν΄ XSS νμ΄λ‘λ μ μ‘
2. botμ΄ /vuln μ ν΅ν΄ μ μ‘ν XSS νμ΄λ‘λλ₯Ό μ€ν
3. /memo μ botμ cookieκ° μ μ₯
XSSμμ μ¬μ©λλ λ€ κ°μ§ μ’ λ₯μ λ¬Έλ²:
<script>
alert("hello"); <!-- λ©μμ§ μΆλ ₯ -->
document.cookie; <!-- μΏ ν€κ° -->
location.href=""; <!-- ""λ΄μ λ§ν¬λ‘ μμΉ μ΄λ -->
document.location=""; <!-- "" λ§ν¬λ‘ μ΄λ -->
</script>
μΏ ν€λ₯Ό νμ·¨νκΈ° μν XSS payload
μμ λ¬Έλ² μ€ μΏ ν€κ°μ μΆλ ₯νλ document.cookieμ location.hrefλ₯Ό ν΅ν΄ memoμμ μΏ ν€λ₯Ό μΆλ ₯νλλ‘ μ½λλ₯Ό μ§λ³΄κ² λ€.
<script>location.href='http://127.0.0.1:8000/memo?memo='+document.cookie</script>
μμ μ½λλ₯Ό /flag νμ΄μ§μ μ λ ₯νκ³ μ μΆνλ©΄
vuln νμ΄μ§λ₯Ό κ±°μ³ memo νμ΄μ§μ document.cookieκ° μ μ₯λ κ²μ΄λ€.
μ λ΅!!
[4] λμ λ°©μ
(1) μ λ ₯κ° κ²μ¦ λ° κΈΈμ΄ μ ν
whitelist λλ blacklist λ°©μμΌλ‘ <script>κ°μ μ€ν¬λ¦½νΈ νκ·Έλ€μ λν λ¬Έμμ΄ κ²μ¦μ μννλ€.
(μ΄ λ¬Έμ μμλ λ¬Έμμ΄ κ²μ¦μ μννμ§ μλλ€.)
(2) HTML Entity μ¬μ©
XSSκ° λ°μνμ§μλλ‘ HTML νκ·Έλ€μ νΉμλ¬Έμλ‘ νννλλ‘ HTML Entityλ₯Ό μ¬μ©νλ€.
HTML Entityλ₯Ό μ¬μ©νλ©΄, 곡격μκ° <script>λ₯Ό μ λ ₯νλλΌλ μΆλ ₯μ <script>λ‘ λκΈ° λλ¬Έμ XSSκ° λ°μνμ§ μλλ€.
(3) HttpOnly νλκ·Έ μ€μ
λΈλΌμ°μ μμ μΏ ν€μ μ κ·Όν μ μλλ‘ HttpOnly νλκ·Έλ₯Ό μ€μ νλ€.
λ§μ½, XSSκ° λ°μνλλΌλ λΈλΌμ°μ κ° μΏ ν€μ μ κ·Όν μ μκΈ° λλ¬Έμ 곡격μλ μΏ ν€λ₯Ό νμ·¨ν μ μλ€.
[5] μ°Έκ³
https://keyme2003.tistory.com/entry/dreamhack-xss-1
https://goldsony.tistory.com/m/259
'SWLUG > μΉ ν΄νΉ' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[Dreamhack/λλ¦Όν΅] xss-2 (0) | 2023.11.06 |
---|---|
[xss-game] Level 5: Breaking protocol (3) | 2023.11.06 |
[Dreamhack/λλ¦Όν΅] DOM XSS (0) | 2023.11.05 |
[los.rubiya.kr] orc (1) | 2023.10.07 |
[los.rubiya.kr] goblin (1) | 2023.10.06 |