.NET Advanced Code Auditing XmlSerializer Deserialization Vulnerability

Coding Challenge

This is an article use google translated from the website of anquanke.com. The original link address is: https://www.anquanke.com/post/id/172316

0X00 Foreword

The XmlSerializer class in the .NET Framework is a great tool for mapping highly structured XML data to .NET objects. The XmlSerializer class performs transformations between XML documents and objects through a single API call in the program. The conversion mapping rules are represented in the .NET class by metadata attributes. If the developer uses the static method of the Type class to get the external data, and calls Deserialize to deserialize the xml data, it will trigger a deserialization vulnerability attack (such as DotNetNuke arbitrary). Code Execution Vulnerability CVE-2017-9822), the author made a related brain map introduction and recurrence from the perspective of principle and code audit.

0X01 XmlSerializer serialization

The XmlSerializer class in the System.Xml.Serialization namespace in the .NET Framework can bind an XML document to an instance of a .NET class. One thing to note is that it can only convert public and public fields of an object into XML elements or attributes. And consists of two methods: Serialize() is used to generate XML from the object instance; Deserialize() is used to parse the XML document into an object graph, and the serialized data can be data, fields, arrays, and XmlElement and XmlAttribute object formats. Embedded XML. Specifically look at the demo below.

XmlElement specifies that the attribute is to be serialized as an element, XmlAttribute specifies that the attribute is to be serialized as a property, XmlRoot attribute specifies that the class is to be serialized as a root element, and that the attribute of the attribute type affects the name, namespace, and type to be generated. Create an instance of the TestClass class to fill its properties into a file. The XmlSerializer.Serialize method overload can accept Stream, TextWrite, and XmlWrite classes. The resulting XML file lists the TestClass element, the Classname property, and other properties stored as elements. :

0x02 XmlSerialize deserialization

The anti-sequence process: Converting an xml file to an object is accomplished by calling the XmlSerializer.Deserialize method by creating a new object. The most critical part of the serialization is the parameter passed in the new XmlSerializer constructor. This parameter comes from the System. The .Type class, which allows access to information about any data type. There are three ways to point to a Type reference of any given type.

2.1, typeof

Instantiate the typeof(TestClass) passed by XmlSerializer to get the Type of the TestClass class. The typeof is the operator in C#. The passed parameter can only be the name of the type, but not the instantiated object, as shown in the following Demo.

After obtaining the Type by typeof, you can get all the Methods, Members and other information in the class. When the following figure runs Debug, a pop-up message dialog box displays the value of the current member Name.

2.2, object.Type

All classes in .NET are ultimately derived from System.Object. There are many public and protected member methods defined in the Object class. These methods can be used in all other classes defined by themselves. The GetType method is one of them. The method returns an instance of the class derived from System.Type, because it can provide information about the class to which the object member belongs, including basic types, methods, properties, etc. In the above case, the TestClass is instantiated, and then the Type of the current instance is obtained, as shown in the following Demo.

2.3, Type.GetType

The third method is the static method GetType of the Type class. This method allows the outside world to pass in the string. This is a big advantage. You only need to pass the fully qualified name to call the methods, properties, etc. in the class.

The parameters passed in Type.GetType are also the pollution points generated by deserialization. The next step is to find the classes that can be used for attack.

0X03 build attack chain

First put the attack chain to create a complete demo after the success, this demo can be reused anywhere (not involving .NET Core, MVC), as shown below:

As long as the XmlSerializer has a deserialization vulnerability, the contents of the following Demo can be used, involving three main technical points. The following principles are introduced separately.

3.1, ObjectDataProvider

The ObjectDataProvider class, which is located in the System.Windows.Data namespace, can call any method in the referenced class, providing the member ObjectInstance with a similar instantiation class, the member MethodName to call the name of the method of the specified type, and the member MethodParameters representing the method passed to the method. Parameters, refer to the figure below

Then define a ClassMethod method for the TestClass class, and the code implementation calls System.Diagnostics.Process.Start to start a new process pop-up calculator. If you use XmlSerializer to serialize directly, it will throw an exception, because the member type of ObjectInstance is unknown during the serialization process, but you can use the ExpandedWrapper extension class to preload the query of the related entity inside the system to avoid exception errors, rewrite the Demo.

