General Looking
When we visit the challenge page, we come across a page with sprinkles in the background and a prompt asking for our name in the center of the page.
And when we type and submit our name, it adds a GET parameter named ‘text’ to the page, and eventually, we see this:
Solving
Good so far. Let’s take a look at the web page source step by step. When we type our name and click the Submit button, this part gets executed. What it basically does is get our name from the input and redirect us to the same URL but with a GET parameter ‘text’.
And when we visit the page with our ‘text’ parameter, we see an alert box welcoming us. This happens due to this part of the code. It gets the parameter from the getParameterByName user function and checks both if the text exists and if another user function XSS returns false.
We’ll inspect the XSS function first because it's important. Here is the XSS function. This function's purpose is to ensure that the search part or hash part doesn't contain any < or > characters. Encoding them won't help because the function decodes these parts before checking. Double encoding won't help either because the script doesn't decode them twice.
Now we understand two things:
- Firstly, we know we should inject our payload somewhere other than the search or hash part of the URL due to the XSS filtering.
- Secondly, the trick of the challenge must lie in the getParameterByName user function since there is nothing else to inspect.
What this function does is get the URL and prevent regex escape at line 2. Then, it executes the regex and retrieves the second item, which is the value of our parameter. Here is the visualized regex provided by https://regexper.com/:
It checks for a parameter name starting with ? or & characters. However, it doesn't do that search on location.search, so if we can inject our payload into the path somehow, we could achieve XSS.
After some testing, we realize the path of the challenge is not a wildcard, so there must be another way.
First, I thought of the idea of path traversal. I tried /asdf/../challenge but, browsers clean this and redirect to /challenge. But what if we encode the slashes and dots?
I changed my path to /asdf%2F..%2Fchallenge, which decodes to /asdf/../challenge. The browser didn't decode it, and I was able to see the challenge page instead of a 404 error.
We found a way to inject our payload into the path. Since the getParameterByName function retrieves the parameter from location.href instead of location.search, we can trick the page to achieve XSS.
Because the regex checks for ?text= or &text= , we should use one of these in the path. We can't use ? in the payload as it will break the path, but we can use &text= .
Here is the first discovery of this trick:
Then I replaced the asdf with the XSS payload to alert the document domain:
Final Payload: https://challenge-0125.intigriti.io/%2f&text=%3Cimg%20src=x%20onerror=alert(document.domain)%3E%2f..%2fchallenge
Thanks for reading.