워게임/web2

xss-1

maru_ 2026. 5. 28. 01:05

xss 문제를 풀어봄

 

여기서 selenium을 첨봤는데

-> 사람이 브라우저에서 하는 행동을 코드로 자동화해주는 도구

-> 웹크롤링, 웹테스트, 반복업무 자동화, 워게임의 victim봇으로 자주 사용됨

이런거라고 한다

 

위 문제는 reflected xss의 성격(?)을 보이는 xss 문제 같다는 생각을 했다

아래에서 코드랑 동작원리를 분석해볼것이지만,

일단 결론적으로 봤을 때 파라미터값에 들어간 값이 결국 서버에서 어떤 처리가 되지 않고, 그대로 응답으로 와서 브라우저에서 실행되면서 발생하는 xss취약점이기에 reflected xss라고 생각했다

 

문제 코드

#!/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"})
    driver = None
    try:
        service = Service(executable_path="/usr/local/bin/chromedriver")
        options = webdriver.ChromeOptions()
        options.binary_location = "/usr/bin/google-chrome"
        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:
        # return str(e)
        return False
    finally:
        if driver is not None:
            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)

 

read_url(), vuln(), check_xss(), flag(), memo() 이렇게 5개의 주요 함수들을 볼 수 있는데

먼저,

read_url()을 보면

def read_url(url, cookie={"name": "name", "value": "value"}):
...

driver.add_cookie(cookie)
driver.get(url)

url, cookie 값을 받고, cookie를 get, url을 get해서 접속(?)하는 걸 볼 수 있다,, 그럼 이 cookie랑 url를 추적해보면

check_css() 함수에서 

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)

url을 생성하고 있는데, /vuln ~~ 이렇게 보인다 

/vuln 을 보면

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

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>'

flag()를 보면,

post 요청일 때, param 값과 쿠키의 값을 flag로 check_xss을 실행하는 걸 볼 수 있다!

그리고 check_xss는 read_url로 반환하는 걸 볼 수 있다

그럼 만약 

이렇게 flag 페이지에서 param값을 입력해서 요청하면 쿠키값은 flag로 넘어갈것이고,, 그 쿠키값을 이제 내가 보도록 만들어줘야할 거 같은데,, 내가 flag값을 보기위해 활용할 페이지가 /memo 인듯,,

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)

이렇게 코드를 보면,

text에 "memo" 라는 파라미터값을 가져오는 걸 볼 수 있고, 또 memo_text는 누적되는 걸 볼 수 있음.

그럼 /memo 페이지로 리다이렉트 되면 저렇게 자동으로 텍스트가 기록되는 것이니까,
/flag에 <script>location.href = "/memo?memo"+document.cookie</script>

이렇게 작성해주면, 

flag를 확인 가능하다..

음,, 뭔가 하나하나 분석한 걸 쓰다 보니까 복잡해보이는 감이 있는데,

차근차근 다시 적어보면,,

1. 사용자가 /flag 페이지에 XSS payload를 제출
2. /flag 에서 check_xss()를 호출
   이때 flag 값이 쿠키 형태로 함께 전달된다.
3. check_xss()는 /vuln?param=payload 형태의 URL을 만듦
4. read_url()에서 Selenium 브라우저를 실행한다.
5. Selenium 브라우저에 flag 쿠키가 저장된다.
   driver.add_cookie(cookie)
6. Selenium 브라우저가 /vuln?param=payload에 접속한다.

   driver.get(url)

7. /vuln 페이지는 param 값을 그대로 반환한다.
8. 브라우저가 <script>location.href = "/memo?memo"+document.cookie</script>를 JavaScript로 실행한다.
9. document.cookie로 flag 쿠키를 읽는다.
10. location.href를 통해 /memo?memo=flag값 으로 이동한다.
11. /memo 페이지가 flag 값을 memo_text에 저장한다.
12. 사용자가 /memo에 접속해 flag를 확인한다.

 

이렇게 진행됐고,

핵심 취약점을 뽑자면

/vuln 에서 사용자의 입력값을 검증없이 그대로 반환해주는 부분이라고 생각한다 (reflected xss)

 

끝!

'워게임 > web2' 카테고리의 다른 글

csrf-2  (0) 2026.06.05
csrf-1  (0) 2026.06.04
xss-2  (0) 2026.06.02
session-basic (dream hack)  (0) 2026.05.15
아주 쉬운 cookie 문제  (0) 2026.05.14