Generate the data.xml content as follows:

The first step of the attack chain is completed, but the fly in the ointment is because the author’s new TestClass class in the test environment has a loophole, but in the production situation is very complicated, you need to find a vulnerable attack point in the Web program, in order to make the attack cost Reducing definitely calls the system class to achieve command execution, so you need to introduce the following knowledge.

3.2, ResourceDictionary

ResourceDictionaries, also known as resource dictionaries, are commonly found in WPF or UWP applications to share static resources across multiple assemblies. Since it is a WPF program, it must be designed to the front-end UI design language XAML. XAML full name Extensible Application Markup Language (extensible application markup language) XML-based, and XAML is a tree structure as a whole, if you understand the XML, you can quickly grasp, for example, see the following Demo

The first tag ResourceDictionary, xmlns:Runtime means to read the name of the System.Diagnostics command space from the individual name Runtime
The second tag ObjectDataProvider specifies three properties, x:key for conditional retrieval, meaningless but must be defined; ObjectType is used to get or set the type of the object whose instance is to be created, and uses XAML extensions; x:Type Equivalent to C# typeof operator function, the value passed here is System.Diagnostics.Process; MethodName is used to get or set the name of the method to be called, the value passed is System.Diagnostics.Process.Start method is used to start a process .
The third tag, ObjectDataProvider.MethodParameters, embeds two method parameter tags. The System:String specifies the startup file and the parameters to be used at startup to be used by the Start method.
After introducing the ResourceDictionary in the attack chain, the Payload body of the attack has been completed, and then the XML parser provided by the XamlReader system class is used to implement the attack.

3.3, XamlReader

XamlReader is located in the System.Windows.Markup space, as the name suggests is used to read the XAML file, it is the default XAML reader, read XAML data in the Stream stream through Load, and return as the root object, and another Parse method Reading the XAML input in the specified string is also returned as the root object. The natural Parse method is what we care about and seek.

Simply instantiate the XamlReader using the ObjectInstance method of the ObjectDataProvider, then specify the MethodName as Parse, and pass the serialized resource dictionary data to the MethodParameters, thus completing the XmlSerializer deserialization attack chain.

0x04 code audit perspective

From the perspective of code auditing, it is easy to find the pollution point of the vulnerability. Through the knowledge of the previous sections, it can be found that serialization needs to meet a key condition Type.GetType. The program must pass the static method GetType of the Type class, for example, the following demo

First create the XmlDocument object to load the xml, the variable typeName gets the value of the type attribute of the Item node through XPath, and passes it to Type.GetType, then reads all the Xml data in the Item node, and finally hands it off to the Deserialize method. This is a near-perfect point of use. Let’s look at the XmlSerializer deserialization class that I collected on github: XmlSerializeUtil.cs

Here the value parameter type is Type, the code itself is no problem, the problem is that the program developer may first define a string variable to accept the passed type value, return the Type object through Type.GetType(string) and pass it into DeserializeXml, in the code. The source of the type here should also be considered in the audit process.

0x05 Case resumption

Finally, through the following case to re-set the whole process, the whole process is demonstrated in the VS debugging through the deserialization vulnerability pop-up calculator.

  • Enter http://localhost:5651/Default?node=root&value=type to load the remote ( 1.xml file
  • Get all the XML data under the root node via xmlHelper.GetValue
  • The most critical step is to get the type attribute of the root node and provide it to the GetType method. The XmlSerializer object is instantiated successfully.
  • XmlSerializer.Deserialize(xmlReader) successfully calls the calculator
  • Finally attached the animation.

0x06 summary

Since XmlSerializer is the system’s default anti-sequence class, the usage rate is still relatively high in actual development. When an attacker finds that the pollution point is controllable, he can find the point of utilization from two dimensions. The first from the Web application. Seeking classes and methods that can execute commands or write WebShell; the second is the attack chain consisting of ObjectDataProvider, ResourceDictionary, and XamlReader to execute commands or bounce shells.

Leave a Reply