SWLUG/์›น ํ•ดํ‚น

[Dreamhack/๋“œ๋ฆผํ•ต] XSS Filtering Bypass

waterproof 2023. 11. 10. 22:07

 

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

 

XSS Filtering Bypass

Description Exercise: XSS Filtering Bypass์—์„œ ์‹ค์Šตํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ๋ฌธ์ œ ์ˆ˜์ • ๋‚ด์—ญ 2023.08.04 Dockerfile ์ œ๊ณต

dreamhack.io

 

 

 

 

๋ฌธ์ œ ์ œ๋ชฉ์„ ๋ณด์•„ํ•˜๋‹ˆ, xss ํ•„ํ„ฐ๋ง์„ ์šฐํšŒํ•ด์„œ ํ‘ธ๋Š” ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™๋‹ค.

 

์ผ๋‹จ ๋ฌธ์ œ ์›นํŽ˜์ด์ง€๋ฅผ ๋ถ„์„ํ•˜๊ณ , ๊ทธ ๋‹ค์Œ์— ๋ฐ›์€ ๋ฌธ์ œ ํŒŒ์ผ๋„ ๋ถ„์„ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

 

 


[1] ๋ฌธ์ œ ๋ถ„์„

 

# ๋ฌธ์ œ ํŽ˜์ด์ง€ ๋ถ„์„

 

 

์ดˆ๊ธฐ ํ™”๋ฉด์ด๋‹ค.

 

(1) /vuln(xss) page

 

/vuln(xss) page ๋ฅผ ๋“ค์–ด๊ฐ€๋ณด๋ฉด ๋‚˜์˜ค๋Š” ํ™”๋ฉด.

 

 

<img> ํƒœ๊ทธ๊ฐ€ ์‚ฌ์šฉ๋˜์—ˆ๋‹ค.

 

src๋Š” ์ด๋ฏธ์ง€ ํŒŒ์ผ์˜ URL์„ ์ง€์ •ํ•˜๊ณ ,

๋”ฐ๋ผ์„œ ์›น ํŽ˜์ด์ง€์—์„œ ํ•ด๋‹น https://dreamhack.io/assets/img/logo.0a8aabe.svg์— ์žˆ๋Š” ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋„๋ก ํ•œ๋‹ค.

 

 

(2) /memo

 

 

memo ํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐˆ ๋•Œ ๋งˆ๋‹ค 'hello'๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

 

URL์— /memo?memo=hello ๋ถ€๋ถ„์„ ๋ณด๋ฉด GET ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

