TL;DR

  • 취약점: (어디서 무엇이 터지나 — 한 줄)
  • 핵심 트릭: (이 문제만의 급소/함정 — 다시 볼 때 가장 먼저 떠올릴 한 줄)
  • 페이로드: (최종 한 방)

분석

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
try:
    FLAG = open("./flag.txt", "r").read()  # Flag is here!!

@app.route("/img_viewer", methods=["GET", "POST"])
def img_viewer():
    if request.method == "GET":
        return render_template("img_viewer.html")
    elif request.method == "POST":
        url = request.form.get("url", "")
        urlp = urlparse(url)
        if url[0] == "/":
            url = "http://localhost:8000" + url
        elif ("localhost" in urlp.netloc) or ("127.0.0.1" in urlp.netloc):
            data = open("error.png", "rb").read()
            img = base64.b64encode(data).decode("utf8")
            return render_template("img_viewer.html", img=img)
		try:
            data = requests.get(url, timeout=3).content
            img = base64.b64encode(data).decode("utf8")
        except:
            data = open("error.png", "rb").read()
            img = base64.b64encode(data).decode("utf8")
        return render_template("img_viewer.html", img=img)
  1. 항상 flag read/반환은 안 함 → 이 flag를 어떻게 내가 읽어낼 것인지가 이 문제의 핵심
  2. 만약 /~처럼 상대경로로 접근 → localhost:8000 + url
  3. 만약 localhost 입력 시도 -> 에러페이지 반환
  4. try~: 접근해서 컨텐츠 가져온 뒤 render_template으로 반환
대상동작

취약점

공격

  1. (단계)
  2. (단계) ← 필요할 때만 끝에 한 줄 당위
  3. (단계)
1
(최종 페이로드 / 명령)

함정: (당연히 먼저 해볼 법한데 막힌 것 → 왜 실패 → 어떻게 전환. 12줄. 없으면 “—”) 핵심 당위: (이 공격이 성립하는 단 하나의 이유. 12줄. 당위는 여기로 모은다.)

배운 점