Cross-site scripting or XSS has been one of those vulnerabilities in security that I am aware of and can exploit with a lot of luck but never really understand the ins and outs. Being that I’m tired of guessing and checking to exploit these vulnerabilities we are going to start with the basics and try our best to fully understand how to solve these basic challenges hosted by Google.
Level 1: Hello, world of XSS
Being that this is a search result and we are requesting information from the server; not altering or adding to the server this attack would be classified as a reflected XSS attack or a non-persistent. In order for this attack to be successful against a particular target a hacker would send a malicious link of the legitimate website with the malicious payload in the url. This can also be done by convincing a person to enter the payload themselves into the vulnerable input field or wherever else is vulnerable.
First things first let’s try any input in order to see how the search uses our query. By inputting “test” into the search field and hitting enter we see the url updates to the following.
Looking at the html of the query we see something of importance. This form has the method “GET” so by submitting the form we will commit to an HTTP GET request with the input id of “query”, the default value “Enter query here…” and onfocus will set the value to “” or nothing when we click into the input field. Then there is another input id for the button which is what we will use to submit. We see no functions being called within the form that would tell us there is input validation here but, it may be elsewhere.
Below we see the javacsript for this challenge. Once again we see no input sanitation or validation. First we see that if there is no get request with the id ‘query’ to return the main page. Otherwise do a get request with the id ‘query’ and a value. We can then see the bold html tags. %lt; is the equivalent of the less than sign ‘<’ so we wind up with <b>query</b> inserted into the page as we can see with the self.render_string() function as it includes the message variable where this html is stored.
Level 2: Persistence is key
We are going to experience a stored XSS vulnerability in this example. This is because the message we submit containing the payload on this site is going to be saved on the server and when a user connects to this page the server will send the message containing the payload. Stored XSS attacks are also known as a persistent attack.
First things first, the previous message is shown in the html within the <blockquote> tags. We see other tags within the message such as an italics and a color which indicates that our input is going to be translated into html. Below we can see the html code for this form and the initial message.
To test if our theory is correct about inserting html into our message we can attempt to send a message containing a tag such as bolding a word. To do this I will type in “testing <b>bold</b>” and select “Share Status!”. The result is exactly what we are looking for!
Entering the below text <img src=”noimage” onerror=”alert(‘cramhack’)”> will execute the alert(‘cramhack’) to finish this challenge.
Level 3: That sinking feeling…
As with most things you should sort of create a routine for yourself to solve a problem. First step, look around the page and think about what features could be vulnerable. For this level we seem to only have 3 buttons that give us 3 different images. Let’s dive a bit deeper. In the HTML there didn’t seem to be anything special. Mainly just shows the 3 tabs and sets chooseTab to a number based on which one was clicked on.
Also within the script we can see that num is being directly inserted into the <img src=” that defines what photo to reveal on the page. For instance the first tab has a photo at src=’/static/level3/cloud1.jpg’ so therefore if we can alter the num variable we can alter this script and exploit the vulnerability.
We can insert our payload right into the url. We know that our input is going to be added to the current <img src= so we can abuse this element. By putting an invalid .jpg filename we can then use the ‘onerror’ function to create an alert when the image does not load. It’s important here not to forget about the single quotation marks. An example payload would be
However, there are cases where you may need to comment the remainder of the line and close out of the <img> tag as so.
Level 4: Context matters
For this example we have a user input form which is used to set a timer based on a user defined number of seconds. This timer will alert the client when the number of seconds is up. First let’s take a look at the HTML. We confirm that it is a form and we see the id of the value we enter is “timer”. We also see that it is using a GET request so the timer requires a separate network request to function. We will be able to analyze this GET request in the network options in the developer tools.
Next we view the source for the challenge. Unfortunately, there doesn’t seem to be anything within these functions that would allow us to manipulate the HTML by inserting our payload. However, we do see a reference to the ‘timer.html’ page which is relevant to our timer form’s input. Let’s do some dynamic analysis with the networking tool.
In developer tools we want to go to the “Network” tab and then we will put in whatever value we’d like in the form and submit it. Of course we are going to want the GET request with the timer value as this is relevant to our form. If we take a look at the “Response” tab for this GET request we see the startTimer() function. We see that it takes in a parameter of seconds and we can see further down that startTimer() takes in whatever value we enter. There is no evidence of input validation or sanitation so this can certainly be the vulnerability. This is especially interesting as the startTimer() is being called with an onload= attribute and thus we can manipulate this to execute our own payload.
While exploiting this we will need to be very cautious as we are going to insert our payload inside the standard code. While we are doing this we can observe the Console tab in developer tools for errors that will help guide us to a successful payload. For instance when I try adding some special characters I received an error which will show me where in the HTML the error occurred. Luckily, this also confirms that there is no input validation or sanitation that we have discovered so far.
Thinking of this logically; we start with an open single quotation so we will insert a value and then we will want to finish the startTimer() function by closing the quotation and parentheses along with the semicolon by inputting something such as the following.
This will cause an error because there is now an additional ‘); that we did not use. However, the onload attribute can execute more than one function. What we will do for our payload is insert our alert() function but utilize the closing ‘); that is already present in the code. Therefore, our final payload will be something such as…
Level 5: Breaking protocol
This challenge shows us a DOM Based XSS. What this means is that the attack payload is executed by altering the DOM “environment” in the browser. We are altering the DOM environment in a way that the client side script runs in an unexpected or unintended manner. In no way are we altering the elements of the page, we are simply abusing the client side script.
There is quite a bit of unnecessary information so I’m not going to include as much as the past challenges. The first page is exactly what it looks like, a page with a link to a sign up page, nothing more.
Let’s checkout the signup page. Here in the HTML we see that the form is actually useless. It does nothing so we can forget about this being vulnerable. Next we see that the “Next” link is referenced to “confirm” but, what is confirm? A reference is meant to be a url or something defined and being that “confirm” is not defined in the HTML we are going to have to look a bit. If you look at the html of the home page or the url of the signup page you will see “signup?next=confirm” which answers the question as to where this variable is defined.
Another common vulnerability on websites is a redirect attack. Using a reputable website to redirect users to a malicious website can be a great way for hackers to lure users to their payload. Simply by changing the url we can alter the “Next >>” button on the page to redirect users to wherever we would like.
Level 6: Follow the *bunny*
Alright let’s see what we got. Firstly, in the HTML we simply see the text portrayed on the screen with the div id “log”. Let’s just jump right into the source on this one as there is nothing more to see in the page’s HTML. We will go through the source below and break it down so we can understand exactly what this page is doing.
Function includeGadget() takes in a url as a parameter. A script HTML element is made with the variable name ‘scriptE1’. For once, there is some input sanitation in the conditional statement. If the url contains ‘https’ or ‘http’ then “log” will be set to cannot load the url however, this is case sensitive so capitalized letters will bypass this sanitation. If we get past the input sanitation then the variable ‘scriptE1’ is going to load the src at the url. Next, we will update ‘log’ id on the page to include the file path and include error checking.
Being that this function literally loads a script based on the url parameter this could certainly be a major vulnerability. Let’s find out where the parameter is defined and where this function gets called.
In the code we even get a nice comment explaining exactly what the function does. Basically, we are going to either get the value after the # in the url or (‘| |’) we are going to default to /static/gadget.js which means we now have a way to execute a payload.
What will our payload be is the question now. We actually have multiple options here. The most obvious choice is to host our payload on a web server we own. This would basically just need to include alert(‘cramhack’) and be able to avoid the input sanitation by utilizing something like capitalized letters in https.
The other option which I will use as it requires no setup is to utilize the data URI scheme. This provides a way to include data on a website as if the data was an external resource. Read more about it on wiki as they explain it best while providing examples. https://en.wikipedia.org/wiki/Data_URI_scheme
***If you are copying and pasting these answers, the single quotation marks may not copy/paste properly. If it does not work simply backspace each of the single quotation marks and place in news ones manually.