Click here to Skip to main content
15,884,425 members
Articles / XSS

In Depth Cross Site Scripting

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
11 Feb 2013CPOL8 min read 15.9K   1   1
Cross site scripting and the way that it can creep into our programs and what different cross site scripting input strings look like

Introduction

This is the second post in a series on cross site scripting (XSS). In this entry, I examine cross site scripting and the way that it can creep into our programs and what different cross site scripting input strings look like. Once we develop a deep understanding of XSS, I’ll show you how to exploit XSS vulnerabilities in my next post before wrapping up with how to defeat input filters & remediation to cross site scripting vulnerabilities. You can see the first post in the series here.

I have provided another tutorial web application so that you can follow along with this post, the web application which is functioning and usable can be found here.

Cross Site Scripting

There are essentially 5 main input areas where we can introduce cross site scripting vulnerabilities. They are:

  1. Hidden Fields on a Form
  2. Session Storage
  3. Cookie Storage
  4. Injected Files
  5. Injected Cookies

Some of these areas are more severe and damaging for various reasons which I’ll explore as I go. An interesting side note, if you notice the screen shot, below, or try it for yourself. When I point the ZAP attack proxy at http://exploits.howellsonline.ca/xss/moderate/default.aspx, the ZAP attack proxy does not detect any cross site scripting vulnerabilities, as seen in the image below. Therefore it’s not always enough for QA or Dev to use an attack proxy and expect to find all the vulnerabilities through such a manner, attack proxies are just a tool in the tool box but should not replace actual testing. These examples for this demo have been tested and work in Firefox. Your mileage may vary in other browsers. Note wordpress seems to have some difficulties with the JavaScript attack strings rendering properly. You can find them in order for this tutorial here.

Hidden Input Field

The hidden input field on an HTML form is used for storing input that’s well hidden from the user. Essentially, what the first example in the demo does is set a hidden input and post back, on the post back, the hidden form value is read and displayed to the user. When used correctly, everything works as expected and is indicated from the image below.

The attack string we’ll use to demonstrate this vulnerability is:

JavaScript
<script type="text/javascript">// <![CDATA[
alert("XSS")//<
// ]]></script>

However, when this input is used for malicious purposes & the cross site scripting vulnerability is discovered, look at the outcome from the image below. To try this example below yourself, input the following string into the text box.

Now let's examine the code that causes this vulnerability.

Client Side

JavaScript

JavaScript
<script type="text/javascript">// <![CDATA[
function populateData() 
{             form1.elements["m_hdnInpt"].value = document.getElementById("m_txtHiddenField").value;
}
// ]]></script>

Server

JavaScript
if (Page.IsPostBack)
            {
                Response.Output.WriteLine("Your input from example  was: " + m_hdnInpt.Value);
            }

It’s obvious to see what the problem is here, we are populating a hidden input on client side, with the value of the user input and then blatantly writing the value back into the raw HTML on the server to be redisplayed to the client. Note that this is not detected by ZAP as a cross site scripting vulnerability. The server should not just trust the input coming from the client.

Session Storage

In this example, if you want, you can first test on the demo application that normal input works as desired, I know it does so I am going to move straight to the vulnerability. The difference between the first example and this example is that, in the first example the form posted back to Default.aspx, in this example the form redirects to SessionInpt.aspx, this example and the remaining examples are similar to the first post in this series were data is being passed between two pages.

The attack string I am going to use for this example is:

JavaScript
&lt;<script type="text/javascript">// <![CDATA[
alert("XSS");//<
// ]]></script>

Notice from the image below, that the cross site scripting vulnerability was successfully exploited.

Now let's examine the code:

Server Side

JavaScript
Session["SessionInpt"] = m_sessionInpt.Text;
           Response.Redirect("/xss/moderate/SessionInpt.aspx");

Redirect Server

JavaScript
Response.Output.WriteLine("Your input for example 2 was: " + Session["SessionInpt"]);

As you can see, Default.aspx blindly throws the data from the user input into a session variable, which SessionInpt.aspx gladly accepts, trusting that everything in the session is safe. If I were in a leadership position reviewing this code, I would be upset that Default.aspx did not do any input validation, I would be even more upset that SessionInpt.aspx did not do any input validation and just trusted the input. This type of a situation can result if you have two devs working on these pages separately, each trusts the other to handle security. This is also very good justification for performing a security review. Having validation on both pages is best and builds on a concept of defense in depth.

Cookie Storage

This example is one of my favourites, and the reason is because of the many ways that it can actually impact the user. Up until this point, the previous two examples and the previous post were essentially a 1 time cross site scripting attack. In this example, we’re actually going to store the attack in a cookie.
The attack string we’ll use for this attack is:

JavaScript
&lt;<script type="text/javascript">// <![CDATA[
alert("XSS Attack")//<
// ]]></script>

As you can see from the image below, the exploit is successful.

The more disturbing trend here is because this exploit is saved in a cookie, everytime the user visits the page, they will re-see the exploit. If you’re following along in the demo application, I would encourage you to enter the attack string on Default.aspx. When you’re redirected, copy the URL that you’re redirected too, in your URL bar navigate to a different URL, say Google. Once Google loads, paste the redirected URL that you copied back into your browser. Notice how the exploit immediately reappears and will continue to reappear until you clean your cookie. If you would like to clean your cookie and try again, selected the delete cookie button.

