XSS challenges are a great way to learn cool tricks on how to exploit client side and circumvent browser’s security measures. This months Intigriti XSS challenge was made by @aszx87410. The requirements for the solution were simple:
- It should work on the latest version of Chrome and FireFox.
- It should execute alert(document.domain).
- It should leverage a cross site scripting vulnerability on this domain.
- It shouldn’t be self-XSS or related to MiTM attacks.
- It should not require any kind of user interaction. There should be a URL that when visited will present the victim with a popup
As we open the link with the challenge we are immediately stroke by a nostalgia wave of the Windows XP CSS styling.
On the webpage we can see a “Window Maker” program, and when we enter some dummy data a custom “window” in generated.
When we open the request in the Burp Suite we can see the following request:
GET /challenge/Window Maker.html?config[window-name]=testname&config[window-content]=testcontent&config[window-toolbar][0]=min&config[window-toolbar][1]=max&config[window-toolbar][2]=close&config[window-statusbar]=true HTTP/2
Host: challenge-0422.intigriti.io
After trying some basic payloads we can observe that the app is escaping some “malicious” characters in the JavaScript.
The culprit of this encoding is the sanitize()
function.
The function replaces every occurence og the <>%&
characters and replaces it with _
. Every occurance of word script
is replaced too. However if the typeof data !== 'string'
condition is not met, the function will not sanitize the user input and simply return the data. To bypass this we can add square brackets []
to the URL parameter, so the function will treat the input as an array. With the following payload, we can bypass sanitization, but still no XSS as the tags are not rendered into DOM tree.
https://challenge-0422.intigriti.io/challenge/Window Maker.html?config[window-name][]=<asd>&config[window-content][]=<asd>&config[window-toolbar][0]=min&config[window-toolbar][1]=max&config[window-toolbar][2]=close&config[window-statusbar]=true
The URL passed to the application is parsed using the parseQueryString(location.search)
function. Later we can see, that if the checkHost()
function will be bypassed, we will be able to overwrite the devSettings
object.
By exploiting a prototype pollution in the merge()
function we are able to overwrite the prototype of the Array
and change the value of temp[1]
to 8080. This can be done by appending the following parameter to the URL:
The above exploit works as there is no prototype
string in the protectedKeys
array:
So now we can overwrite the devSettings
object by simply passing the parameter settings
in the URL:
https://challenge-0422.intigriti.io/challenge/Window Maker.html?config[window-host]=asd&config[window-content]=sad&config[window-toolbar][constructor][prototype][1]=8080&settings[isDebug]=POLLUTED
The final goal is to alter the DOM content, which is generated from the devSettings[root]
object:
It took me a while to search for the right parameter to overwrite but finally I found that the innerHTML
of the settings[root][ownerDocument][all][0]
object can be overwritten and results in HTML code injection into the webpage. The last thing to do, was to add the bypass we found in the first place, to omit the sanitization and inject a malicious script to the webpage. The final payload looked like this:
https://challenge-0422.intigriti.io/challenge/Window Maker.html?config[window-toolbar][constructor][prototype][1]=8080&settings[root][ownerDocument][all][0][innerHTML][]=%3Cinput%20autofocus%20onfocus%3Dalert%28document%2Edomain%29%3E
When we open the above URL we could see that an alert()
function was triggered thus completing the challenge.