Intigriti 0821 XSS Challenge Writeup

Asem Eleraky
5 min readAug 23, 2021

--

In this post, I am going to walk you through the Intigriti 0821 XSS Challenge, I hope you enjoy reading.

Starting with the challenge page, it has three links with the same parameter (called recipe) and it takes a base64-encoded string for what will be printed on the page.

Decoding these values, we will find the data that will be separated and printed on the page, ( Title, Ingredients, Payload, and Steps ).

After checking the main.js file to see how it works, I found the following functions:

readCookie() function:

This function just searches for a specific cookie parameter and if it exists, it returns its value, otherwise, it returns null.
One thing to note in this function, if the parameter exists, it only returns the first occurrence!

welcomeUser() function:

This function accepts one argument and it prints the welcome message followed by the given argument value.

generateRecipeText() function:

This function takes an object as an argument and then prints the title, ingredient, payload, and steps properties into the HTML elements that have specific IDs shown above.

handleLoad() function:

The handleLoad function does the following:

  • It uses the readCookie function to search if there is a cookie parameter called username, then it stores its value in the username variable, and if there is not, it creates a cookie parameter with the same name and gives it a random value.
  • It also decodes the base64 string of the recipe parameter then uses deparam jquery function to unparameterize the query string and then converts it back into an object and stores it on the recipe object.
  • Then it prints the message “welcome” and the value of the username cookie parameter.

The ga object indicates that the application uses Google Analytics and it is clear because the application imports the analytics.js file.

Now we need an injection point, all values coming from the recipe parameter are printed on the page with innerText property, so even if we tried to inject any XSS payload, it will be sanitized.

After reading the script for the second time, I noticed that the only variable which will be printed without any validation will be the value of the username cookie parameter because it was the only one that printed with innerHTML property, So how we can inject the cookies?

I know that deparam function is vulnerable to prototype pollution, you can check out the other vulnerable functions in this repository, we can use a test payload to check if it works, the payload is __proto__[test]=melo and of course, we should encode it in base64.

and it works! now back to the main question, How can we inject it into the cookies?

After some research, and reading the documentation of Google-Analytics, I found that the ‘auto’ keyword in the ga object, refers to the automatic cookie domain configuration, so all the Field References will be set to default values, as the cookieName reference will be ‘_ga’!
and this becomes very clear when we look at the cookies

So as you guessed, this will be our injection point!

Now let’s change the cookieName reference to ‘username’
We can do it with this simple payload
__proto__[cookieName]=username

Nice, we successfully did it, but as I mentioned above, the readCookie function returns the first occurrence of the username parameter, and unfortunately, our parameter is not the first occurrence!

How to give our parameter the priority to be the first occurrence?

After I saw that the original username parameter path attribute is the home path, come to my mind to change our parameter path to the “/challenge”, path=/challenge; and we will do it with the help of cookiePath reference! So our payload will be:

__proto__[cookieName]=username&__proto__[cookiePath]=%2fchallenge

let’s check the results

Good, we are so close, we just need to add our XSS payload to be the value of our username cookie parameter, this is the easiest part, we can add our XSS payload like this:

__proto__[cookieName]=username%3d<img%2fsrc%3dx%20onerror%3dalert(document.domain)>&__proto__[cookiePath]=%2fchallenge

After base64 encoding, let’s check the response

Done!

I spent more time at this part of the challenge to check for another way to inject my XSS payload, I came back to the documentation of Google-Analytics.

To briefly wrap up the part of the structure of _ga cookies value, check the following example:

  • The green part is the versioning number.
  • The red part is the clientId reference, and if it’s not selected, it would be some random numbers as you can see, but if you want to know what exactly is these numbers, I made the below figure for you

So I tried to inject my payload inside the clientId reference, so the payload will be:

__proto__[cookieName]=username&__proto__[cookiePath]=%2fchallenge&__proto__[clientId]=%3cimg%2fsrc%3dx%20onerror%3dalert(1)%3e

Now let’s check the response

Bad luck, it’s double URL encoded and it will not work even after using some tricks to bypass it!

But anyway, I solved the challenge!

I hope you enjoyed reading and I will be very happy if you have any feedback!

--

--

Asem Eleraky

Penetration Tester, CTF Challenges Developer & Player, Bug Hunter | AKA Melotover