본문 바로가기
Security_study/CTF,WARGAME Write-up

[Dreamhack] xss-1 write-up

by 1M9ur1 2023. 10. 25.

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

 

xss-1

여러 기능과 입력받은 URL을 확인하는 봇이 구현된 서비스입니다. XSS 취약점을 이용해 플래그를 획득하세요. 플래그는 flag.txt, FLAG 변수에 있습니다. 플래그 형식은 DH{...} 입니다. 문제 수정 내역

dreamhack.io

이 문제는 간단한 xss취약점을 이용한 워게임입니다.

 

일단 문제서버에 접속하여 보겠습니다.

문제에 vuln(xss)page, memo, flag세 가지 메뉴가 있습니다. 

일단 첫 번째 메뉴로 들어가보겠습니다.

접속 시 다음과 같은 알림창이 뜨게됩니다. 여기서 자세히 볼것은 URL주소를 자세히 봐야합니다. URL주소에는 script태그를 이용한 자바스크립트코드가 사용되었고 이는 곧 xss취약점이 발생할 수 있는 사이트라는 것입니다. 

두 번째 메뉴도 한번 들어가보겠습니다.

이 memo부분을 들어갈때 마다 hello라는 문자가 찍히고 있고 주소창에는 memo라는 변수에 hello라는 값이 있습니다.

다음과 같이 memo변수의 값을 저의 블로그 닉네임으로 변경하여보았더니 해당 값이 memo칸에 적히는 것을 확인할 수 있었습니다. 이걸로 memo라는 변수를 이용하면 해당 페이지에 글을 적을 수 있는것을 확인할 수 있엇습니다.

 

다음 메뉴인 flag라는 곳으로 들어가보겠습니다.

flag라는 사이트에는 해당 사이트에서 vuln메뉴의 param의 변수에 값을 보내는 칸이있다. 우리는 vuln페이지에는 xss공격이 쉽게 이루어지는 것을 확인하였고 이 부분에 xss공격을 통해 flag를 얻을 수 있는 방식으로 추측하였다.

사이트에 대해서는 어느정도 파악이 되었으니 문제 코드에 대해서 한번 살펴보겠다.

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

이것이 해당 문제의 코드다. 해당 코드를 보면 flag라는 부분에서 check_xss함수에 우리가 flag페이지 입력한 param부분과 플래그를 넘겨주고있다.

 

그리고 그 다음 check_xss함수에 대해서 확인해보겠다. check_xss함수는 param를 받고 우리가 보낸 플래그를 cookie에 넣고있다. 그 후에 url이라는 변수를 통해 우리가 입력한 param을 vuln페이지의 param변수에 진짜로 넣는 작업을 하고 url이라는 변수에 저장한다. 그리고 read_url을 url와 cookie와 함께 호출한다.

 

그 다음 read_url함수를 쭉 보다보면 driver.add_cookie(cookie)라는 부분을 통해 쿠키를 더해주는 것을 알 수 있고 이것은 cookie에 플래그가 있다는 것을 확인할 수 있다.

 

이런 점들을 종합해서 우리가 가지고있는 정보는 flag가 쿠키에 있다는 것, vuln페이지는 xss공격이 가능하다는 것 memo페이지의 memo변수에 입력한 값은 화면에 출력된다는 점을 이용하여 다음과 같이 페이로드를 작성할 수 있다.

 

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

loaction.href는 해당 주소로 이동하는 것이고 document.cookie는 cookie값을 적어주는 것이다. 이러한 기능을 이용하여 param의 값에 전달하여주면 memo페이지의 flag를 얻을 수 있다.