Halloween came with an awesome XSS Challenge by Intigriti, and I'm here to present the solution I found for this. Hope you like it 🦇
Reading the content of the page, at the first glance, it tells us that there is a query parameter called
html, which is capable of define partially what's displayed to the user. When we define, for example, a
<h1> tag to this parameter, we are going to get returned a page with this tag being reflected, which is already an HTML injection. From now on, we will be working to make it become an XSS.
If we simply try to inject something like
<script>alert(document.domain);</script>, this script tag will be reflected, but the code itself will not be executed. Why? Well, if we look at the head of the page, we are going to find something interesting:
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-eval' 'strict-dynamic' 'nonce-random'; style-src 'nonce-random'">
This meta tag tells us that the page has a CSP, which will not let any random script be executed. Also, it's possible to see, from the script-src policies, that 'strict-dynamic' was defined, which means that generally a script will only be trusted if it comes with a trusted one-use token (nonce).
document.createElement("script"), and by the way, if we look a little bit further at the page source, we are going to find this section of code:
When we don't pay enough attention to the code, we might think that it's just needed to insert something like
alert(document.domain) to the
xss parameter on the URL, but if you do so, you won't get any alert popping out, because what's truthfully being inserted to the script tag is:
Paying a little bit more attention to the previous section of code, this specific piece is important:
Now, we know that we have to create a tag with an id "intigriti", and also that this tag needs to, somehow, unbreak the
)]}' that we have seen. The second part its actually pretty easy to think of, because it ends with a simple quotation mark, and if we open it before, every other character will be considered part of the string, so the solution for this would be something like
a=', but we have to apply this on the context of an HTML tag, resulting in
<div><diva='>. Remember that Intigriti Jr's INTERNAL HTML is what is parsed, and not the element itself, that's the reason for the external div.
The other part is the one who takes more effort. If we simply try to add
<div id="intigriti"><div><diva='></diva='></div></div> to the
html parameter, as you can see on the picture below, we will have these tags inside of the DOM but inside
<h1> tags, and waaaay too far from being the last element of the body, which is what is want:
So, in order to trigger an alert, we have to figure out a way of go outside this
<div><h1></h1></div> pair and a way of making the next divs fit inside our payload
<div id="intigriti"><div><diva='></diva='></div></div>. One possibility is to trick the browser by inserting unopened/unclosed tags, so it tries and fails to fix it.
For getting outside of the
<div><h1></h1></div> pair, all we have to do is insert
</h1></div> before our friends
<diva='>, resulting in:
Now we have to make everything that originally goes next
</h1></div><div id="intigriti"><div><diva='></diva='></div></div>, fit inside our structure so it becomes the last element of the body. Just by leaving the DIVs unclosed, like
</h1></div><div id="intigriti"><div><diva='>, we will have as result that all the divs that goes after our payload instantly fit inside
<div id="intigriti">, which is great but not our final goal.
Finally, by adding a
<div> tag and leaving it unclosed at the end of our payload, everything will fit inside our
<diva='></diva='> tags, and also, if we look at the generated script tag, we will find something REALLY insteresting:
This means that all the weird characters were turned into a string called "a", and we just have to insert our alert onto the
xss parameter. This would result on the final payload:
And from this payload right down below, I was able to trick our fictional villain 1337Witch69 🤗