A simple but deadly reflected XSS hole you can fall into with ASP.Net MVC & the Razor view engine

Hackered
Sunday, May 3, 2015
by Sean McAlinden

Cross site scripting (XSS) is an attack most of us have heard of and also have an appreciation of the devestation that can be caused with the right attack.

Despite this fact, I still believe most developers do not truly understand it or know how to fully protect their sites.

Whilst we all mostly know encoding volatile input values before rendering is a crucial defence, in this post I am going to demonstrate an attack using ASP.Net MVC, ViewBags and some naughty javascript that requires protection by a specific encoder.

Ok, let's get to it...

The code in my view won't change in each example, it is a little bit of Javascript which displays a welcome message:

<div id="welcomeMessage"></div>
<script type="text/javascript">
    $(document).ready(function() {
        var message = '@ViewBag.DisplayName';
        $('#welcomeMessage').html('Welcome ' + message);
    });
</script>

Example 1: No protection

public ActionResult Index(string displayName)
{
    ViewBag.DisplayName = displayName;

    return View();
}

If I request the following url: http://localhost:49263/Home/Index?displayName=Sean, a nice message stating Welcome Sean is printed out on the page.

If I request the following url: http://localhost:49263/Home/Index?displayName=Sean\x3cscript\x3ealert(\x27doingSomethingNaughty\x27)\x3c/script\x3e, a nice message is also displayed stating Welcome Sean, however a alert box is displayed letting you know I am doingSomethingNaughty.

It is important to note that a real attack would more likely silently create a web socket connection between your client and the attack server, or something else just as interesting.

The above url is just a very simple hex attack.

Why is the RequestValidator not catching this script?

Mainly as it is not a script at this point, or something that would become a script if it were html decoded, it is just a set of characters.

If you were to print this out within the html and not in a javascript block it would print out just fine and not cause an issue.

However, the javascript engine is interpretting the characters and decoding it into the attack string - this is a crucial point to remember.

Example 2: Html Encode - surely this will save us!

I've updated my controller to html encode the value in the hope that the encoding will help:

public ActionResult Index(string displayName)
{
    ViewBag.DisplayName = Server.HtmlEncode(displayName);

    return View();
}

As expected this has not helped at all, the evil alert box pops up to tell us we've fixed nothing...

Example 3: Javascript Encode - this one will work :)

This works because it is the Javascript engine which is decoding the attack string - we need to stop this from happening.

First thing you should do is NuGet in the AntiXss library from Microsoft into your application, you can find it here: https://www.nuget.org/packages/AntiXSS.

public ActionResult Index(string displayName)
{
    ViewBag.DisplayName = Encoder.JavaScriptEncode(displayName, false);

    return View();
}

This prints out the following welcome message:

Welcome Sean\x3cscript\x3ealert(\x27doingSomethingNaughty\x27)\x3c/script\x3e

Summary

Cross site scripting (XSS) is a nightmare that will not be going away anytime soon, it is so easy for us to leave holes within our apps so the more we know about the subject the better.

The more you hack, the more you'll know.