A web browser is a code interpreter that takes HTML and script code to present a document to the user in an attractive and useful format, including text, images, and video clips. It allows the user to interact with dynamic elements including search fields, hyperlinks, forms, video and audio controls, and many others.
There are many ways for an application to manage this dynamic interaction with users. The one way that is most common in today's web applications is the use of client-side script code. This means that the server sends code to the client that will be executed by the web browser.
When user input is used to determine the script code behavior, and this input is not properly validated and sanitized in order to prevent it from containing code, rather than information, the injected code will be executed by the browser and you will have a Cross-Site Scripting (XSS) vulnerability. In this article, we will be going to explore cross-site scripting.
XSS is a type of code injection that happens when script
code is added to the user's input and processed as code instead of data by the
web browser, which then executes it, altering the way the user sees the page
and/or its functionality.
Explaining “Scripting”
Let’s first explain the
“Scripting” part of cross-site scripting. Most major websites today use
JavaScript (or sometimes VBScript) to perform calculations, page formatting,
cookie management, and other client-side actions. This type of script is run on
the browsing user’s computer (client side) within the web browser, not on the
web server itself.
Let’s explain it with a simple example:
In
this simple example, the web page instructed the web browser via JavaScript to write
the text, “A script was used to display this text”. When the web browser
executes this script, the resulting page looks like this.
Simple script example result page
|
The user browsing this website would have no idea that a script running locally transformed the content of the web page. From the rendered view within the browser, it doesn’t appear to be any different from a static HTML page. Only if a user were to look at the HTML source could they see the JavaScript.
Scripting support is
included in most browsers and is typically enabled by default. Web application developers have become accustomed to using scripts to automate client-side
functions. It is important to note that the script being enabled and used is not
the cause of the vulnerabilities. It is only when a web application developer
makes a mistake that scripting becomes dangerous. Without web application
flaws, scripting is safe and is a good tool to enable a rich user experience.
Explaining Cross-Site Scripting
Web application flaws that lead to cross-site scripting are generally input validation vulnerabilities. A successful XSS attack involves two steps. First, the attackers send to a web application a request that the web application does not properly sanitize or validate as being properly formatted. Second, the web application returns to the attacker, without encoding, a web response page that includes the improperly formatted input. Some examples of the characters that are used for XSS include & < > " ' and /. These characters should be encoded, preferably using hex, or escaped when being returned to the browser.
The OWASP XSS (Cross-Site Scripting) Prevention Cheat Sheet is a project that provides guidance on properly protecting against XSS. It can be found at the below link.
Cross-Site Scripting Prevention Cheat Sheet
The Cross-Site Scripting Prevention Cheat Sheet provides developers with a set of best practices to prevent cross-site scripting (XSS) vulnerabilities in web applications.
There are three major types of cross-site scripting: reflected XSS, stored XSS, and DOM-based XSS.
- Reflected XSS
- Stored XSS
- DOM-based XSS
Reflected XSS
Reflected XSS is one of the most widely exploited web application vulnerabilities. To exploit this vulnerability, the application takes one or more parameters as input, which is reflected back to the web page generated by the application.
This may not sound harmful at the moment but this vulnerability can be exploited to do one of the following things or more:
- Execute malicious JavaScript
- Execute client-side exploits
- Bypass CSRF protections
- Temporary defacements and other nuisance
The first instance is of quite a concern, as this allows a hacker to execute client-side JavaScript code of his choice to be rendered and executed by the browser of the victim or the viewer viewing the page. In this case, it gets worse when the session or other essential cookies of the user are available to be stolen through the document.cookie property of JavaScript. Consider the following JavaScript code:
This code, if executed on a browser, will transfer all the cookies that fall under the origin of the webpage to evil.example.com as soon as it gets loaded.
However, there is an
exception; cookies marked with HttpOnly will not be transferred as this acts as
a defensive measure to prevent marked cookies from being accessed through "document.cookie".
Demonstrating reflected XSS vulnerability
I've made a web page in a vulnerable demonstration domain that simply reflects whatever input that is provided inside the GET parameter XSS.
This PHP page places the value passed in for parameter id into a variable named, “name”. It then writes the passed-in value directly into the response.
To run this PHP code, you need a PHP-enabled web server like Apache or Nginx.
Firstly, Save the code into a file named “welcome.php” and Place this file in the appropriate web server directory.
Now, we will have to start the apache2 server.
When you access the PHP file through your web server (e.g., http://localhost/welcome.php), you'll see the form. After submitting the form with a name(e.g. Bob), the PHP code will display the "Hello" message if the name parameter is provided.
Sample vulnerable PHP page
|
Because the web page does not validate the passed-in value and displays it verbatim on the response page, this page is vulnerable to an XSS attack. Instead of “Bob”, an attacker could pass in a script such as the following to simply pop up a dialog box:
In that case, the resulting web page would look more like
this:
Sample vulnerable PHP page XSS example
|
As you can see, the passed-in script was executed within the
client-side browser. The alert box proves that the web application is
vulnerable to a reflected XSS attack.
Stored XSS or Persistent XSS
An XSS flaw is called
persistent or stored when the injected data is stored on the web server or the
database, and the application serves it back to one or all users of the
application without validation. An attacker whose goal is to infect every
visitor to the website would use a persistent XSS attack. This enables the
attacker to exploit the website on a large scale.
Typical targets of Persistent XSS flaws are as follows:
- Web-based discussion forums
- Social networking websites
- News websites
Persistent XSS is
considered to be more serious than any other XSS flaws, as the attacker's
malicious script is injected into the victim's browser automatically. It does
not require a phishing attack to lure the user into clicking on a link.
The attacker uploads the
malicious script onto a vulnerable website, and it is then delivered to the
victim's browser as part of their regular browsing activity. As XSS can also be
used to load scripts from an external site. This is especially damaging in
stored XSS.
When injected, the following code will query the remote server for the JavaScript to be executed:
The application is an
online forum where users can create accounts and interact with others. The
application stores the user's profile in a database along with other details.
The attacker determines that the application fails to sanitize the data kept in
the comments section and uses this opportunity to add malicious JavaScript to
that field. This JavaScript gets stored in the database of the web application.
During normal browsing, when an innocent victim views these comments, the
JavaScript gets executed in the victim's browser, which then grabs the cookie
and delivers it to a remote server under the control of the attacker.
Recently, stored XSS has
been used on multiple sites across the internet to exploit users' websites as
workers for cryptocurrency mining or to form botnets of browsers.
Demonstrating stored XSS.
Let’s take a look at an example stored XSS vulnerability. We’ll use the Mutillidae web application from the OWASP Broken Web Application (BWA) VM that we introduced in our previous Article.
To follow along, browse the following URL:
Now, log in with the username, “user” and the password, “user”:
In this example, we will be posting an entry to the user's blog, and storing an attack script for an unsuspecting victim to view. The website http://ha.ckers.org contains a convenient demonstration script we’ll use for this example.
Click the “Add to your blog” link in the left margin’s A3 – Cross-Site Scripting (XSS) section.
On click, you will get below webpage:
In this example, we will be posting an entry to the user's blog, and storing an attack script for an unsuspecting victim to view. The “blog entry” then would look like the following:
Mutillidae stored XSS example
|
Now, We will have to Save the Blog Entry and create a JavaScript file to link "ha.ckers.org". The JS file to which we are linking contains the following script:
Save this script as "xss.js" and copy this file to the web server:
Now, we will have to add a hostname on "/etc/hosts" file.
When a victim views the blog (by clicking the “View someone’s blog” link) and chooses the Author as a User, the attack script stored at ha.ckers.org runs in the context of the Mutillidae website.
On clicking the "View Blog Entries" button, You can see the result of this attack below screenshot:
Mutillidae stored XSS attack result
|
DOM-based XSS
The third type of XSS is local and directly affects the victim's browser. This attack does not rely on malicious content being sent to the server, but it uses the Document Object Model (DOM), which is the browser's API in order to manipulate and present the web pages. In persistent and reflected XSS, the script is included in the response by the server. The victim's browser accepts it, assuming it to be a legitimate part of the web page, and executes it as the page loads. In DOM-based XSS, only the legitimate script provided by the server is executed.
An increasing number of
HTML pages are generated by downloading JavaScript on the client side and using
configuration parameters to adjust what the user sees, rather than being sent
by the server as they should be shown. Any time an element of the page is to be
changed without refreshing the entire page, it is done using JavaScript. A
typical example is a website that allows a user to change the page's language
or colors, or resize the elements within it.
DOM-based XSS makes use
of this legitimate client-side code to execute a scripting attack. The most
important part of DOM-based XSS is that the legitimate script is using a
user-supplied input to add HTML content to the web page displayed on the user's
browser.
Demonstrating DOM-based XSS
Let us consider the following piece of code to better understand DOM-based XSS:
To run this code, you can follow these steps:
Firstly, save the code with a ".html" extension, for example, "dom-xss.html" and open this file, which will load a webpage on the web browser.
Webpage loaded |
This web page will load, and the JavaScript code will retrieve the name from the URL's hash value and display a personalized greeting.
Remember: To provide a name in the URL hash, you can append "#" followed by the name you want to display. For example, to greet the name "TechnoScience", use http://[URL]/dom-xss.html#TechnoScience.
As You can see, the greeting name is displayed, which is taken from the location.hash attribute. In this instance, the input here was benign, but if it contained something malicious, like an XSS payload, then what would happen?
In the given scenario, an XSS payload is inserted into the location.hash property of the URL. This payload is then written to the web page's DOM using the document.write() function. The payload consists of a code that tries to load an image from a specific location, 'x' in this case.
If the image is not found, it triggers the execution of the console.log() function. As a result, the payload is executed, and the console.log() statement is executed, potentially leading to the output of a message or information in the browser's console.
DOM-based XSS attack result on injection after XSS payload |
Open the browser's console by right-clicking on the page, and selecting "Inspect Element". In the developer tools panel, navigate to the "Console" tab.
DOM-based XSS attack result on the Console tab |
In the console, you should see the output "1234" logged, indicating that the console.log(1234) code inside the "onerror" attribute was executed.
In DOM-based XSS, the attack payload is injected into a web page's input or source code, and it later reaches a specific part of the web page called a DOM sink.
Indication of DOM sink |
This DOM sink, often represented by a function like document.write, directly writes the payload onto the page, causing an XSS vulnerability. This type of XSS differs from the usual XSS because the attack occurs entirely on the client side, without involving communication with the server.
Attack Possibilities with XSS
Our demonstration XSS attacks have simply displayed an alert box or displayed text and a cookie ID on the page. While these examples have only displayed information, far more damaging attacks are possible. For example, the malicious script could post the cookie values to an attacker’s website, potentially allowing an attacker to log in as the user or resume an in-process session. The script could also rewrite the content of the page, making it appear as if it has been defaced.
Cross-Site Scripting (XSS) attacks can be used in a variety of ways, including:
- Stealing credentials:
- Attackers can use XSS to steal user credentials such as usernames and passwords, session tokens, and other sensitive information.
- Defacing websites:
- Attackers can use XSS to change the appearance of a website, including adding or removing content, changing images or logos, and altering the layout or design.
- Malvertising:
- Attackers can use XSS to inject malicious ads into legitimate websites, which can then infect the user's computer with malware or other malicious software.
- Phishing attacks:
- Attackers can use XSS to create fake login pages or other forms that trick users into entering their credentials or other sensitive information.
- Session hijacking:
- Attackers can use XSS to steal a user's session ID, allowing them to hijack the user's session and perform actions on their behalf.
- Cookie theft:
- Attackers can use XSS to steal user cookies, which can then be used to impersonate the user and perform actions on their behalf.
- Keylogging:
- Attackers can use XSS to log keystrokes made by the user, allowing them to capture passwords and other sensitive information.
Attackers have recently leveraged XSS vulnerabilities on popular social networking sites to create an “XSS worm,” spreading from one user’s page to another. XSS worms could be leveraged to perform denial-of-service or brute-force attacks unbeknownst to the user.
A fun way to explore the power of XSS attacks is to install the Browser Exploitation Framework (BeEF). Exploiting a victim via an XSS vulnerability can turn their browser into a “zombie” controlled by the BeEF command-and-control interface.
Client-Side Exploitation with BeEF
Client-Side Exploitation with BeEF is a comprehensive guide that covers the fundamentals of client-side attacks and demonstrates how to use the BeEF (Browser Exploitation Framework) tool for testing web browser vulnerabilities.
BeEF can force a browser to visit a malicious website, log keystrokes, detect if a browser is using Tor (from www.torproject.org), perform port scans, and even run Metasploit attack modules. It’s a great demonstration of the power of XSS attacks.