Intigriti January XSS Challenge
TITLE : Intigriti’s January Challenge by Godson
URL : https://challenge-0125.intigriti.io/
- It’s a simple and interesting challenge that shows how important the basics are in every part of security.
--------------------------JS Source--------------------------
function XSS() {
return decodeURIComponent(window.location.search).includes('<') || decodeURIComponent(window.location.search).includes('>') || decodeURIComponent(window.location.hash).includes('<') || decodeURIComponent(window.location.hash).includes('>')
}
function getParameterByName(name) {
var url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
// Function to redirect on form submit
function redirectToText(event) {
event.preventDefault();
const inputBox = document.getElementById('inputBox');
const text = encodeURIComponent(inputBox.value);
window.location.href = `/challenge?text=${text}`;
}
// Function to display modal if 'text' query param exists
function checkQueryParam() {
const text = getParameterByName('text');
if (text && XSS() === false) {
const modal = document.getElementById('modal');
const modalText = document.getElementById('modalText');
modalText.innerHTML = `Welcome, ${text}!`;
textForm.remove()
modal.style.display = 'flex';
}
}
-
Lets try to understand each function and what they are doing to solve the challenge,
checkQueryParam()
function is called while loading the page. -
It checks for the query param
text
and if it exists, it passes the valuetext
togetParameterByName
function. -
The
getParameterByName
function further construct a regex/[?&]text(=([^&#]*)|&|#|$)/
and executes it on the urlregex.exec(url);
-
The regex meant to match either
?text=somevalue
or&text=somevalue
and the output is decoded and returned to innerHTML sink. -
There is also
XSS()
function which detect characters< , >
throughwindow.location.search
andwindow.location.hash
. -
If it founds such characters after decoding
(text && XSS() === false)
this condition will fail and results in failure of our payload entering the sink. -
How do we bypass it?
?text=somevalue
is required to enter the functioncheckQueryParam()
and there is proper check on both query param and hash fragment. -
lets understand the structure of URL before solving the challenge.
window.location.search - returns the query string from the URL.
window.location.hash - returns the hash fragment from the URL.
- Both query param and hash has an xss check ! other than that what we can control on the URL?
The Path:
தை பிறந்தால் வழி பிறக்கும் 😉
- If we can control the path , we can supply our paylod through
/&text=payload/
and execute xss with it. - Obviously we can control the path but there is one more problem we need to tackle is to use a non existent path ![ our payload would be an non existent path which will result in 404]
- We can use path traversing and path normalizing to overcome the 404 error.
- Combining everything our final payload looks like this
https://challenge-0125.intigriti.io/&text=%3Cimg%20src='1'%20onerror=alert(document.domain)%3E%2f..%2fchallenge?text=123&text=?text
- Since the regex match
&text=
our xss payload will be passed to the innerHTML sink [ XSS() function will return false as it searches only the query param and hash fragment of the URL]