Intigriti XSS Challenge March 2022
Hello guys I am back again. This challenge was pretty interesting and one of my fav. Let’s start talking instead of wasting our time.
Last updated
Hello guys I am back again. This challenge was pretty interesting and one of my fav. Let’s start talking instead of wasting our time.
Last updated
So there’s rules of the challenge and some solution like in every other challenge. So let’s start doing this challenge.
It’s something about hashing algorithm hmm. Let’s type ‘rootjkqsta’ in PlainText and md5 hash algorithm.
I can assume this will be about CSP bypass tho. But hold we forgot to check page source.
There’s nothing interesting? Then this means there’s high chance that sink must be elsewhere. But let’s comeback to normal page and type this XSS payload <img src=x onerror=alert(1)>
in both of these fields.
The Hashing algorithm field is using PHP hash_file() at the back-end, and the XSS payload does not trigger here. The XSS payload is nearly injected into the PlainText field except that our onerror
’s value got replaced. This sanitization logic was provided to us.
With the regex used with preg_replace(), we are not allowed to use brackets or backticks. But we are able to bypass this by encoding these characters using HTML entities. Let’s encode the ()
in our original payload and it will look like: <img src=x onerror=alert(1)>
.
We can see that our XSS payload is now as expected, but there’s a new problem: Content Security Policy (CSP). This mitigates our basic XSS payload and we have to find ways to bypass it. The policy looks correct as we cannot inject arbitrary <script>
tag since a valid nonce is required each time the page is requested. We are also unable to insert inline JavaScript events such as onload
, onerror…
But have you noticed that there’s a lack of unsafe-inline
. Even though we are able to inject a <base>
tag, this challenge does not import any form of JavaScript files at all. But what is that CSP?
Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft, to site defacement, to malware distribution.
CSP is designed to be fully backward compatible (except CSP version 2 where there are some explicitly-mentioned inconsistencies in backward compatibility; more details here section 1.1). Browsers that don’t support it still work with servers that implement it, and vice-versa: browsers that don’t support CSP ignore it, functioning as usual, defaulting to the standard same-origin policy for web content. If the site doesn’t offer the CSP header, browsers likewise use the standard same-origin policy.
To enable CSP, you need to configure your web server to return the
Content-Security-Policy
HTTP header. (Sometimes you may see mentions of theX-Content-Security-Policy
header, but that's an older version and you don't need to specify it anymore.)Alternatively, the
<meta>
element can be used to configure a policy, for example:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src https://*; child-src 'none';">
But however you can find it on developer.mozilla. I posted link. Now let’s comeback to our challenge. So let’s re-examine the request parameters that are sent when the form is submitted.
Token is likely set to a 64-character string, FirstText
and Hashing
are set based on our input. Remember how entering a non-valid hashing algorithm revealed some verbose warning messages by PHP?
This is from a normal string:
Now to a long string:
Wait look at this the CSP header is no longer returned in the response header for the second request. This means that our XSS payload would work successfully. But hold this is not end. Let’s craft an CSRF-based exploit since we can confirm that XSS is working.
Let’s save this exploit. This relies on user interaction as we would need to click on the ‘Click me’ button first. So the JavaScript in this file would open a new tab to the https://challenge-0322.intigriti.io/challenge/LoveSender.php page. So visiting this page would grant the victim a valid PHPSESSID
cookie, which is required by the LoveReceiver.php
vulnerable page before the XSS payload would even load. Once a valid PHPSESSID
cookie is obtained, we have 2 minutes before the SameSite=Lax
setting kicks in, preventing cross-site POST requests from sending cookies. Now we have to quickly send our POST
request to trigger the XSS payload. The HTML file above automatically sends this POST
request after a 5-second delay, tbh I was thinking to make a 10 seconds delay tho, but 5 second is better. So when the request is sent successfully, the XSS should trigger in the victim’s context.
And that is it. We got everything working perfectly. Now cheers up.
Resources:
Hope you enjoy reading my writeup, hope you learned something new, take a care and see you in a next one writeup. Peace out!