Intigriti hosted their 2nd XSS challenge to celebrate 5k followers. It is an interesting challenge but easier then the previous one. This is challenge is basically a DOM Based XSS.
So let's get started by understanding the code.NEW CHALLENGE: We're giving away a Burp Pro license, swag & invites to celebrate 5k followers! 🤩💙 Claim your prize: 👉 https://t.co/KYQHSOpGvn #BugBounty #CTF #HackWithIntigriti pic.twitter.com/h2jDTM3qos— intigriti (@intigriti) May 21, 2019
Lines 1 to 4: It just checks the fragment identifier, if it is empty it just add some string. By looking at the string we can say that its base64, so decoding the string "aW50aWdyaXRpLWNoYWxsZW5nZQ==" gives us intigriti-challenge.
Lines 10 to 23: Basically 10th line gets the fragment identifier by removing the #. At 11th line XMLHttpRequest is initialized, then script assigns a function which only executes if readystate == 4 and status == 200. If it happens, then FileReader is used to read the response and if file reader finishes reading then onloadend funcion will execute which writes the html tag <a> with base64 decoded fragment identifier in the alternate text and FileReader result to the src of an image tag.(Keep an eye at this lines.)
Line 24 to 26: GET request to fragment identifier which is b64img. Therefore, the request will be
Two main observations:
1) Fragment identifier must be a valid URL to get the http response 200.
Initially I tried to find the other resources in the challenge server to exploit, but it is the waste of time.
Then I tried giving external URLS like https://challenge.intigriti.io/2/#https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png, it doesn't work because of CORS policy.
Ok wait! Can't we just simply bypass this by the server which accepts Cross Origin requests? Ya, we can so let's just spin up a server with index.php file having Access-Control-Allow-Origin: * header in it.
Let's access https://challenge.intigriti.io/2/#http://127.0.0.1/index.php. Wait What?
Connection refused, after some time I found that it is because of we are using https for the challenge server, so browser loads the localhost server using the same https scheme and I don't have certificates for that.
Then I tried loading the challenge server on http, then boom it worked fortunately. http://challenge.intigriti.io/2/#http://127.0.0.1/index.php.
Finding a valid url
Getting rid of http: scheme: After doing some google search I found that we can request http://challenge.intigriti.io/2/#//127.0.0.1/index.php. without http:, //url we can access any URL without scheme and it is called network reference path.
Getting rid of dots: This can be easily done because we can represent ip in the form of decimal, hexadecimal and octal so our //127.0.0.1 becomes //2130706433. If we are testing in the localhost, we can replace //127.0.0.1 with //localhost
Getting rid of .php: To do this what we can do is, we can write a apache server configuration file to resolve .php file for extensionless php urls. So we can simply get rid of .php. Now our url becomes
We found a valid url, now it's time for the payload.
Now our payload will be "><script>"Great" + document.domain</script> and encode it using base64 which becomes Ij4gPHNjcmlwdD4gYWxlcnQoIkdyZWF0ICIrZG9jdW1lbnQuZG9tYWluKTs8L3NjcmlwdD4K.
Then we just have to rename our index.php with Ij4gPHNjcmlwdD4gYWxlcnQoIkdyZWF0ICIrZG9jdW1lbnQuZG9tYWluKTs8L3NjcmlwdD4K.php.
Final URL : http://challenge.intigriti.io/2/#//2130706433/Ij4gPHNjcmlwdD4gYWxlcnQoIkdyZWF0ICIrZG9jdW1lbnQuZG9tYWluKTs8L3NjcmlwdD4K
And finally we can see the pop up. :)Nice challenge. pic.twitter.com/hNtNo4uCgb— Mohan Sri Ramakrishna (@S1r1u5_) May 24, 2019