rsp-∞

[Dreamhack] csrf-1 본문

Write-ups/web

[Dreamhack] csrf-1

portrait.kim 2025. 4. 4. 16:29

사이트에 들어가서 이번에도 vuln(csrf) page 항목에 들어가 본다. 아래와 같이 출력을 볼 수 있다.

 

url을 보면 <script> 태그를 쓰고 있는데 *로 치환되어 제대로 출력이 되지 않은 것을 볼 수 있다. 이것을 보고 이 문제에서는 필터링 같은 걸 사용하고 있나? 하고 생각했다. 그렇다면 이 문제에서도 <script> 태그를 사용하는 것은 불가능할 듯하다. 코드를 살펴보자.

 

#!/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()
        print(str(e))
        # return str(e)
        return False
    driver.quit()
    return True


def check_csrf(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", "").lower()
    xss_filter = ["frame", "script", "on"]
    for _ in xss_filter:
        param = param.replace(_, "*")
    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_csrf(param):
            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", None)
    if text:
        memo_text += text
    return render_template("memo.html", memo=memo_text)


@app.route("/admin/notice_flag")
def admin_notice_flag():
    global memo_text
    if request.remote_addr != "127.0.0.1":
        return "Access Denied"
    if request.args.get("userid", "") != "admin":
        return "Access Denied 2"
    memo_text += f"[Notice] flag is {FLAG}\n"
    return "Ok"


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

 

/vuln을 보면 param을 그대로 반환하고 있지만, 예상한 것과 같이 script, frame, on을 필터링하고 있다. 그렇다면 xss-2에서 사용한 <iframe>도 사용할 수 없고, 외에 자주 쓰이는 <onclick>, <onload> 등도 사용할 수 없을 것이다. 또한 

 

그리고 이하 코드가 중요한 내용을 담고 있다고 생각해서 따로 떼어 놓고 볼 필요가 있다고 생각했다.

 

@app.route("/admin/notice_flag")
def admin_notice_flag():
    global memo_text
    if request.remote_addr != "127.0.0.1":
        return "Access Denied"
    if request.args.get("userid", "") != "admin":
        return "Access Denied 2"
    memo_text += f"[Notice] flag is {FLAG}\n"
    return "Ok"

 

함수 이름이 admin_notice_flag이다. userid라는 값에 admin이 저장되어 있으면 flag가 어떤 값인지 출력해 주는 코드이다. 또한 이전에 xss 워게임 두 문제와 같이 flag 값을 memo_text에 추가하여 memo 항목에서 확인 가능하도록 하고 있다. 그 과정에서 notice_flag를 거치고 있지만, 코드를 보면 결국 플래그가 memo_text에 추가되어 출력되는 페이지는 memo라는 것을 알 수 있다. 그렇다면 페이로드에서 userid를 admin으로 수정해 주는 명령어를 입력하면 플래그가 화면에 뜨지 않을까? 

 

여기까지는 생각할 수 있지만 중요한 것은 위 전체 코드에서 우리가 사용할 만한 태그들을 전부 필터링하고 있다는 것이다. 그렇다면 우리가 사용할 수 있는 태그는 무엇이 있을까. xss-2 라이트업에서 언급했던 다른 태그의 예시로 <img>가 있다. 이 태그를 사용해 보도록 하자.

 

<img src="/admin/notice_flag?userid=admin"/>

 

입력한 페이로드는 위와 같다. 이전에 설명했던 것처럼 src는 불러 올 다른 웹 페이지를 지정하기 위한 속성이고, 위 코드에서 보았던 것처럼 /admin/notice_flag에 접속하여 userid를 admin으로 설정해 준다. 그리고 플래그가 memo_text에 추가되어 출력되었을 memo 항목에 들어가 본다.

 

 

플래그를 획득할 수 있었다.

'Write-ups > web' 카테고리의 다른 글

[Dreamhack] csrf-2  (0) 2025.04.04
[Dreamhack] xss-2  (0) 2025.04.04
[Dreamhack] xss-1  (0) 2025.04.04
[DreamHack] session-basic  (0) 2025.03.27
[DreamHack] cookie  (0) 2025.03.27