Intigriti XSS Challenge July 2022
This was amazing XSS challenge from Intigriti. Thanks to vroemy for creating this kind of interesting challenge. From SQL Injection to second order SQL Injection + CSP bypass and then XSS.
Last updated
This was amazing XSS challenge from Intigriti. Thanks to vroemy for creating this kind of interesting challenge. From SQL Injection to second order SQL Injection + CSP bypass and then XSS.
Last updated
So this is our challenge. Intigriti hosted this challenge while I was on vacation. I cameback home last day when challenge was almost over so I started hard focusing on this challenge.
As usually we have challenge's description obviously. But have you noticed something at the beginning of the description? 'Find a way to execute arbitrary javascript on the iFramed page and win Intigriti swag.' When I saw this, I got kinda big motivation to pwn this challenge. So let's start doing this challenge.
Okay. So, this is the official page of our challenge. Let's see what is there.
So, when you click any user on this website, you will notice URL fragment in URL. If you don't know what is URL fragment just read this carefully. Basically, URL fragments, located at the end of a URL, that begin with a # character. They are often used to automatically direct users to a section withing a web page or transfer additional information. So I was like let's try inserting some string and see is there gonna be some reflection, sometimes DOM XSS knows to be reflected in URL fragments.
Nothing :( our input is not being parsed anywhere in DOM nor is there reflection so go ahead.
Take a look at 'Archives'. Let's check them.
I went to 'March 2022' and it's kinda interesting since it has that ?month=3 parameter. Let's see what we can do here.
So, I was like let's use some specific chars. And It looks like web app filters untrusted HTML content tho. At the beginning I tried different chars and it encodes untrused HTML content, looks like web app is using PHP function called htmlentities(), it encodes <>, single/double quotes, ampersand etc. Let's try SQL Injection since there's no any reflection for XSS.
I tried single quote for SQL Injection and it gave me an error. Let's use automation for SQL Injection (SQLMap).
So, here we can confirm that SQL Injection exists on website. Let's see what are these payloads doing. Also have you noticed that for some reason it's giving me payload for parameter ?month=2 haha lmao. But however none of these months were vulnerable to SQL Injection (only for me). Maybe because it's patched or something? But however ?month=1 parameter is vulnerable to SQL Injection, that's important. So let's dive deep into this.
So, I had tried that second payload and it works. It is added as a blog post. And DB inputs are not being sanitized since it is vulnerable to SQL Injection. Let's see what is going in DOM:
What is happening here? Basically <h2> tag is used as a title and notice that <a> anchor tag is being empty. Hm quite interesting. We need to figure a way out to get our XSS via SQL Injection. I've found this quite interesting blogs about XSS via SQL Injection.
We need to convert string to HEX code. So, how does this works? Basically if we try to encode <script>alert(document.domain)</script> to hex it will become like this
month=1 UNION ALL SELECT 1,0x3c7363726970743e616c65727428646f63756d656e742e646f6d61696e293b3c2f7363726970743e,2,3,4 — %20-
Let's try some basic XSS payload.
As you can see, we didn't got our XSS triggered. This means that values including malicous JS are sanitized and validated, as you can see web app is using htmlentities() function to sanitize <> I was right at the beginning of the challenge. But it doesn't sanitize single/double quotes which is good, if it was sanitizing them then it would be impossible to escape them even if there's reflection.
Let's comeback to our SQLMap.
As you can see I will dump tables. But why am I doing this? You can see above that our SQLMap found 5 tables. We can use our SQLMap to find more about 5 column table and see what’s happening with the SQL database.
So, SQLMap found out 3 tables. Let's take a look at user table.
These are names on blog posts. Let's check next table, this is not useful at all.
Now our next table is 'post' table. Let's dump that table.
Update: Don't use --batch. Since it won't dump anything for some reason.
This would take a while but however you would get 5 columns. First column is about ID. Second column is about msg which means our payload is sanitized. Third column is title which means our payload is sanitized. Fourth column is not showing but only anchor tags. And last one fifth column is about datetime and payload is sanitized again. In the post table column four 'author' is the reference by ID 1 and 2 this matches ID columnin the user table. I think that name and picture are vulnerable. Now we will use three values as user tables containing only three columns, but this payload will go into position four of the first SQL Injection payload. This is my payload for XSS reflection:
?month=1 UNION SELECT 11,22,33,0x3320554e494f4e2053454c45435420312c307833633639366436373230373337323633336437383230366636653635373237323666373233643631366336353732373432383331323933652c332d2d202d,55-- -
Also try to craft XSS payload alone if you want to learn something.
So, this is success. Our malicious JS is being reflected inside of an anchor tag. Basically our user input is being parsed into <a href attribute inside of an anchor tag. But have you noticed that we didn't got a pop-up? Now one problem comes...
It's CSP (Content-Security-Policy).
This violates the following CSP directive: "default-src 'sel' *.googleapis.com *.gstatic.com *.cloudflare.com". Now how can we find way to bypass this CSP and trigger our XSS?
So, I found 2 interesting blogs about bypassing CSP:
So, which payload we need to use to bypass this CSP?
I saw that a lot of people at the ending of the Intigriti XSS challenge were using JSONP to bypass CSP. JSONP endpoints allow insecure callback methods which allow an attacker to perform XSS, working payload:
And via 'unsafe-eval' and Wildcard either. Here's the solution:
This is bypass. This is done via Third Party Endpoints + JSONP. Now all we had to do is to convert this payload to hex code. This is my final payload for bypass:
This is my payload:
https://challenge-0722.intigriti.io/challenge/challenge.php?month=3%20Union%20Select %2011,22,33,0x3320756e696f6e2073656c65637420312c3078336335333633373236393730373432 30353337323633336436383734373437303733336132663266373737373737326536373666366636 37366336353631373036393733326536333666366432663633373537333734366636643733363536 31373236333638326637363331336636333631366336633632363136333662336436313663363537 32373432383634366636333735366436353665373432653634366636643631363936653239336533 63326635333633373236393730373433652c332d2d202d,55--%20-
Hope you learned something from this writeup, have a good day and peace out!