ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [webhacking] XSS-1 / XSS-2 문제 풀이
    해킹/wargame 2023. 3. 5. 16:04

    XSS (Cross Side Scripting)에 관한 문제 2개를 가져왔습니다.

    관련 개념 설명은 아래 포스팅을 참고해 주시기 바랍니다.

    https://white-hack.tistory.com/entry/webhacking-1-XSS-Cross-Site-Scripting-feat-SOP

     

    [webhacking] 1. XSS ( Cross Site Scripting ) / feat. SOP

    XSS 이란? 클라이언트 사이드 취약점 중 하나로, 공격자가 웹 리소스에 오리진 권한으로 악성 스크립트를 삽입하여 이용자가 그 사이트를 방문했을 때, 해당 악성 스크립트가 실행되어 세션 정보

    white-hack.tistory.com

     

     

     

    문제 1. XSS - 1

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

     

    xss-1

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

    dreamhack.io

     

     

     

    코드 분석

    #!/usr/bin/python3
    from flask import Flask, request, render_template
    from selenium import webdriver
    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:
            options = webdriver.ChromeOptions()
            for _ in [
                "headless",
                "window-size=1920x1080",
                "disable-gpu",
                "no-sandbox",
                "disable-dev-shm-usage",
            ]:
                options.add_argument(_)
            driver = webdriver.Chrome("/chromedriver", 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)

    엔드포인트는 총 3가지로, 각각 함수에 대해 살펴보겠습니다.

     

    1. /vuln : "param" 이라는 파라미터를 전달받고 그 값을 출력합니다.

    2. /flag : GET요청에는 flag.html을 보여주고, POST요청에는 param을 전달받은 후 쿠키를 포함하여 check_xss함수를 호출합니다.
      check_xss함수는 read_url함수를 통해 /vuln 엔드포인트에 접속합니다.

    3. /memo : "memo" 이라는 파라미터를 전달받고, 전역변수 memo_text에 저장한 후,
      render_template함수를 통해 memo.html에 값을 저장하고 출력합니다.

     

    /vuln 과 /memo 엔드포인트는 사용자의 입력을 출력하는데, /memo 엔드포인트가 render_template함수를 통해 HTML 엔티티 코드로 저장하기 때문에 XSS가 발생하지 않지만, /vuln 엔드포인트는 입력받은 값을 그대로 출력하기 때문에 XSS에 취약합니다.

     

     

     

     

     

     

    Exploit

    /flag 엔드포인트에서 text 상자에 XSS를 시도해 봅시다.

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

    다음과 같이 자바스크립트 코드를 넣어주게 되면, /memo 엔드포인트로 접속하고, memo 파라미터에 쿠키 값을 넣어주게 됩니다.

     

    이제 /memo 엔드포인트로 이동하게 되면 저장된 쿠키를 확인할 수 있습니다.

     

     

     

     

    취약점 보완법

    이용자의 입력값을 별다른 검증 없이 그대로 출력했기 때문에 XSS가 발생했습니다.

    악성태그를 필터링하는 HTML Sanitization을 이용하거나, render_template함수를 사용해 엔티티코드로 치환하는 것으로 보완할 수 있습니다.

     

     

     

     

     

     

     

    문제 2. XSS - 2

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

     

    xss-2

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

    dreamhack.io

     

     

    코드 분석

    #!/usr/bin/python3
    from flask import Flask, request, render_template
    from selenium import webdriver
    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:
            options = webdriver.ChromeOptions()
            for _ in [
                "headless",
                "window-size=1920x1080",
                "disable-gpu",
                "no-sandbox",
                "disable-dev-shm-usage",
            ]:
                options.add_argument(_)
            driver = webdriver.Chrome("/chromedriver", 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)

    문제 1과 비슷하지만, 차이점은 vuln() 함수가 위와는 다르게 render_template을 사용하여 엔티티코드로 치환하고 있습니다.

    따라서 위 문제와 똑같이 풀 수 없으므로, 이를 우회하는 기법을 사용해야 합니다.

     

     

    우선 /vuln 엔드포인트로 가서 XSS를 사용해봅시다.

    /vuln?param=<script>alert(1)</script>

    다음과 같이 param으로 script 태그를 전달하면 아무 반응이 없습니다.

    아마도 script 태그를 필터링하고 있는 것 같습니다.

     

     

     

     

    /vuln?param=<img src="https://www.google.co.kr/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png">

    위 src의 링크는 구글 사진입니다. img 태그를 사용하면 정상적으로 사진이 추가된 것을 확인할 수 있습니다.

    따라서 script태그가 아닌 img 태그를 이용해서 XSS를 사용해 볼 수 있습니다.

     

     

     

     

     

    Exploit

    다시 /flag 엔드포인트로 돌아와서 XSS를 사용해봅시다.

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

    위와 같이 onerror 이벤트로 memo의 엔드포인트로 이동하여 memo를 cookie로 전달하게 하면,

    문제 1과 같이 /memo 엔드포인트에 쿠키가 노출될 것입니다.

    • onerror는 이미지 로딩시 문제가 생겼을 때 호출됩니다. src=""로 설정하였기 때문에 onerror가 불릴 것입니다.

     

    /memo 엔드포인트에서 플래그를 얻어냈습니다.

     

    이 문제는 풀이 방법이 다양한 것 같습니다. 더 다양한 풀이는 구글에 XSS bypass sheet 또는 XSS cheat sheet라고 검색하시면 다양하게 XSS 필터링을 우회하는 방법이 나와있을 것입니다.

     

     

     

     

    취약점 보완법

    이 코드는 Flask로 짜여져 있고, 봇이 XSS 필터링을 하기 때문에 추가적인 우회에 대해서는 필터링 코드를 작성해야 합니다.

    <, > 같은 특수문자를 필터링하는 것이 하나의 방법이 될 수 있습니다.

     

    '해킹 > wargame' 카테고리의 다른 글

    [webhacking] cookie, session- basic 풀이  (0) 2023.03.03
    [web hacking] login filtering 풀이  (0) 2023.02.28
    [web hacking] strcmp 풀이  (0) 2023.02.28

    댓글

Designed by Tistory.