Today, I will be sharing my solution on Intigriti’s February XSS Challenge 0222.
It is titled XSS (eXtremely Short Scripting) Game. It hints that there might be some twists that require us to use as least as possible characters to solve the challenge.
The solution needs to meet the following criteria in order to be accepted:
alert(document.domain)
.At the start of the challenge, we were greeted with a form needing two inputs. One asked for our Name and the other asked if we already played the game before.
After submitting, a pop-up appears greeting us a Welcome Back! Our input was being loaded using DOM innerHTML Property
We get the following URL after submission. Our name is reflected in the q
parameter
https://challenge-0222.intigriti.io/challenge/xss.html?q=Echidonut&first=yes
The first thing to do when playing an XSS challenge is to obviously give the page a payload to execute JavaScript. <svg/onload=alert(1)>
The name-field is not sanitized and is vulnerable to DOM XSS.
Of course not. The challenge requires us to alert(document.domain)
.
One thing we should know about the DOM innerHTML Property is it does not allow the execution of JavaScript thru <script>
tags. Our only option is to use event handlers to achieve JavaScript execution.
I tried to give it a payload like <svg/onload=alert(document.domain)>
but something unexpected happened.
Upon reviewing the source code, it definitely limits the input to a maximum of 24 characters.
Our input is stored in the qs
variable.
If our input qs
is limited to only 24 characters, we should think outside the box. In other words, think outside the variable.
One thing that caught my attention is uri
var uri = decodeURIComponent(location.href)
The uri
variable is just our URL, with “some” modifications. We can inject the payload in the URL and use it in eval () later.
I found a short XSS payload that is like this approach. I found it here.
<svg/onload=eval(`'`+uri)>
This payload is 26 characters long. Just two characters more than the limit. If we can tweak this to shove off just 2 characters, we can solve the challenge. I see no other way to save characters. The only possible thing from here is
<svg/onload=eval(uri)>
We can now inject our payload in the URL
https://challenge-0222.intigriti.io/challenge/xss.html?q=<svg/onload=eval(uri)>&first=yes#;alert(document.domain);//
But we got an error. Uncaught SyntaxError: Unexpected end of input
I spent too much time overthinking this part. I was so close to getting the XSS but now I’m getting an error. I decided to replicate the error in my IDE to make things more organized
Unlike a multiple-line comment /**/, a single-line comment // can’t be closed with another comment. The only way to escape a single-line comment is by making another line.
We only control the URL. How can we add another line to the uri
variable? Well, it's the vulnerability in the variable declaration. It carelessly used decodeURIComponent()
. We can add a new line by URL encoding CRLF %0d%0a
The CRLF is the missing puzzle piece for the XSS challenge. The only thing we need to do is add it and there should be a pop-up of document.domain
https://challenge-0222.intigriti.io/challenge/xss.html?q=<svg/onload=eval(uri)>&first=yes#%0d%0aalert(document.domain);//
The challenge is now solved, or so I thought…..
My solution does not work in the latest version of Firefox. In the rules, the solution must work in both Chrome and Firefox
I investigated more into the issue. It is not just me that was surprised about the svg load
handler working in Chrome but not the other. To solve the challenge, I used <style onload=eval(uri)>
exactly 24 characters, instead of <svg>
https://challenge-0222.intigriti.io/challenge/xss.html?q=<style onload=eval(uri)>&first=yes#%0d%0aalert(document.domain);//
I got the sweet pop-up in Firefox
I would like to thank Intigriti for hosting this challenge. I learned a lot about DOM XSS, and the unusual way Firefox treats svg
event handlers when inserted using innerHTML