https://dreamhack.io/wargame/challenges/26/

해당 문제는 CSRF 취약점을 사용해 플래그를 획득하는 문제이다.
서버 생성 후 사이트를 들어가본다.
총 5개의 페이지가 존재한다.

@app.route("/")
def index():
return render_template("index.html")

@app.route("/vuln")
def vuln():
param = request.args.get("param", "").lower()
xss_filter = ["frame", "script", "on"]
for _ in xss_filter:
param = param.replace(_, "*")
return param
이 문제는 xss문제가 아니므로 xss에 관련 공격을 필터링 걸어놨다.
frame, script, on이 3가지 키워드가 들어가는 문자열은 *으로 치환한다.

memo_text = ""
@app.route("/memo")
def memo():
global memo_text
text = request.args.get("memo", None)
if text:
memo_text += text
return render_template("memo.html", memo=memo_text)
memo 파라미터의 값을 기록하고, render_template를 사용해 출력한다.

@app.route("/admin/notice_flag")
def admin_notice_flag():
global memo_text
if request.remote_addr != "127.0.0.1":
return "Access Denied"
if request.args.get("userid", "") != "admin":
return "Access Denied 2"
memo_text += f"[Notice] flag is {FLAG}\n"
return "Ok"
로컬 호스트(127.0.0.1)에서 유저 아이디가 "admin"일 때 플래그를 획득할 수 있다.
memo 페이지에 플래그를 출력함을 알 수 있다.

@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_csrf(param):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
param 파라미터를 check_csrf 함수를 통해 참이면 good 메시지를 띄운다.
이래 아래 app.py에서 동작을 하는 함수들을 살펴보자
주요 코드
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()
print(str(e))
# return str(e)
return False
driver.quit()
return True
def check_csrf(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)
우선 위의 flag 페이지에서 check_csrf함수를 사용하였기에 이 함수 먼저 살펴보면 인자를 다시 CSRF 취약점이 발생하는 URL의 파라미터로 설정하고, read_url 함수를 이용해 방문한다.
read_url 함수에서 url은 서버가 동작하고 있는 로컬호스트의 이용자가 방문하는 시나리오이기 때문에 127.0.0.1의 호스트로 접속하게 된다.
/vuln 페이지에서 frame, script, on 키워드를 금지하였으나 <, >같은 태그를 사용할 수 있기 때문에 csrf 공격이 가능하게 된다.
<img src="/admin/notice_flag?userid=admin" />을 작성해 공격을 시도하면 플래그를 얻을 수 있다.

good 메시지가 출력이 되고, memo 페이지에 가보면 플래그가 쓰여져있을 것이다.
