web-ssrf

2024. 9. 26. 17:13·DreamHack/WEB

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#!/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
)
print(local_port)


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)

 

 

문제 전체 코드이다.

 

문제 사이트도 들어가 보자.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

image Viewer에 들어가서 url 안에 있는 경로를 view 버튼을 눌렀더니 png 가 나온다.

 

뭐 할거 없으니 중요 코드를 보러 가자

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

url = request.form.get("url", "")
urlp = urlparse(url)

 

url에 대해서 POST 요청으로 처리가 된다.

 

 

 

 

 

 

 

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)

 

 

if 문에서는 URL에 대해서 상대경로인지 확인한다.

 

만약 상대경로이면 절대경로인 "http://localhost:8000"으로 바꾼다.

 

elif에서는 urlp.netloc을 사용하여 "localhost" , "127.0.0.1"을 확인한다.

 

조건에 맞다면 error.png를 불러온다.

 

error.png 이미지를 가져올 때 base64 인코딩을 해서 표시한다.

 

 

 

 

 

 

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)

 

 

다르게 URL 이 로컬 호스트(127.0.0.1 , localhost)가 아닐 경우, error.png를 출력한다.

 

똑같이 base64 인코딩해서 표시한다.

 

 

 

 

 

 

 

 

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

 

local_host는 127.0.0.1로 설정

 

port 은 1500~1800 사이의 랜덤포트 번호이다.

 

local_server는 HTTP 서버를 설정한다.

 

서버에 들어가 /flag.txt를 출력하려면

http:로컬호스트:{랜덤포트번호}를 만족시켜야 한다.

 

로컬호스트는 "localhost" , "127.0.0.1" 으로만 막아둔 상태이다.

 

그러면 로컬호스트는 "Localhost" , "LOCALHOST" , "0.0.0.0" 으로 우회가 가능하다.

 

나머지 포트번호를 찾기 위해서는 1500~1800 에다가 브루트 포스 연산을 넣어야하는데

 

조건을 찾아야한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

다시 돌아와

 

정상적으로 url 에 dream.png 를 불러오면 image Viewer 가 잘 불러와준다.

 

우리는 아까 소스코드에서 image 를 불러올때 base64 로 표시가 된다는걸 확인했다.

 

프록시로 보면...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

확인해보면 정상적으로 url 를 보냈을때 image 가 base64 인코딩된걸 확인할수있다.

 

이것은 error.png 도 마찬가지로 base64 로 인코딩되서 나온다.

 

decode 를 해보면....

 

 

 

 

 

 

 

 

 

 

 

error.png , dream.png 전부 decode 할때 동일하게 PNG 가 decode 된걸 확인할 수 있다.

 

그렇다면 저 PNG 부분만 걸러낸다면 포트번호를 확인할 수 있을거 같다.

 

왜냐하면

 

포트번호가 실패한다면 error.png 가 출력되면서 PNG 가 나오기 때문이다.

 

그러면 종합적으로 보면 localhost 우회하고 포트번호를 찾을수 있는 조건을 알아낸것이다.

 

 

 

 

 

 

 

 

 

PNG 만 걸러내도록 하자.

 

 

 

 

 

 

나 같은 경우는 1582 포트 가 열려있었다.

 

 

 

 

 

 

 

 

 

 

 

 

localhost 우회, 찾은 포트 를 입력하니 flag.txt 를 가져왔다.

 

flag.txt 를 여전히 image 에서 가져오기 때문에 base64 인코딩이 되어 있는 상태이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'DreamHack > WEB' 카테고리의 다른 글

proxy-1  (0) 2024.10.16
web-misconf-1  (1) 2024.10.10
blind-command  (0) 2024.10.10
session  (1) 2024.10.08
pathtraversal  (0) 2024.09.11
'DreamHack/WEB' 카테고리의 다른 글
  • web-misconf-1
  • blind-command
  • session
  • pathtraversal
G_OM
G_OM
최대한 설명 열심히 하려고 합니다. 궁금한 거 있으면 언제든지 물어보셔도 좋습니다.
  • G_OM
    끄적끄적
    G_OM
  • 전체
    오늘
    어제
    • 분류 전체보기 (157)
      • 모의해킹 (18)
      • CTF (22)
      • Wargame (69)
        • Linux_bandit (33)
        • Webhacking.kr (36)
      • DreamHack (52)
        • WEB (14)
        • Reverising (9)
        • System (0)
      • Mobile_security (13)
        • Drozer_Android (4)
        • Frida_Android (1)
        • IOS (1)
        • tool (1)
      • 정보보안기사 (2)
      • IT? (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
  • 공지사항

    • DreamHack 에 대한 문제들...
  • 인기 글

  • 태그

    난독화
    모의해킹
    CTF
    리눅스
    webhacking
    php wrapper
    Frida
    bandit
    insecurebankv2
    bandit17
    bandit30
    lfi
    bandit20
    php
    cookies
    Dreamhack
    리눅스 워게임
    Linux
    워게임
    Android
    OSINT
    wargame
    Linux wargame
    url encode
    sql injection
    bandit18
    webhacking.kr
    drozer
    overthewire
    정보보안기사
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
G_OM
web-ssrf
상단으로

티스토리툴바