초심자이기 때문에 하나부터 열까지 매우 세세하게 작성할 예정이다. 모든걸 이해하고 넘어가고 싶다. 다만 틀릴수도 있다.. !

 

파일이 깨지면 https://zzczzc123.notion.site/Dreamhack-XSS-1-45026e8388c0430a8751054d5a207024 로 가서 보자

 

문제분석


처음에 접속하게 되면

 

그림과 같은 페이지가 나오게 된다.

 

먼저 vuln(xss) page 부터 눌러보면 그림과 같이 뜨는걸 확인할 수 있다. 또 빨간박스를 보면 script가 들어가서 실행되는걸 확인할 수 있는데 이 말인 즉슨 XSS가 가능하다는 말이다.

vuln(xss) page 실행화면

 

두번째로 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()}) 여기서 넘겨주는 값은

  1. 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 값을 반환하는것 ..

 

아니 알겠는데 그래서 어떻게 해야하는데? 이게 vuln(xss) page 페이지에서 xss 일어나는거랑 무슨상관인데?

 

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= 에 입력을 하냐면 메모 페이지에 들어가서 보니 입력을 받는 인자가 아래 그림과 같았다.

 

길었다..끝이다.

 

 

 

+ Recent posts