rsp-∞

[Dreamhack] xss-1 본문

Write-ups/web

[Dreamhack] xss-1

portrait.kim 2025. 4. 4. 15:27

 

서버를 생성하여 홈페이지를 먼저 본다.

 

첫 번째 vuln(xss)page 항목에 들어가 보았더니 아래 사진과 같은 알림창이 내려왔다.

 

1이 나왔는데, 이게 xss 취약점을 가지고 있다는 것을 알려 준다. 위 url을 보면 지금 <script>aler(1)</script> 명령어가 url에 포함되어 해당 스크립트가 실행되고 있다는 것을 알 수 있기 때문이다. 그렇다면 이 페이지는 <script> 태그에 내성이 없는 상태. 그러므로 우리가 <script> 태그를 사용하여 xss 취약점을 공략해 볼 수 있을 것이다.

 

그 다음은 memo 페이지에 들어가 본다. 

hello가 출력된다. url에 memo?memo=hello가 써 있는 것을 볼 수 있다. hello를 지우고 다르게 수정하면 어떻게 출력되나 보자.

 

 

hi라고 입력했더니 hi라고 메모장에 쓰인 걸 볼 수 있다. 그렇다면 저 url의 값을 조작함으로써 이 화면에 플래그를 출력시킬 수 있지 않을까?(사실 냅다 flag를 넣어서 url을 수정해 보기도 했다. ㅎㅎ)

 

문제 파일을 다운로드 받고 코드를 살펴보자.

 

#!/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)

 

활용할 수 있는 명령어로 location.href와 document.cookie가 있다. 문제가 자바 스크립트에 기반하고 있기 때문에 명령어를 html에서 실행시키기 위해 <script></script> 태그를 사용하면서, 위 두 개의 자바 스크립트 속성을 사용하면 문제를 풀 수 있다.

 

먼저 location.href는 해당 페이지의 url 주소를 나타낸다. 그러므로 이 값을 바꾸면 페이지 간의 이동이 가능하게 되고, 즉 뒤에 따라붙는 명령어가 실행되는 페이지를 다르게 할 수 있다. document.cookie는 브라우저에 저장된 쿠키 정보를 다룰 수 있는 속성이다. 문자열 형태로 쿠키를 읽고, =로 값을 지정해 설정할 수 있다.

 

코드를 살펴보면 /vuln 부분에서 사용자가 입력한 파라미터 값인 param을 그대로 return하고 있는 것을 볼 수 있다. 여기가 xss의 주요 진입점이라고 할 수 있다. 학회에서 OWASP 취약점 중 improper output handling을 다루며 xss의 두 가지 유형을 발표했는데, 여기서는 공격자가 직접 악성 스크립트를 url에 삽입하여 클라이언트를 대상으로 공격을 수행하는 reflected xss에 해당한다고 볼 수 있다.

 

read_url()과 check_xss()는 자동 방문 기능을 수행한다. 서버는 사용자가 입력한 param 값을 check_xss() 함수로 넘긴다. 사용자의 XSS 스크립트가 실행되면 봇이 쿠키를 포함한 정보에 노출될 수 있는데, 코드 34번째 줄의 driver.add_cookie(cookie)를 보면 flag인 쿠키 값을 들고 포함하고 있고 공격자가 xss 페이로드를 통해 이 쿠키 값을 탈취하면 flag를 획득할 수 있다. 이 내용을 포함한 파라미터를 전달하면 서버는 해당 파라미터를 포함한 url을 클라이언트가 방문하도록 하며 document.cookie에 접근이 가능하고, 해당 쿠키에 포함된 flag 값을 도출해 낼 수 있다.

 

코드의 끝에 보면 /memo라고 하여 memo 페이지가 어떻게 구성되는지 알 수 있는데, 필터링 없이 입력을 받아 html에 내보고 memo에서 출력하는 내용 뒤에 붙어 출력된다. 아래와 같이 페이로드를 작성하였다.

 

<script>location.href="/memo?memo=hello"+document.cookie;</script>

 

띄어쓰기, 따옴표, 세미콜론 등 조건이 꽤나 까다롭지만 전부 다 알맞게 되어야만... 플래그가 제대로 뜬다. 닫히는 따옴표가 앞에 붙어 한참 동안 플래그가 뜨지 않아 고생했던.

 

 

사진과 같이 memo에 플래그가 hello 뒤에 붙어 출력된 것을 알 수 있다. 내가 보낸 페이로드에서 url 자체를 memo=hello라고 설정해 놓았지만, 아마 hello를 지우면 flag=DH{....} 형식으로 출력될 것이다.

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

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