Expressing Yourself: Analysis of a Dot Net Elevation of Privilege Vulnerability

Expressing Yourself: Analysis of a Dot Net Elevation of Privilege Vulnerability

In the .NET framework sandboxing is implemented by running code with 'Partial Trust' which uses the built-in Code Access Security (CAS) framework to limit what code can do to a specific set of permissions.

By James Forshaw

Security Consultant

17 December 2013

This is used in technologies such as ClickOnce Deployment to limit what permissions an application runs with. As an example there is the FileIOPermission class which is used when opening a file or enumerating the file system. When a piece of code requires this facility it makes a Demand for the permission. This starts a process where the framework will walk the current execution stack inspecting each piece of calling code and checking if it has that permission in its current set. If the framework encounters a stack frame which doesn’t have that permission (such as partially trusted code) then it throws a SecurityException and blocks the request. This is very important because this protects trusted code from being subverted to do privileged requests as the entire stack leading up to the call is checked.

What happens when trusted code does want to open a file? Well permission objects also have an Assert method. When code calls this method it effectively places a marker on the stack which tells the framework, “Hey no need to go any further, assume from here the entire stack is trusted”. Of course non-trivial code might then do a significant amount of work under this asserted permission some of which could actually be untrusted, but it doesn’t matter, if the framework encountered this untrusted call lower down the stack than the assert it still will fail as expected.

What this can do is set you up for a Trusted Chain attack where you re-purpose existing trusted code to perform an action you control. From the security manager's point of view all calls on the stack are trusted, so the asserted permission holds. This is exactly the same sort of issue which I abused in Java to get my Pwn2Own jacket.

Finding trusted chains is tricky, you need to find the right combination of pieces to put together to have some useful effect. Therefore the stack walking security model works fairly well as long as partially trusted code cannot manufacture its own fully trusted methods. It turns out there was a way to do so, in .NET 3.5 and above it was possible for partially trusted code to create fully trusted methods using the DynamicMethod class. This was apparently a design decision taken by the .NET product team, they did identify it might be a security issue but perhaps did not see a way of exploiting it. Fortunately you can't just exploit it directly, say by calling Assert to disable the security, but what it did allow you to do was create custom trusted chains.

The simplest way of using DynamicMethod, without getting into detail with MS Intermediate Language (MSIL) is by using the Linq Expression class. The C# compiler provides a nice lambda style syntax to populate the Expression object. Note that this is not the same as a normal lambda function that gets compiled into your code and therefore runs with partial trust. Instead the compiler builds a representation of the expression you want to run in memory, and when the Compile method is called a delegate is created backed by a DynamicMethod object.

If you could bind the resulting delegate from this process to a call-back which runs under higher asserted permissions it will not cause the security manager to throw a SecurityException and your action will run as if it had those permissions. This is how you can use this to break out a sandbox.

Exploiting SecurityException

Whenever I audit code for security issues I always try and make note of unusual behaviour. In this case I had noticed a long time ago that the SecurityException class had an Assert for full privileges during its constructor and ToString method. In fact I had abused this before to get an information disclosure vulnerability (CVE-2012-1896 for those interested), but I just knew there must be more to it than that. Let's look at one of the constructors:

Nothing immediately untoward there, but look again at the setting of Demanded. This is actually a property, not a field of the class. This means that when it gets set some code will execute. If we go and look at the setter code, we can find it is converting the passed in demanded object to a string through the XMLUtil.SecurityObjectToXmlString method.

To cut a long story short, what this ends up doing is converting the demanded object to an IPermission interface, calling the ToXml method on that and returning the XML string. But I noticed there was potential for a trusted chain, during the conversion to a string it iterates through the Children property of a SecurityElement object we can control. This almost sounds like my Java Pwn2Own vulnerability all over again.

So we have a potential point for control, we now just need to exploit it. What we need to find is a fully trusted class, which will perform an attacker controlled call-back when iterating a list of values and is also an ArrayList object. Sounds a tough challenge, but you can never underestimate the power of having so much code to reuse. Looking in Reflector there weren't that many derived forms of the ArrayList class, and the ones that did not look like they were immediately useful. Then I found the ArrayList.Adapter static method. This creates an ArrayList around any IList interface; this is far more useful, there are a lot of classes which implement the http://msdn.microsoft.com/en-us/library/system.collections.ilist.aspxIList interface.

After a bit more digging I settled on the ListViewItemCollection class which is part of the ListView control in Windows.Forms. When a ListView is placed in VirtualMode, meaning the list generates items on demand, it will call the RetrieveVirtualItem event on the ListView when the caller requires an item from the collection. Our exploit ends up running the following sequence of events:

  1. A new SecurityException object is created receiving a custom permission object with overridden ToXml method as the demanded parameter.
  2. SecurityException asserts full trust, calls ToXml on the permission object
  3. ListViewItemCollection created in virtual mode, RetrieveVirtualItem event bound to a fully trusted DynamicMethod which runs Process.Start("calc")
  4. ToXml creates a new SecurityElement object and binds the ListViewItemCollection to the Children property via the ArrayList adapter.
  5. SecurityElement object returned to the caller and its ToString method is called. This iterates the Children ArrayList, which in turn calls the RetrieveVirtualItem event, which creates the Windows Calculator

So putting it all together here is some sample code which when placed in a custom permission class and gets passed to the SecurityException constructor will run calculator.

The first attempt to fix the issue was to correct the places where you could abuse this functionality, such as in Windows Forms (see MS13-015) but after supplying Microsoft with at least 3 more vulnerabilities, exploited using the same technique they finally made DynamicMethod not generate trusted methods. This should be fixed for good, I hope, but again it only serves to demonstrate how difficult it is to sandbox code when you run multiple different permission levels within the same process.

About James Forshaw

Security Consultant