This October, Microsoft has provided a security update for System.Web.Mvc.dll which addresses a ‘Security Feature Bypass’. The vulnerability itself is in ASP.NET MVC technology and given its wide adoption we thought we would take a closer look.
Referring to the bulletin we can glean a few useful pieces of information:
“A cross-site scripting (XSS) vulnerability exists in ASP.NET MVC that could allow an attacker to inject a client-side script into the user's web browser… The vulnerability is caused when ASP.NET MVC fails to properly encode input.”
We looked at System.Web.Mvc.dll Version 5.1.20129.0 (unpatched) vs. System.Web.Mvc.dll Version 5.1.20821.0 (patched)
After decompiling each DLL with dotPeek (https://www.jetbrains.com/decompiler/) and diffing the output with WinMerge (http://winmerge.org/) we can see there are only a few files that have nontrivial changes.
[caption id="attachment_20567" align="alignnone" width="806"] Figure 1 - Changed Classes[/caption]
After reviewing the few areas that actually had meaningful changes, it appeared that XSS could have been patched in a few places, but DisplayTextExtensions.cs contained the fix most interesting to us. The pre-patched code can be seen below.
[caption id="attachment_20568" align="alignnone" width="676"] Figured 2 - DisplayTextExtensions.cs (System.Web.MVC.dll 5.1.20129.0)[/caption]
We can now compare this code with the new logic which utilizes the new HtmlEncode property of the modelMetadata object to determine whether or not to HtmlEncode the string.
[caption id="attachment_20569" align="alignnone" width="662"] Figure 3 - DisplayTextExtensions.cs (System.Web.MVC.dll 5.1.20821.0)[/caption]
The metadata.HtmlEncode bool which the conditional is based upon can be found in ModelMetadata.cs.
[caption id="attachment_20570" align="alignnone" width="458"] Figure 4 - ModelMetadata.cs (System.Web.MVC.dll 5.1.20821.0)[/caption]
We can see here that this added boolean defaults to true.
So to restate our discoveries, we think that the DisplayTextFor() function will call the DisplayTextHelper() function which in turn will allow for XSS due to its failure to encode HTML characters. The easiest thing to do here is mock up some sample code to see what happens. Obviously it was made quickly for brevity of this post so some parts will change in a real-world application. Most of that should be obvious but we made a couple extend notes before so there isn't any confusion.
We first create a model ‘User’ with a property ‘name’.
We then construct our Controller which contains a classical XSS vector in this Name property. Obviously in a real-world web application myUser.Name would have its data set from some user controlled area of web code like a form or related.
The bug is as simple as now calling displayTextFor() on our Name property which triggers the underlying XSS. In a real-world scenario you would want to take into account ASP.NET and Internet Explorer's XSS filters. Those are always useful mitigation but never 100% in filtering out this type of data before it reaches a vulnerable function such as was fixed in this patch.
It is important for web developers to review their servers to both make sure that this patch has been applied and that their MVC related projects have been updated to patched versions. For customers you can use the following vulnerability audits from Retina to determine if a server has been patched or not:
[MS14-059] – Vulnerability in ASP.NET MVC Could Allow Security Feature Bypass (2990942)
35434 – Microsoft ASP.NET MVC Security Feature Bypass (2990942) – MVC 2.0 35435 – Microsoft ASP.NET MVC Security Feature Bypass (2990942) – MVC 3.0 35436 – Microsoft ASP.NET MVC Security Feature Bypass (2990942) – MVC 4.0 35437 – Microsoft ASP.NET MVC Security Feature Bypass (2990942) – MVC 5.0 35439 – Microsoft ASP.NET MVC Security Feature Bypass (2990942) – MVC 5.1