In the previous blog about Reflective XSS, we discussed how to manually test for XSS in HTML tags and attributes, along with their bypasses. In this second part, we will explore how to exploit XSS when input is reflected in JavaScript code, for example, when the user input is reflected inside a <script> tag or an event handler.
What is <script> tag?
A <script> tag in HTML is a way to include and run JavaScript code on a webpage. You use the <script> tag to either write JavaScript code directly or link to an external JavaScript file. When the browser loads the webpage, it finds the <script> tag and executes the JavaScript code.
Examples: Inline JavaScript
<!DOCTYPE html>
<html>
<head>
<title>Example Page</title>
</head>
<body>
<h1>Hello, World!</h1>
<script>
alert('This is an inline JavaScript code!');
</script>
</body>
</html>
External JavaScript
<!DOCTYPE html>
<html>
<head>
<title>Example Page</title>
<script src="script.js"></script>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
In the first example, the JavaScript code runs directly from within the HTML file. In the second example, the JavaScript code is in an external file called script.js, and the <script> tag links to that file.
How Browsers Parse and Render HTML and JavaScript
1. HTML Parsing:
- The browser reads the HTML file from top to bottom.
- It builds a structure called the Document Object Model (DOM), which represents the elements on the page.
2. CSS Parsing
- If the HTML file includes CSS (Cascading Style Sheets), the browser reads and applies the styles.
3. JavaScript Execution
- When the browser encounters a <script> tag, it pauses HTML parsing to load and execute JavaScript.
- If the <script> tag includes src, the browser fetches the external JavaScript file and runs it.
4. Rendering
- After parsing HTML, CSS, and executing JavaScript, the browser combines the DOM and CSSOM to render the webpage visually.
Possible Reflection points inside <script> tag
Reflection points in <script> tags are places where user input can be dynamically inserted into JavaScript code. Here are some common reflection points within <script> tags:
1. Inline JavaScript
- This script assigns the value USER_INPUT to the variable userInput and then logs it to the browser's console. If USER_INPUT is derived from user input and contains malicious JavaScript, it could lead to cross-site scripting (XSS).
2. Dynamic Script Content
<script>
var message = "Welcome, " + "USER_INPUT";
alert(message);
</script>
-
In this script, a message is dynamically created by concatenating the string Welcome, with USER_INPUT. The resulting message is then displayed in an alert box. If USER_INPUT is untrusted user input, it could include harmful script content, leading to an XSS attack.
3. DOM
<script>
document.getElementById("username").innerHTML = "USER_INPUT";
</script>
-
This script targets an HTML element with the ID username and replaces its inner HTML with the value of "USER_INPUT". If "USER_INPUT" contains malicious content, it could alter the webpage's structure or behavior, leading to XSS vulnerabilities.
4. Event Handlers
<script>
document.getElementById("myButton").onclick = function() {
alert("Hello, " + "USER_INPUT");
};
</script>
- Here, an event handler is assigned to an HTML element with the ID myButton. When the button is clicked, an alert box displays a message that includes "USER_INPUT". If "USER_INPUT" is unsafe and is not properly sanitized, it could trigger XSS when the event is fired.
5. URL Parameters
<script>
var params = new URLSearchParams(window.location.search);
var user = params.get('user'); // USER_INPUT
document.write("Hello, " + user);
</script>
- This script extracts the user parameter from the URL's query string and uses it to write a greeting directly into the document. If the user parameter contains unsensitized input, it could lead to XSS by executing malicious scripts directly in the user's browser.
How to break out of JavaScript syntax?
Now, let’s try to break the context between the <script> tags using the example.
Input: https://example.com/?search=fuzz
Reflected Output:
Here, in this case, we have two reflection points: one between <h1> tags and another between <script> tags. So now, let's try to break the content in Reflection 1 by adding a < character, just like we learned in Part 1.
Input: https://example.com/?search=fuzz<>
Reflected Output:
In the above image, you can see that the application is encoding the inputs and converting the < character to < and the > character to > in both of the reflection points here. This means we cannot perform XSS in Reflection 1.
Let’s move on to Reflection 2 now. The syntax is JavaScript here, so we need to insert a payload that breaks the context and triggers the alert. First, the application is using a single quote here. Let’s try inserting a single quote (') to break the context.
Input: https://example.com/?search=fuzz<>’
Reflected Output:
Here, you can analyze Reflection 2 and observe that the application does not sanitize the ' character. Now, let’s attempt to perform XSS here. In JavaScript, you can insert a string using two hyphens (-). Therefore, our payload would be -alert(1)- in this context.
Input: https://example.com/?search=fuzz<>’-alert(1)-’
Reflected Output:
In Reflection 2 you can see that the color of syntax has been changed and it is a valid JavaScript syntax.
var searchTerms = 'fuzz<>'-alert(1)-'';
Breakdown of the Code
- 'fuzz<>'
- This is a string that contains the HTML entities < and >
- < stands for the less-than symbol (<).
- > stands for the greater-than symbol (>).
- So, 'fuzz<>' is equivalent to the string 'fuzz<>', where the < and > characters are encoded in HTML entity form.
- '-alert(1)-'
- This part is a string that seems to be intended as an XSS payload or test input. It contains the JavaScript function alert(1) surrounded by hyphens.
- The alert(1) function would, if executed in a browser, display a popup alert box with the number "1".
Final Thoughts
When testing for XSS, you should avoid spamming multiple payloads. Instead, try enumerating what is being blocked or sanitized by the application and find alternatives to bypass the restrictions.
Citations: Portswigger