1. ๋ฌธ์
https://dreamhack.io/wargame/challenges/28
2. ํด๊ฒฐ ๊ณผ์
(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**]"
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
def check_xss(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)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
return param
@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>'
memo_text = ""
@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)
app.run(host="0.0.0.0", port=8000)
vuln๊ณผ memo ํ์ด์ง๋ ์ด์ฉ์์ ์ ๋ ฅ๊ฐ์ ์ถ๋ ฅํ๋ค.
memo๋ render_template ํจ์๋ฅผ ์ฌ์ฉํด memo.html์ ์ถ๋ ฅํ๊ณ . render_template ํจ์๋ ์ ๋ฌ๋ ํ ํ๋ฆฟ ๋ณ์๋ฅผ ๊ธฐ๋กํ ๋ HTML ์ํฐํฐ์ฝ๋๋ก ๋ณํํด ์ ์ฅํ๊ธฐ ๋๋ฌธ์ XSS๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
๊ทธ๋ฌ๋ vuln์ ์ด์ฉ์๊ฐ ์ ๋ ฅํ ๊ฐ์ ํ์ด์ง์ ๊ทธ๋๋ก ์ถ๋ ฅํ๊ธฐ ๋๋ฌธ์ XSS๊ฐ ๋ฐ์ํ๋ค.
@app.route("/vuln")
def vuln():
param = request.args.get("param", "") # ์ด์ฉ์๊ฐ ์
๋ ฅํ vuln ์ธ์๋ฅผ ๊ฐ์ ธ์ด
return param # ์ด์ฉ์์ ์
๋ ฅ๊ฐ์ ํ๋ฉด ์์ ํ์
(2) ํ์ด์ง ์ ์
- vuln(xss) page์ ๋ค์ด๊ฐ๋ฉด ํ๋ผ๋ฏธํฐ์ ๋ค์ด๊ฐ ์คํฌ๋ฆฝํธ๊ฐ ๋์ํ๋ค.
- memo ํ๋ฉด
- memo ํจ์๋ flag ์ ์ ๋ ฅํ ๊ฐ์ด ์ฑ๊ณต์ ์ถ๋ ฅ๋๋ ํ์ด์ง์ด๋ค.
- flag ํ๋ฉด
- flag ํจ์๋ ์คํฌ๋ฆฝํธ ์ธ์ด๋ฅผ ๊ธฐ์ ํ์ฌ, vuln ํ์ด์ง์ ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐ์ํ์ฌ ๊ณต๊ฒฉํ๋ ํ์ด์ง์ด๋ค.
์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด, ๋ฉ์๋์ ๋ฐ๋ฅธ ์์ฒญ๋ง๋ค ๋ค๋ฅธ ๊ธฐ๋ฅ์ ์ํํ๋ ๊ฒ์ ์ ์ ์๋ค.
GET์ ์ด์ฉ์์๊ฒ URL์ ์ ๋ ฅ๋ฐ๊ณ ,
POST๋ params ํ๋ผ๋ฏธํฐ์ ๊ฐ๊ณผ ์ฟ ํค์ FLAG๋ฅผ ํฌํจํด check_xss ํจ์๋ฅผ ๋ฆฌํดํ๋ค.
check_xss๋ read_url ํจ์๋ฅผ ํธ์ถํด ๋ก์ปฌ ํ์ด์ง์ vuln ํ์ด์ง์ ์ ์ํ๋ค.
์ฌ๊ธฐ์ read_url์ ๋ํด ์ดํดํ๊ธฐ ์ ์ ์ ๋ ๋์์ ๋ํด์ ์ดํดํ๊ณ ๋์ด๊ฐ์ผ ํ๋ค.
์ ๋ ๋์ (Selenium)์ ์น ์ ํ๋ฆฌ์ผ์ด์ ํ ์คํ ์ ์ฌ์ฉ๋๋ ํ์ด์ฌ ๋ชจ๋๋ก, ์๋ต์ ํฌํจ๋ Javascript, CSS์ ๊ฐ์ ์น ๋ฆฌ์์ค๋ฅผ ์น ๋๋ผ์ด๋ฒ๋ฅผ ํตํด ํด์ํ๊ณ ์คํํ๊ธฐ ๋๋ฌธ์ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด ํ์ด์ง๋ฅผ ๋ฐฉ๋ฌธํ๋ ๊ฒ๊ณผ ๊ฐ์ ์ญํ ์ ํ๋ค.
- ์ฟ ํค ์ค์ :
- cookie={"name": "name", "value": "value"}: ํจ์ ์ธ์๋ก ๊ธฐ๋ณธ ์ฟ ํค๋ฅผ ๋ฐ๋๋ค.
- cookie.update({"domain": "127.0.0.1"}): ์ฟ ํค์ ๋๋ฉ์ธ์ ์ถ๊ฐํ๋ค. ์ด ๊ฒฝ์ฐ, ๋ก์ปฌ ํธ์คํธ ์ฃผ์์ธ 127.0.0.1์ ์ฌ์ฉํ๋ค.
- ์น ๋๋ผ์ด๋ฒ ์ค์ :
- Service(executable_path="/chromedriver"): Selenium์์ Chrome ์น ๋๋ผ์ด๋ฒ์ ์์น๋ฅผ ์ง์ ํ๋ค.
- webdriver.ChromeOptions(): ํฌ๋กฌ ์ต์ ์ ์ค์ ํ๊ธฐ ์ํ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค.
- ์ต์ ์ถ๊ฐ: ์ฌ๋ฌ ๊ฐ์ง ํฌ๋กฌ ์ต์ ์ ์ถ๊ฐํ์ฌ ๋ธ๋ผ์ฐ์ ์ ๋์์ ์กฐ์ ํ๋ค. ์๋ฅผ ๋ค์ด headless ๋ชจ๋๋ GUI ์์ด ๋ธ๋ผ์ฐ์ ๋ฅผ ์คํํ๋ฉฐ, window-size=1920x1080๋ ์ฐฝ ํฌ๊ธฐ๋ฅผ ์ง์ ํ๋ค.
- ์น ๋๋ผ์ด๋ฒ ์ด๊ธฐํ ๋ฐ ์ค์ :
- webdriver.Chrome(service=service, options=options): ์ค์ ํ ์ต์ ๊ณผ ์๋น์ค๋ฅผ ์ฌ์ฉํ์ฌ Chrome ๋๋ผ์ด๋ฒ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค.
- driver.implicitly_wait(3): ์น ์์๊ฐ ๋ก๋๋ ๋๊น์ง ์ต๋ 3์ด๊ฐ ๋๊ธฐํ๋ค.
- driver.set_page_load_timeout(3): ํ์ด์ง ๋ก๋ ์๊ฐ ์ ํ์ 3์ด๋ก ์ค์ ํ๋ค.
- ์น ํ์ด์ง ์ ์:
- driver.get("http://127.0.0.1:8000/"): ๋จผ์ ๋ก์ปฌ ์๋ฒ์ ๋ฃจํธ URL๋ก ์ด๋ํ๋ค. ์ด ๋จ๊ณ๋ ์ฟ ํค๋ฅผ ์ค์ ํ๊ธฐ ์ํ ์ด๊ธฐ ์ ๊ทผ ๋จ๊ณ๋ก ์ฌ์ฉ๋๋ค.
- driver.add_cookie(cookie): ์์ ์ค๋นํ ์ฟ ํค๋ฅผ ๋ธ๋ผ์ฐ์ ์ธ์ ์ ์ถ๊ฐํ๋ค.
- driver.get(url): ์ค์ ๋ก ์ ๊ทผํ๊ณ ์ ํ๋ ์น ํ์ด์ง๋ก ์ด๋ํ๋ค. ์ฌ๊ธฐ์ url์ ํจ์ ์ธ์๋ฅผ ํตํด ๋ฐ์ ๋์ ์ฃผ์์ด๋ค.
- ์์ธ ์ฒ๋ฆฌ
์ฆ, flag ํ์ด์ง์์ vuln ํ์ด์ง์ ์ทจ์ฝ์ ์ ์ด์ฉํ์ฌ flag์ value(์ฟ ํค๊ฐ)์ ํ์ทจํ๊ณ ์ด๋ฅผ memo ํ์ด์ง์ ์ถ๋ ฅํ๋ค.
flag ํ์ด์ง์์ ๋ค์๊ณผ ๊ฐ์ ์ต์คํ๋ก์ ์ฝ๋๋ฅผ ์ ๋ ฅํ๋ค.
vuln ํ์ด์ง์ ์ทจ์ฝ์ ์ ์ด์ฉํด ๋ก์ปฌ์ ๋ฉ๋ชจ ํ์ด์ง์ ํ๋ผ๋ฏธํฐ์ ์ฟ ํค๊ฐ์ ๋ถ์ฌ ์ด๋ํ๋๋ก ํ๋ ๊ฒ์ด๋ค.
<script>location.hraf = "http://127.0.0.1:8000/memo?memo="+document.cookie</script>