초심자이기 때문에 하나부터 열까지 매우 세세하게 작성할 예정이다. 모든걸 이해하고 넘어가고 싶다. 다만 틀릴수도 있다.. !
파일이 깨지면 https://zzczzc123.notion.site/Dreamhack-XSS-1-45026e8388c0430a8751054d5a207024 로 가서 보자
문제분석
처음에 접속하게 되면
그림과 같은 페이지가 나오게 된다.
먼저 vuln(xss) page 부터 눌러보면 그림과 같이 뜨는걸 확인할 수 있다. 또 빨간박스를 보면 script가 들어가서 실행되는걸 확인할 수 있는데 이 말인 즉슨 XSS가 가능하다는 말이다.
두번째로 memo 실행화면이다. 하얀색 박스에 hello 라고 적하는걸 확인할 수 있다. vuln 페이지에 들어가서 XSS를 하면 하얀색 박스에 문구가추가되는것 같다. (한번 더 XSS해봤더니 또 hello 라고 뜨더라).
다음은 flag 페이지이다. 무언가 입력할 수 있는 박스가 하나 있고 입력을 하면 good 이라는 pop-up 창이 하나 뜬다. 그리고 memo에도 hello 문구가 또 추가된다. 여기에도 무슨 관계가 있구나 정도만 파악하고 넘어가자.
지금까지 내용을 정리하면 flag, memo, vuln 페이지에 어떠한 관계로 얽혀있는것 같고.. flag 페이지에 어떠한 값을 넣어야지 이 문제를 풀 수 있을것 같은 느낌이 든다.
그럼 그 느낌이 맞는지 소스코드를 보면서 확인해 보자
소스코드 분석
길다...
가장먼저 코드분석전에 어노테이션이라는걸 알게되었는데, 자세한 설명은 기타 다른 글에 뛰어난분들이 잘 정리하였으니 참고하고
어노테이션이 쓰인 @app.route("/flag", ........) 부분을 보면
/flag로 url 요청이 오면 해당 함수를 실행하겠다 라는 의미이다. (@app.route(”/flag”)
이 문제의 핵심은 FLAG 키값을 읽어오는 것이다
위에서 이야기했듯 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>'
코드를 대략적으로 분석해보면 POST 메소드로 요청이 오면 request.form.get("param")
을 통해 param
값을 설정하고 조건문으로 들어가게 된다.
그 조건문에서 check_xss(param, {"name": "flag", "value": FLAG.strip()})
구문을 통해 check_xss 함수를 호출하게 되는데 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)
이렇게 되어있다.
자 !
if not check_xss(param, {"name": "flag", "value": FLAG.strip()})
여기서 넘겨주는 값은
- param, 2. {"name": "flag", "value": FLAG.strip()}) 인데, check_xss에서 인자를 받는걸 보면
check_xss(param, cookie={"name": "name", "value": "value"}):
이므로
param == param , {"name": "flag", "value": FLAG.strip()}) == cookie 인걸 확인할 수 있다.
정리하면 클라이언트 측 flag 페이지에서 어떤값을 입력해서 보내면, flag 함수가 있는 서버단에서 param과 cookie 값을 세팅해서 check_xss 함수로 넘겨준다. 그런데 세팅된 cookie 값은 flag다.
그러면 현재 check_xss() 함수의 url 변수에 저장되어 있는 값은
url = f"http://127.0.0.1:8000/vuln?param=우리가flag 페이지에서 입력한값
이 되게 되어진다.
이 상태에서 다시 read_url() 로 url, cookie 를 넘겨주게 되는데 .. 그렇다면 read_url() 을 봐보자
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
인자로는 url, cookie를 받고 있다.!!
코드를 자세히 보면 보면 윗부분은 드라이버를 세팅해주는 내용인것 같고..
봐야할 부분은
driver.add_cookie(cookie)
, driver.get(url)
이 두부분인것 같다. check_xss로 부터 들어온 인자값을(url, cookie) 값을 추가하고 True 값을 리턴해 준다. True 값을 리턴해 주므로
@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>'
맨 아래 코드가 실행되게 된다.
코드의 전체적인 흐름과 문제가 의도한 내용은 지금까지 파악을 해 보았다.. flag 페이지에서 입력값
이랑 FLAG 값을 각각 param, coockie로 설정해서 chec_xss 넘겨주고check_xss에서 url을 설정 후 read_url 에서 url, cookie 세팅을 해주게 되고 true 값을 반환하는것 ..
chec_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)
url을 유심히 봐보면 /vuln?param=
을 볼 수 있을것이다. /vuln
함수가 실행된다 !!
결국 위의 과정들(flag페이지에서 입력→ chec_xss 함수 호출 → read_url 함수 호출) 이 일어나는데 read_url 에서 /vuln 페이지를 다시 요청하므로 XSS취약점이 있는 vuln(xss) page에서 스크립트(우리가 flag 페이지에 입력한 값)가 실행되어 진다.
자 다왔다..
결국 중요한건 flag 값을 찾는건데.. cookie에 flag 값이 설정되어있다.. 그렇다면 어떻게 해야할까.. 어떤 스크립트를 써야 내부적으로 실행되어진 스크립트를 통해 cookie 값을 클라이언트 측에서 볼 수 있을까 ?
location 객체의 href 를 쓰면 된다. (다른게 있을수도 있다.. )
그리고 왜 존재하는지 몰랐던 memo 페이지를 사용하면 된다.
url = f"http://127.0.0.1:8000/vuln?param=
이게 지금 url 인데 여기에 파라미터값을 다음과 같이 주면 어떻게 될까
<script>location.href=”http://127.0.0.1:8000/memo?memo=”+document.cookie</script>
이 값을 넘겨주게 되면 최종적으로 check_xss 함수에서 세팅되는 url 값은
url = f"http://127.0.0.1:8000/vuln?param=<script>location.href=”http://127.0.0.1:8000/memo?memo=”+document.cookie</script>
이 되어진다. 따라서 XSS 가 가능한 vuln코드에서 <script>가 실행되어 지고 스크립트 내용을 통해 memo에 cookie 내용이 입력되어지게 된다...
왜 memo?memo= 에 입력을 하냐면 메모 페이지에 들어가서 보니 입력을 받는 인자가 아래 그림과 같았다.
길었다..끝이다.
Uploaded by Notion2Tistory v1.1.0