Clobbering the clobbered vol. 2

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

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 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 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:


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

  • 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 and domains.

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


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
  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 that works on both Chrome and Firefox. This solution uses a trick presented by @shafigullin.

The decoded version looks like:
&img=cats.gif"name=cookie x='
<a id=show_session href=cid:alert(/1337/)></a>
<form id=trusted name=user>
<img id=referer name=referers>
<img name=referers>

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 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 name="trusted">
<a name="referers">
<a name="referers">


<!-- 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">

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

My original solution

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

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