/memo ํŽ˜์ด์ง€์— ํŒŒ๋ผ๋ฏธํ„ฐ memo์— hello๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ์ „์†กํ–ˆ๋‹ค๋Š” ์˜๋ฏธ๋กœ ๋ฐ›์•„๋“ค์ผ ์ˆ˜ ์žˆ๋‹ค.

 

 

 

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ?memo=hi๋ฅผ ์ „์†กํ•˜๋ฉด "hi"๋ผ๋Š” ๋ฉ”์„ธ์ง€๊ฐ€ ์ด ํŽ˜์ด์ง€์— ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์ด ํŽ˜์ด์ง€์˜ ์†Œ์Šค ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค,

 

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="/static/css/non-responsive.css">
    <title>Index XSS-Filtering-Bypass</title>
    
  
  <style type="text/css">
    .important { color: #336699; }
  </style>

  </head>
<body>

    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">XSS-Filtering-Bypass</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
          </ul>

          <ul class="nav navbar-nav navbar-right">
          </ul>

        </div><!--/.nav-collapse -->
      </div>
    </nav>

    <div class="container">
      
  <pre>hello
hi
</pre>

    </div> <!-- /container -->

    <!-- Bootstrap core JavaScript -->
    <script src="/static/js/jquery.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script> 
</body>
</html>

 

์Œ... ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์—†์—ˆ๋‹ค.

 

 

(3) /flag

 

 

/flag ํŽ˜์ด์ง€์˜ ํ™”๋ฉด์ด๋‹ค.

 

์ง€๊ธˆ๊นŒ์ง€ ๋“œ๋ฆผํ•ต์—์„œ ํ’€์—ˆ๋˜ xss ๋ฌธ์ œ๋“ค์€,

์ž…๋ ฅ ์นธ์— ๋ฌด์–ธ๊ฐ€๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์ œ์ถœํ•˜๋ฉด /memo ํŽ˜์ด์ง€์— ๋ฌธ์ œ์˜ ๋‹ต์ธ FLAG๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ์—ˆ๋‹ค.

 

์•„๋งˆ ์ด ๋ฌธ์ œ ๋˜ํ•œ ๋น„์Šทํ•œ ๋ฐฉ์‹์ผ ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ƒ๋œ๋‹ค. 

(๋‹ค์šด๋ฐ›์€ ๋ฌธ์ œ ํŒŒ์ผ์„ ์‚ดํŽด๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.)

 

 

 

๋‹ค์Œ์€ /memo ํŽ˜์ด์ง€์˜ ์†Œ์Šค ์ฝ”๋“œ์ด๋‹ค.

 

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="/static/css/non-responsive.css">
    <title>Index XSS-Filtering-Bypass</title>
    
  
  <style type="text/css">
    .important { color: #336699; }
  </style>

  </head>
<body>

    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">XSS-Filtering-Bypass</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
          </ul>

          <ul class="nav navbar-nav navbar-right">
          </ul>

        </div><!--/.nav-collapse -->
      </div>
    </nav>

    <div class="container">
      
  <form method="POST">
    http://127.0.0.1:8000/vuln?param=<input type="text" name="param"/><br/>
    <input type="submit"/><br/>
  </form>

    </div> <!-- /container -->

    <!-- Bootstrap core JavaScript -->
    <script src="/static/js/jquery.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script> 
</body>
</html>

 

์ด ์ฝ”๋“œ์—์„œ ํผ์€ POST ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋ฉฐ,

"http://127.0.0.1:8000/vuln?param="์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” URL๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ธ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

 

# ๋ฌธ์ œ ํŒŒ์ผ ๋ถ„์„

 

(1) app.py

 

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

def xss_filter(text):
    _filter = ["script", "on", "javascript:"]
    for f in _filter:
        if f in text.lower():
            text = text.replace(f, "")
    return text

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


@app.route("/vuln")
def vuln():
    param = request.args.get("param", "")
    param = xss_filter(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)

 

 flag๊ฐ’์„ ์ฐพ์•„๋‚ด๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ์ด๋ฏ€๋กœ, ์šฐ์„  ์ด ํŒŒ์ผ์—์„œ 'flag'๋ผ๋Š” ๋ฌธ์ž์—ด์ด ๋“ค์–ด๊ฐ„ ๋ถ€๋ถ„์„ ๋จผ์ € ๋ณด์•˜๋‹ค.

๊ทธ๋Ÿฌ๋‹ค๋ณด๋‹ˆ /flag ํŽ˜์ด์ง€์˜ ๊ตฌ๋™ ๋ฐฉ์‹์„ ๋‚˜ํƒ€๋‚ด๋Š” '@app.route("/flag", methods=["GET", "POST"])'๋ผ๋Š” ๋ถ€๋ถ„์„ ๋จผ์ € ๋ณด๊ฒŒ๋˜์—ˆ๋‹ค.

 

 

@app.route("/flag", methods=["GET", "POST"])

 

 

์ด ์ฝ”๋“œ๋Š” "/flag" ๊ฒฝ๋กœ(ํŽ˜์ด์ง€)์— ๋Œ€ํ•œ GET ๋ฐ POST ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

 

 

1. ๋งŒ์•ฝ ํด๋ผ์ด์–ธํŠธ๊ฐ€ GET ์š”์ฒญ์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, "flag.html" ํ…œํ”Œ๋ฆฟ์„ ๋ Œ๋”๋งํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

2. ๋งŒ์•ฝ ํด๋ผ์ด์–ธํŠธ๊ฐ€ POST ์š”์ฒญ์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, ์š”์ฒญ์œผ๋กœ๋ถ€ํ„ฐ "param"์ด๋ผ๋Š” ์ด๋ฆ„์˜ ํผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

 

 

(์—ฌ๊ธฐ์„œ "param"์ด๋ผ๋Š” ํผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฑธ ๋งํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.)

 

 

3. ๊ทธ๋ฆฌ๊ณ  check_xss ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด XSS ๊ณต๊ฒฉ์„ ํ™•์ธํ•œ๋‹ค. ๋งŒ์•ฝ xss ๊ณต๊ฒฉ์ด ๊ฐ์ง€๋˜๋ฉด, "wrong??"์ด๋ผ๋Š” ๊ฒฝ๊ณ  ๋ฉ”์„ธ์ง€๋ฅผ ํฌํ•จํ•œ ์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์ด์ „ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋„๋ก ํ•œ๋‹ค. ๋งŒ์•ฝ xss ๊ณต๊ฒฉ์ด ๊ฐ์ง€๋˜์ง€ ์•Š์œผ๋ฉด "good"์ด๋ผ๋Š” ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ํฌํ•จํ•œ ์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์ด์ „ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋„๋ก ํ•œ๋‹ค.

 

.

.

.

๊ทธ๋ ‡๋‹ค๊ณ  ํ•œ๋‹ค.

๊ทธ๋Ÿผ xss ๊ณต๊ฒฉ์„ ํ™•์ธํ•˜๋Š” check_xss ํ•จ์ˆ˜ ๋ถ€๋ถ„์„ ์‚ดํŽด๋ณด์ž.

 

 

def check_xss(param, cookie={"name": "name", "value": "value"})

 

 

check_xss ํ•จ์ˆ˜๋Š” param ๊ฐ’์„ ์‚ฌ์šฉํ•ด xss ๊ณต๊ฒฉ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด

์™ธ๋ถ€ URL (http://127.0.0.1:8000/vuln?param=<encoded_param>)๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ ,

return_url ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

.

.

.

์—ฌ๊ธฐ์„œ read_url ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด์ž.

 

 

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

 

 

์ด ํ•จ์ˆ˜์˜ ๋‚ด์šฉ์—๋Š” ๋‚˜๋„ ๋ชจ๋ฅด๋Š” ๋‚ด์šฉ์ด ๋งŽ์ด ์ ํ˜€์žˆ์–ด์„œ ์ฐพ์•„๋ดค๋Š”๋ฐ,

 

์š”์•ฝํ•˜๋ฉด read_url ํ•จ์ˆ˜๋Š”:

์™ธ๋ถ€ URL์— ๋Œ€ํ•œ ์š”์ฒญ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๊ณ , ํ•ด๋‹น ํŽ˜์ด์ง€์— ์ฟ ํ‚ค๋ฅผ ์ „๋‹ฌํ•œ ํ›„ XSS ๊ณต๊ฒฉ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐ ํ™œ์šฉ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

.

.

.

์—ฌ๊ธฐ์„œ๋Š” ํžŒํŠธ๋ฅผ ์–ป์ง€ ๋ชปํ•ด์„œ app.py ํŒŒ์ผ ์•ˆ์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„๋„ ์‚ดํŽด๋ณด์•˜๋‹ค.

 

@app.route("/vuln")

 

 

์ด ๋ถ€๋ถ„์€ "/vuln"(ํŽ˜์ด์ง€)์— ๋Œ€ํ•œ ๋ถ€๋ถ„์ด๋‹ค.

 

์ฝ”๋“œ ๋™์ž‘์„ ์„ค๋ช…ํ•˜์ž๋ฉด,


1. GET ์š”์ฒญ์œผ๋กœ๋ถ€ํ„ฐ "param" ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค. ๋งŒ์•ฝ "param"์ด ์—†์œผ๋ฉด ๋นˆ ๋ฌธ์ž์—ด๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.


2. ๊ฐ€์ ธ์˜จ "param" ๊ฐ’์„ xss_filter ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•˜์—ฌ XSS ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๋„๋ก ํ•„ํ„ฐ๋งํ•œ๋‹ค.

 

3. ํ•„ํ„ฐ๋ง๋œ "param" ๊ฐ’์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

.

.

.

์—ฌ๊ธฐ์„œ xss_filter ํ•จ์ˆ˜์—์„œ ์–ด๋–ป๊ฒŒ xss ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด, xss filter ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

 

def xss_filter(text):

 

 

์ด ํ•จ์ˆ˜์—์„œ๋Š” ์ฃผ์–ด์ง„ ํ…์ŠคํŠธ์—์„œ ํŠน์ • XSS ๊ณต๊ฒฉ๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ž์—ด์„ ํ•„ํ„ฐ๋งํ•˜์—ฌ ์ œ๊ฑฐํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

 

 

์ข€ ๋” ์ž์„ธํžˆ ๋™์ž‘์„ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค,:

 

1. _filter = ["script", "on", "javascript:"]:

ํ•„ํ„ฐ๋งํ•  ๋ฌธ์ž์—ด ํŒจํ„ด์„ ๋‹ด๊ณ  ์žˆ๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

"script", "on", "javascript:"์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

 

2. for f in _filter::

_filter ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ๋ฌธ์ž์—ด์„ ์ˆœํšŒํ•œ๋‹ค.

 

3. if f in text.lower()::

์ฃผ์–ด์ง„ ํ…์ŠคํŠธ์— ๋Œ€๋ฌธ์ž ๋˜๋Š” ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•œ ๋ฌธ์ž์—ด ์ค‘์— _filter์˜ ์›์†Œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•œ๋‹ค.

(๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ๊ฒ€์‚ฌํ•˜๊ธฐ ์œ„ํ•ด ํ…์ŠคํŠธ๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•œ ํ›„ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ.)

 

4. text = text.replace(f, ""):

ํ…์ŠคํŠธ์—์„œ _filter์— ํ•ด๋‹นํ•˜๋Š” ๋ฌธ์ž์—ด์„ ์ œ๊ฑฐํ•œ๋‹ค.

๋งŒ์•ฝ "script", "on", "javascript:" ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ๋ฌธ์ž์—ด์„ ๋นˆ ๋ฌธ์ž์—ด๋กœ ์น˜ํ™˜ํ•˜์—ฌ ์ œ๊ฑฐํ•œ๋‹ค.

 

5. return text:

ํ•„ํ„ฐ๋ง๋œ ํ…์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

 

์ •๋ฆฌํ•˜์ž๋ฉด

>> text๋ฅผ ๋ชจ๋‘ ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ "script", "on", "javascript:"๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๊ณ , ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ๋ฌธ์ž์—ด์„ ๋นˆ ๋ฌธ์ž์—ด๋กœ ์น˜ํ™˜ํ•˜์—ฌ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

.

.

.

๊ทธ๋ ‡๋‹ค๋ฉด text ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ •ํ™•ํ•œ ์˜๋ฏธ๋ฅผ ์•Œ๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ๋ถ€๋ถ„๋„ ์‚ดํŽด๋ณด์•˜๋‹ค.

 

 

@app.route("/memo")

 

 

์ด ๋ถ€๋ถ„์„ ํ›‘์–ด๋ณด๋‹ˆ def memo()์—์„œ์˜ 'text'๊ฐ€ def xss_filter(text)์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์“ฐ์ด๋Š” ๊ฒƒ ๊ฐ™์•˜๋‹ค.

 

 

์ข€ ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•˜์ž๋ฉด,

 

memo ํ•จ์ˆ˜์—์„œ text ๋ณ€์ˆ˜์— ํ• ๋‹น๋œ ๊ฐ’์€ ์‚ฌ์šฉ์ž๊ฐ€ "/memo"๋กœ ์ „์†กํ•œ GET ์š”์ฒญ์˜ "memo" ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜จ ๊ฐ’์ด๋‹ค.

์ด text ๋ณ€์ˆ˜๋Š” ์ดํ›„ memo_text ๋ณ€์ˆ˜์— ์ถ”๊ฐ€๋˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ „๋‹ฌ๋œ๋‹ค.

 

๋งŒ์•ฝ ์ด text ๊ฐ’์„ xss_filter ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•œ๋‹ค๋ฉด, xss_filter ํ•จ์ˆ˜์—์„œ ์ •์˜๋œ ํ•„ํ„ฐ๋ง์ด ์ ์šฉ๋˜์–ด XSS ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์„œ text ๋ณ€์ˆ˜๋Š” xss_filter ํ•จ์ˆ˜์˜ text ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

 


[2] ๊ณต๊ฒฉ ์‹œ๋„

 

 

/vuln ํŽ˜์ด์ง€์—์„œ

/vuln?param=<script>alert(1);<script> URL ๋’ค์— ์ž…๋ ฅํ•ด์ฃผ์—ˆ๋”๋‹ˆ

์—ญ์‹œ 'script'๊ฐ€ ํ•„ํ„ฐ๋ง๋˜์–ด์„œ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

 

 

NULL(%00)์„ ์‚ฌ์šฉํ–ˆ๋”๋‹ˆ ๊นจ์ง ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ๋‹ค.

์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

 

(๋‚˜์ค‘์— ๋ณด๋‹ˆ๊นŒ ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ ๋‹ซ๋Š” ๋ถ€๋ถ„์— </script>์—์„œ '/'์ด ๋น ์กŒ๋‹ค...ใ…Žใ…Ž ๊ทธ๋ฆฌ๊ณ  %00 ๋ฐ”๋กœ ๋‹ค์Œ์— ๋ฌธ์ž ํ•˜๋‚˜๋ฅผ ์ž…๋ ฅ์‹œ์ผœ์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ๋„ ๊นŒ๋จน์—ˆ๋‹ค... ์–ด์ฐŒ๋˜์—ˆ๋“  NULL์„ ์‚ฌ์šฉํ•˜๋ฉด ๊นจ์ ธ์„œ script๋Š” ์ธ์‹์ด ์•ˆ ๋จ!)

 

 

 

์™•!

ํ•„ํ„ฐ๋ง ๋˜๋Š” ํ‚ค์›Œ๋“œ ์‚ฌ์ด์— ์ƒˆ๋กœ์šด ํ‚ค์›Œ๋“œ๋ฅผ ๋„ฃ์–ด๋‘๋Š” ๊ฒฝ์šฐ ์šฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž์—ด ์น˜ํ™˜ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ๋”๋‹ˆ ๊ณต๊ฒฉ์— ์„ฑ๊ณตํ•˜์˜€๋‹ค!

 

๊ทธ๋ ‡๋‹ค๋ฉด ๊ณต๊ฒฉ์€ ๋ฌธ์ž์—ด ์น˜ํ™˜ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

 

์ด์ œ ์ „์— ํ’€์—ˆ๋˜ xss ๋ฌธ์ œ์—์„œ <svg onload="location.href = '/memo?memo=' + document.cookie"> ์ฝ”๋“œ์— ๋ฌธ์ž์—ด ์น˜ํ™˜ ๋ฐฉ๋ฒ•์„ ์ ์šฉ์‹œ์ผœ

์ฟ ํ‚ค ๊ฐ’์— ์ €์žฅ๋œ flag๊ฐ’์„ ์ฝ์–ด์˜ฌ ๊ฒƒ์ด๋‹ค.

 

<svg oonnload="locatioonn.href = '/memo?memo=' + document.cookie"> ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

(์ฒ˜์Œ์— location์—๋„ 'on'์ด ๋“ค์–ด๊ฐ„ ๊ฒƒ์„ ๋†“์น˜๊ณ  ๊ณ„์† "hello"๊ฐ€ ์ถœ๋ ฅ๋˜์–ด์„œ ๋‹นํ™ฉํ–ˆ๋‹ค.)

 

 

 

 

ํ’€์ด ์™„๋ฃŒ!

 


[3]๋Š๋‚€ ์ 

 

์˜ค๋žœ๋งŒ์— ํŒŒ์ด์ฌ ์ฝ”๋“œ๋ฅผ ์œ ์‹ฌํžˆ ๋“ค์—ฌ๋‹ค๋ณด๋‹ˆ ๋ฐฐ์› ๋˜ ๊ธฐ์–ต์ด ๋‹ค์‹œ ๋‚ฌ๋‹ค.

ํ•จ์ˆ˜์™€ ๋ณ€์ˆ˜๊ฐ€ ์„ ์–ธ๋˜๊ณ  ํ˜ธ์ถœ๋˜๋Š” ์œ ๊ธฐ์ ์ธ ๊ณผ์ •์„ ๋”ฐ๋ผ๊ฐ€๋Š” ๊ฒƒ์ด ๋‚˜๋ฆ„ ์žฌ๋ฏธ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.

์™œ ๋ณดํ†ต python์„ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํŒŒ์ผ์„ ๋งŒ๋“œ๋Š”์ง€๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค. (ํŒŒ์ด์ฌ์˜ ๊ธฐ๋Šฅ์ด ๋‹ค์–‘ํ•ด์„œ ๊ทธ๋Ÿฐ ๊ฒƒ์ผ๊นŒ?)

 

 

 

'SWLUG > ์›น ํ•ดํ‚น' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Dreamhack/๋“œ๋ฆผํ•ต] csrf-2  (1) 2023.11.11
[Dreamhack/๋“œ๋ฆผํ•ต] csrf-1  (0) 2023.11.10
[webhacking.kr] Challenge old-23  (0) 2023.11.09
[Dreamhack/๋“œ๋ฆผํ•ต] xss-2  (0) 2023.11.06
[xss-game] Level 5: Breaking protocol  (3) 2023.11.06