[WEB] xss-1 문제풀이

XSS(Cross Site Script) 취약점이란 웹 어플리케이션에서 사용자 입력 값에 대한 필터링이 제대로 이루어지지 않을 경우, 공격자가 입력이 가능한 폼에 스크립트 삽입이 가능하여 악의적인 스크립트가 희생자 측에서 동작하도록 하는 취약점을 말한다. 공격자는 취약점을 이용하여 사용자의 개인정보 및 쿠키정보 탈취, 악성코드 감염, 웹 페이지 변조 등의 공격을 수행한다.

문제를 확인해보자.

 

 

입력받은 URL을 확인하는 봇이 구현된 서비스에서

XSS 취약점을 이용해 flag.txt에 존재하는 FLAG 변수를 읽는 문제이다.

문제 페이지에 접속해보자.

 

 

접속 가능한 페이지가 3개나 있다. 차례대로 들어가보자.

 

1) xss 페이지

 

xss 파라미터로 입력된 값을 전송하면, 페이지 응답 시 해당 변수가 페이지 내 삽입된다.

위 과정에서는 xss 파라미터 값으로 스크립트 구문이 삽입되어, 페이지 응답 시 해당 스크립트가 동작한다.

 

 

2) memo 페이지

 

memo 파라미터로 입력된 값을 전송하면 페이지 응답 시, 해당 변수가 페이지 내 삽입된다.

xss 페이지와 유사하다.

 

3) flag 페이지

 

xss 파라미터에 test 입력 후 전송 시, "good"이라는 알림창이 뜬다.

 

일단은 소스코드를 확인해보자.

 

#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for, session, g
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(f'http://127.0.0.1:8000/xss?xss={urllib.parse.quote(url)}')
    except:
        driver.quit()
        return False
    driver.quit()
    return True

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

@app.route('/xss')
def xss():
    xss = request.args.get('xss', '')
    return xss

@app.route('/flag', methods=['GET', 'POST'])
def flag():
    if request.method == 'GET':
        return render_template('flag.html')
    elif request.method == 'POST':
        xss = request.form.get('xss')
        if not read_url(xss, {'name': 'flag', 'value': FLAG}):
            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', None)
    if text:
        memo_text += text.replace('<', '&lt;') + '\n'
    return render_template('memo.html', memo=memo_text)

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

 

1) xss 페이지에서는 문자열 필터링이 없기 때문에 xss 파라미터에 스크립트 구문을 삽입할 경우 해당 구문이 동작한다.

 

2) memo 페이지에서는 replace 함수를 이용하여 memo 파라미터에 '<' 문자열을 '&lt' 문자열로 치환하기 때문에 별도의 우회로직이 존재하지 않는 한, 스크립트 구문을 삽입하기가 어렵다.

 

3) flag 페이지에서는 read_url 함수를 실행시키며 함수 정상 동작 시 "good" 알람창을 띄운다.

 

 

read_url 함수의 선언은 read_url(url, cookie={'name': 'name', 'value': 'value'}) 이며,

flag()에서 read_url은 read_url(xss, {'name': 'flag', 'value': 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(f'http://127.0.0.1:8000/xss?xss={urllib.parse.quote(url)}')
    except:
        driver.quit()
        return False
    driver.quit()
    return True

 

read_url  함수가 실행되면

1) driver.get('http://127.0.0.1:8000/')

    => 로컬호스트 환경에서 웹 페이지를 접속한다.

 

2) driver.add_cookie(cookie)           

    => 접속한 웹 페이지에 매개변수로 받아온 cookie를 추가한다.

 

3) driver.get(f'http://127.0.0.1:8000/xss?xss={urllib.parse.quote(url)}') 

    => 매개변수로 받아온 xss 값을 이용하여 xss 페이지에 접속한다.

 

정리하면 flag 페이지에서 xss 값을 입력 후 전송하면, 

로컬호스트 환경에서 웹 페이지 접속 후, FLAG 값을 쿠키로 추가하며 

사용자로부터 입력받은 xss 값을 이용하여 xss 페이지를 실행한다.

 

따라서 flag 페이지에서 xss 파라미터를 조작하여 

로컬호스트 환경에서 FLAG가 적힌 쿠키 값이 추가되면, 

해당 쿠키값을 memo 페이지의 매개변수로 전달하고 memo 페이지에 FLAG를 작성하도록 한다.

 

공격구문: xss=<script>window.open('http://127.0.0.1:8000/memo?memo='+document.cookie)</script>

=> 'http://127.0.0.1:8000/memo?memo={현재 로컬의 쿠키 값}' 페이지를 새 창으로 여는 스크립트 구문

=> memo 페이지에 FLAG가 삽입된 로컬의 쿠키 값 인자 값으로하여 작성하는 것으로 이해하면 된다.

 

 

로컬에서 FLAG를 따와서 memo 페이지로 쓰는 구문을 작성하고 제출하기를 누른다.

 

 

memo 페이지에 접속하면 FLAG 값이 메모로 작성되어 있는 것을 볼 수 있다.

 

소스코드 너무 복잡하다.

소스코드를 이해하는 게임인건가

으아아아아아ㅏ악

 

문제풀이 끗

 

 

 

 

복사했습니다!