XSS(Cross site script)

XSS는 chrome, safari에서 발생할 수 있는 취약점으로 브라우저에서 동작하는 자바스크립트 코드를 다른 공격자에 의해서 실행되는 공격이다

예를 들어서 이용자가 웹 페이지에 접속한다면 브라우저에서 소켓 프로그래밍을 통해 웹 서버에 커넥션을 맺도록 할 것이고(3 way handshake) 이후에 restful API 통신에 의해 html을 받아온 뒤 html 코드를 브라우저에서 랜더링하여 사용자의 눈에 보여질 것이다.

따라서 실 통신에서 전달되는 것은 unicode 형식의 text가 server와 client 사이에 송수신 될 것이다.

여기서 브라우저에서 랜더링 할 때 DOM 형식의 코드는 눈에 보이는 형태로 랜더링 될 것이고 script 테그 내에 존재하는 것들은 브라우저 내의 console, 즉 js 엔진에서 동작한다.

js engine 에서는 javascript가 동작하고 html 코드에서 javascript 코드를 실행할 때 동작한다.

그렇다면 게시판 등 사용자의 입력에 html 코드를 입력할 수 있다면 다른 사람이 그 글을 읽을 때 악의적인 js를 실행할 수 있을것이다.

이러한 행동으로 악성 스크립트를 페이지에 심는다면 C&C 서버로 이동시키거나 브라우저를 exploit하여 RCE(원격코드실행)등을 통해 추가적인 공격이 가능할 것이다.

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"})
    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)

위 코드는 XSS를 실습하기 위해 만들어진 워게임 문제이다.

코드를 보면 flag라는 페이지를 보면 사용자가 입력한 주소를 셀레니움으로 접속하게 되어있고 vuln이라는 페이지를 이용하면 XSS payload가 동작하게 되어 있다.

따라서 해당하는 페이지를 이용해 XSS공격을 수행하면 서버측에서 셀레니움으로 동작하므로 셀레니움의 쿠키를 가져온다면 플래그를 획득할 수 있다.

<script>location.href=`/memo?memo=${document.cookie}`;</script>

위에 해당하는 페이로드를 입력하면 플래그 획득이 가능하다.

Untitled