Hey Everyone! 👋
I am Isira Adithya and I am a 16 years old ethical hacker from Sri Lanka.
Recently (21/03/2021), I found out that the Intigriti, Europe's #1 ethical hacking and bug bounty platform was releasing XSS Challenge. I've never participated to these before, but I found some cool write-ups about previous challenges on the internet.
Those XSS challenges were very interesting and I thought this may be my chance to win. (But, It was hard. 😅)
Sorry, for my bad english. 😅
Website is very simple. I will highlight the interesting parts. There is a little text box below to save notes. 🤔
It's kinda weird that there is a box to save notes. So, I immediately thought that will be the target. 😎
We can type anything in the textbox and we can save it.
Now, let's analyze deeply how the website works. 👀
I used Chrome Dev Tools to analyze the website. (Ctrl + Shift + I)
As you can see, our data is injected into a
<p> tag with id called
notes-display. But, if you try to inject something like
<script> it will be encoded with HTML entities. So, there's no hope using tags.
Then, let's navigate to the networks tab and analyze what kinda request this website uses.
As always, GET Request was not interesting at all.
But, when we save a note, it sends a POST request to the server with
notes as parameters.
As you can see I highlighted 3 major parameters,
- Request Headers
Method: POST(A common method used to send data to server)
Cookies: PHPSESSID:3d34ex7...(Used to track your browser's session)
- Form Data
csrf: [MD5 Hash](Used to protect against Cross-Site Request Forgery 😤)
notes: [Your_Data](Our data... This is the parameter we are going to use to get XSS 😎)
Also, I noticed that every time we update the notes or refresh the website we get new
csrf token with a very interesting comment. 🤨
So, whenever we refresh the page, it returns a new
CSRF token with a new
Date\Time in that comment. 🤔
That gives us a hint 🤩. So, I was thinking how the CSRF could be generated.
Now, I will show you how to decode this using Cyber Chef.
Analyzing CSRF Token
If you look closer in the Response headers you will find that the website uses PHP/7.2. (This is useful to know.)
Paste the CSRF token, and analyze hash. It shows some interesting hashing functions there. But, we already know that server-side language is PHP. So, It's super clear that developers are using MD5 to generate the hash. (There is a function called
md5 in PHP)
So, Intigriti is giving us the date and the time when the page was generated. If you know about Unix Timestamp it's good way to generate current time in a number.
Ex: 1616914585 -> Sun 28 March 2021 06:56:45 UTC
So, I thought that the CSRF is generated based on the time that web page generated.
Then, I navigated to Cyberchef
The Cyber Swiss Army Knife - Cyberchef
In the above picture, You can see the recipe I used.
I know about PHP and I knew it's very easy to generate MD5 hash of something in PHP. You just have to call
md5(data) also I knew that
time() function returns the current time in Unix Timestamp. So, dev only have to call
<?php echo md5(time()) ?> output the CSRF to the page.
(I am developing a Android Application. Server-side is written in PHP that's why I already knew about these. 😎)
So, let's discover how to exploit it in my way.
Finding the XSS
OK, First of all, I have to tell this. I know everyone uses BurpSuite by Portswigger when it comes to Web Application Testing.
However, I am not used to burp at all. I know the basics but I don't know how to use it with this kinda CSRF token 😂.
I will learn how to use it in the future. But, for this challenge I used Python Programming Language
I wrote a little script to test my custom payloads. I will add the Github link below.
Here's a little preview how the tool works. (It helped me a lot)
So, I tried basic functions and All of the payloads returns encoded data. (Html Entities)
But, as you can see in the above (Terminal Animate - Ascii Cinema) urls returns a
<a> tag. That's kinda good right?
When we send something like, [email protected] it detects it as a Email and returns a
<a> tag with following code in it.
There was some hints about the challenge in Intigriti's Twitter Announcement and in one of them they mentioned a RFC.
I think it is RFC822.
It describes STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES.
Then, I started to search about this and eventually I came across this payload by PayloadsAllTheThings - Github.
"><svg/onload=confirm(1)>"@x.y and I tried it.
As you can see it returned,
<a ><svg="" href="mailto:" onload='confirm(1)>"@x.y"'> "><svg/onload=confirm(1)>"@x.y </a>.
Then, I tried it in the browser and it didn't triggered the XSS. I was so confused and I found out that the problem is
onload attribute. As you can see that
< and > was encoded in that
<svg> payload. But,
onload attribute is in the
<a> tag and that's enough to perform a XSS attack.
I modified the
onload attribute to
onmouseover then I tried once again and Boom! 💥. It triggered the xss when I got my mouse pointer over it.
That's it. Then, I modified the payload little bit according to the Intigriti.
So, after modifying it. The final payload looks like this.
Finally, I got the CSRF Bypass and XSS. Then, I started to create a POC.
Writing a POC
So, This was my solution to the problem.
To reset the CSRF token, I used a
<iframe> tag with
sandbox attribute in it. So, the browser will send the cookies to the https://challenge-0321.intigriti.io/ website. Remember, we need to send the PHPSESSID cookie to the server. That's important if not the XSS attack is useless because we can't interact with victim's account. So, we have to send the cookies with the iframe request.
You can get more details from below website. Check it out.
HTML5Rocks.com - Sandboxed Iframe
But, chrome was more protective about this. Chrome checks if the cookie has the attribute
SameSite= None, if not it won't send those cookies to server. But, in the other hand firefox was vulnerable to this.
So, You have to use Firefox to trigger the XSS with CSRF Bypass.
Now, It's time to write the code. However you can use below link to read the whole code.
Replit - Intigriti 0321 POC
You can read the code to understand the attack, but I am trying my best to explain it further. 😅
First, I created the iframe in the html.
<iframe sandbox="allow-scripts" src="https://challenge-0321.intigriti.io/"></iframe> <script src="script.js"></script>
That's it. Whenever, someone open this code, the
iframe is going to reset the
POST request containing the XSS payload.
That's the solution for the Intigriti 0321 - XSS challenge. I hope you learned something from this writeup.
Thanks Intigriti for creating a such a great challenge.
Also, I went through lot of rabbit holes and I learned lot of new things from this challenge.