XSS Challenge by Johan

Published on 15th December 2023 by 0xrudra

I recently engaged with an XSS (Cross-Site Scripting) challenge created by Johan Carlsson, which you can find on his Twitter page here.

Despite numerous attempts and some procrastination, which included skimming over JavaScript hoisting concepts, I found myself unable to crack the challenge.

However, this process taught me an important lesson about the need to slow down and focus, as I often rush through code and articles. Previously, I had missed Johan's first challenge but later came across his write-up on Twitter here.

This introduced me to the concept of JavaScript hoisting, a term I was unfamiliar with and initially found baffling, especially in understanding how it influenced the challenge's payload. Driven by curiosity, I quickly Googled the concept and superficially convinced myself that I had grasped it. Armed with this new, albeit surface-level knowledge, I attempted Johan's second XSS challenge and, unfortunately, did not succeed.

This experience serves as a reminder and an effort on my part to solidify my understanding of the basics of JavaScript hoisting and its practical applications. In a javascript the variables and function declaration are reassigned to the top of the scope before the code execution. This is called hoisting.

Let's understand better with an example.

a = 5; 
var a;
What do you think is suppose to happen after executing this piece of code since we haven't declared a in the start of the code?

The answer to this is that the code will not throw errors since the variable declaration was automatically reassigned to the top and assigning value 5 to a and this is known as javascript hoisting.

Note: Only the declaration get's hoisted and not the initialization.


Hoisting works well with variables declared with var but will throw error if the variable was declared using let or const keyword.

a = 5; 
let a;

Throws error `Uncaught ReferenceError: Cannot access 'a' before initialization`

Accessing a `let` declared variable before the declaration should result in `ReferenceError`.

Armed with the knowledge we shall solve the challenge right? Well, I'm noob so a big NO.

But let's try to understand what the code expect from us and let's see from there. Code is pretty straightforward (for me):

(function(){
  config = {
    env: "prod"
  }  
  try {
    if(config){
      return;
    }
    // TODO handle missing config for: https://try-to-catch.glitch.me/"
  } catch {
    fetch("/error", {
      method: "POST",
      body: {
        url:"https://try-to-catch.glitch.me/"
      }
    })
  }
})()


We know that if we want to execute the sweet little popup we would need to enter the `catch` block but since the try block would return in the if condition no matter what you enter in the catch block it would not be executed.

So the idea is to use `let` variable hoisiting to create a variable named `config` such that if the code is rearranged and executed it will throw `ReferenceError` and we will enter the `catch` block.

POC taken from Jonah's blog - https://try-to-catch.glitch.me/%22-alert()-%22%E2%80%A8let%20config

It's very creative approach to solving the challenge it uses a unicode new line character to balance the try and catch block syntax and execute XSS.

With that I conclude my knowledge of hoisting, see you later.

Back