Let's examine the code:

Server Side

JavaScript
Response.Cookies["UserInpt"]["Data"] = m_txtCookieInpt.Text;
          Response.Redirect("/xss/moderate/CookieInpt.aspx");

Redirected Page

JavaScript
String txt = Request.Cookies["UserInpt"]["Data"];
         Response.Output.WriteLine("Your input for example 3 was: " + txt);

As you can see, Default.aspx drops a cookie when the button is clicked, that CookieInput.aspx is going to pick up and constantly read from the cookie for exploits.howellsonline.ca until the cookie is cleared, therefore the user will constantly see this exploit, and it may drive them away from your site.

Injected Files

This is one of the more advanced forms of cross site scripting, this is where the attack attempts to execute some malicious code on your website, they do this by injecting their own JavaScript file.
For this example, our attack string will be:

Look at the output shown below:

That wasn’t at all what you entered in the text box, was it? How was the attacker able to do this? Let's look at the code: Server Side.

JavaScript
Session["Injected"] = m_txtBoxInjected.Text;
           Response.Redirect("/xss/moderate/InjectedXss.aspx");

Redirected Page

JavaScript
String txt = (String)Session["Injected"];
Response.Output.WriteLine("Your input for example 4 was: " + txt);

There is one more important file that we need to look at and that, was the script we injected which can be found here.

Injected Script

JavaScript
document.writeln("Hello site you have an injected suffered an XSS attack");

This attack was pretty simple, essentially I was able to get my injected script to run. The reason that this was possible was because the Redirected page blindly accepted input from Session, and immediately wrote that input to the HTML without verification. When it did this and the page rendered, the page went off and made an HTTP GET request for the injected URL, as soon as the requested script was received, the script executed and defaced my web page. Interestingly enough up until this point, all of the other attacks that we’ve seen have displayed a message box, however this script does not display a message box and if it were not for the output, the user wouldn’t know that this script had executed at all.

Injected Cookies

This next example demonstrates the combination of a couple of attack vectors we’ve already seen, in this example, we are going to inject a script into a cookie, every time the page loads, the page will download the script as in the previous example.

The attack string we’ll use for this attack is:

As you see, the attack is successful.

Up until this point, you may have noticed a pattern, all of the previous examples use the pattern:

JavaScript
Response.Output.WriteLine(Some OUTPUT)

It would stand to reason then that as long as you don’t use this pattern that you’re reasonably okay. Up until this example, you would be correct.
Let's look at the code:

Server Side

JavaScript
Response.Cookies["UserInpt"]["Deface"] = TextBox1.Text;
           Response.Redirect("/xss/moderate/InjectedDefaced.aspx");

InjectedDefaced

JavaScript
<script type="text/javascript">// <![CDATA[
function handleCookies() {
         var cookie = document.cookie;
         var cookieValue = cookie.substr(cookie.lastIndexOf("Deface=") + 7, cookie.length - 7);
         document.write("Welcome back: " + cookieValue);
     }
// ]]></script>

Notice the difference here? The difference is that the cookie is read from the client when the HTML body loads. So instead of the vulnerability being made in the back end server side code, it’s actually all happening on the client, therefore the request does not have to back to the server and come back to the client.

In Closing

The truest danger with example #5 is, once an attacker has their URL for JavaScript stored in somewhere like a cookie, they can modify the JavaScript to do whatever they want, against the unsuspecting user. So perhaps for maybe a month, my JavaScript file does nothing at all. Then I have it start stealing the data the user enters from on the form of your website. Because the URL for my attack vector is saved in your cookie, I almost have complete control to do as I wish.

I hope the moral of the story is do not trust unvalidated user input. I’ve demonstrated 5 sources that user input can come from, all of it as you see should be properly validated before being displayed and shown to the user. I would even recommend validating the input both on input and before you show it to the user, however as a minimum it should be validated before being written to the HTML.

In my next post, I’ll show you how to exploit these vulnerabilities, and then how to re-mediate them and how potential attackers will attempt to bypass your filtering and what you can do about it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
Canada Canada
I am a Sr Engineer for a major security firm; I have been developing software professionally for 8 years now; I've worked for start ups, small companies, large companies, myself, education. Currently the company I work for has 7,000+ employees worldwide. I am responsible for our platform security, I write code, implement features, educate other engineers about security, I perform security reviews, threat modeling, continue to educate myself on the latest software. By night, I actively work to educate other developers about security and security issues. I also founded a local chapter of OWASP which I organize and run.

I cut my teeth developing in C++ and it's still where my heart is with development, lately I've been writing a lot of C# code & some java, but I do have a project or two coming out in C++ /DiectX 11 whenever I get the time.

When I am not developing code I am spending my time with my wife and daughter or I am lost deep in the woods some where on a camping trip with friends. If you can't find me with a GPS and a SPOT device then chances are I am on the Rugby pitch playing Rugby and having a great time doing so.


You can find more about me and My thoughts on security

Comments and Discussions

 
QuestionStored XSS vulnerability Pin
snpcrud4-Mar-13 14:57
snpcrud4-Mar-13 14:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.