Webhacking-Write-Up/Dreamhack
[Dreamhack] CSP Bypass
SlowTurtle_
2023. 1. 10. 06:31
728x90
[Dreamhack] CSP Bypass
우선 코드를 보자.
#!/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)
nonce = os.urandom(16).hex()
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)
@app.after_request
def add_header(response):
global nonce
response.headers[
"Content-Security-Policy"
] = f"default-src 'self'; img-src https://dreamhack.io; style-src 'self' 'unsafe-inline'; script-src 'self' 'nonce-{nonce}'"
nonce = os.urandom(16).hex()
return response
@app.route("/")
def index():
return render_template("index.html", nonce=nonce)
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
return param
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html", nonce=nonce)
elif request.method == "POST":
param = request.form.get("param")
if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
return f'alert("wrong??");history.go(-1);' return f'alert("good");history.go(-1);' 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, nonce=nonce) app.run(host="0.0.0.0", port=8000)
우선 /vuln을 보면 아무런 필터링조차 하지 않고 입력값을 페이지에 출력함으로써 XSS공격이 쉽게 가능해보인다. memo부분은 render_template함수를 이용해서 memo.html을 출력하는데 render_template함수가 변수를 HTML 엔티티코드로 변환하여 저장하기 때문에 XSS공격을 이용할 수 없다. 또한 none은 계속 바뀌어 생성되어 예측한다는 것은 불가능이다.
그렇다면 vuln을 이용해서 스크립트를 실행시켜보자.
<script src='/vuln?param=alert(1)'></script>
alert(1)이 정상적으로 실행되는 것을 알 수 있다. 이것을 document.location과 document.cookie를 활용해서 조금 수정해서 memo페이지에 받아보자.
<script src="/vuln?param=document.location='/memo?memo='+document.cookie"></script>
왜 안될까...싶어서 이것저것 계속 바꿔보고 시도하다가 힌트를 얻기위해 드림핵 함께실습을 보았는데...
스크립트 부분은 두 단계에 거쳐서 파라미터로 해석되기때문에 URL 디코딩되어 공백으로 해석되었기 때문이었다..
그렇다면 +를 인코딩하면 %2b가 나오기때문에 +대신 %2b를 넣어 다시 제출해봤다.
flag값을 획득할 수 있었다.
728x90