What We Found — TL;DR
This is a walkthrough of a web app pentest against pentest-ground.com — a legal practice range running a Python Flask notes application. This post takes you through every phase from the first curl to full database access and server code execution.
What to expect reading this:
- A Flask app with debug mode left on in production (instant RCE)
- A search endpoint with no SQL parameterisation (full DB dump)
- Write routes with zero authentication (anyone can create or modify records)
- Step-by-step commands with real output at every stage
- A full animated kill chain tying all three exploits together
● CRITICAL Werkzeug Debugger RCE — /console open → Python exec on server · CWE-94 · OWASP A05
● CRITICAL Broken Access Control — /create /edit no auth → data tampering · CWE-284 · OWASP A01 · WSTG-ATHZ-02
● HIGH CORS Wildcard — Access-Control-Allow-Origin: * · OWASP A05 · WSTG-CONF-07
● HIGH Insecure Cookie — no HttpOnly/Secure/SameSite on SessionID · CWE-614
Tools used in this walkthrough: nmap · gobuster · nuclei · sqlmap · whatweb · curl
Skill level: Beginner-friendly — every command is explained.
Phase 1 — Information Gathering
I started by fingerprinting the target at https://pentest-ground.com:81. The first thing I do before touching any active scanning is understand what I’m dealing with — the technology stack, server headers, and any obvious misconfigurations visible from a simple HTTP response.
Right away the Server header told me this was a Flask application running Werkzeug 3.1.3. That’s immediately interesting — Werkzeug has a built-in interactive debugger that, if left enabled in production, allows arbitrary Python code execution directly from the browser.
I noted the missing security headers as well — no CSP, no HSTS, no X-Frame-Options. These would become findings later.
A Notes application running on Flask. That meant likely a database backend (SQLite or MySQL), user sessions, and CRUD operations — all classic SQL injection and access control territory.
Phase 2 — Reconnaissance
With the stack confirmed I moved into active reconnaissance — mapping every endpoint and understanding what each one does before touching any of them offensively.
The /console endpoint stood out immediately. That’s the Werkzeug interactive debugger — and it was open to the world.
I also noticed /create and /{id}/edit were returning 200 without any redirect to login. That suggested zero authentication on write operations — a major access control red flag I’d verify shortly.
Phase 3 — Scanning
Port 6379 showed Redis with no authentication — in a real engagement that would be an instant critical. It was marked out of scope here so I logged it and moved on.
Nuclei confirmed the CORS wildcard and Werkzeug debugger in one sweep.
Phase 4 — Vulnerability Analysis
With the scan complete I sat down and categorised everything. Three criticals in one small Flask app — that’s a complete compromise. I worked through them in order of severity.
Phase 5 — Exploitation
F-009 — SQL Injection (Critical, CVSS 9.8)
The /search endpoint accepts a POST parameter called query. I started with the classic single-quote test to check if input was reaching the database unsanitised.
That confirmed it — a raw MySQL error returned directly to the browser. The query string is being concatenated straight into a SQL statement with no parameterisation.
Full database access. The users and notes tables were both enumerable. In a real engagement I’d extract password hashes and pivot from there.
F-010 — Werkzeug Debugger RCE (Critical, CVSS 9.8)
Gobuster found /console returning 200. I opened it in the browser and was greeted with the Werkzeug interactive Python debugger — completely unauthenticated.
This is a web-based Python REPL running in the context of the application server. Any Python command typed here executes directly on the server.
Complete Remote Code Execution. The application is running as a non-root user but the server filesystem is fully readable and writable. A real attacker would drop a reverse shell here immediately.
F-011 — Broken Access Control — Unauthenticated Write (Critical, CVSS 9.1)
I noticed /create returned a form page with no login redirect. I tried submitting it without any session cookie at all.
No cookie. No session. No authentication check. The note was created and assigned ID 47. I then tried editing someone else’s note:
Both create and edit operations have zero authentication. Any anonymous user can create, modify, or delete records belonging to any other user.
Phase 6 — Post Exploitation
At this point the application is fully compromised. Between the three critical findings an attacker would have:
- Full database access via SQLi — user credentials, all notes, session tokens
- Full server code execution via Werkzeug debugger — ability to install backdoors, read environment variables, extract database passwords from the config file
- Complete data integrity loss via BAC — every record in the application can be created, modified, or deleted by anyone
The combination of SQLi + RCE means privilege escalation to database admin would be the natural next step, followed by attempting lateral movement to any other services on the same network.
Kill Chain
</div>
Disclaimer
This assessment was conducted on pentest-ground.com — a legal practice range by Pentest-Tools.com, designed for authorized security testing. All techniques documented here are for educational purposes only. Do not replicate against systems you don’t own or have explicit permission to test.
Generated with BlackOps — SweshInfoSec