https://y4er.com/posts/dotnet-deserialize-bypass-binder/#cve-2022-23277-of-exchange (Binder原理)

https://exp10it.io/2024/02/dotnet-serializationbinder-%E7%BB%95%E8%BF%87/ (Binder原理加绕过方法)

这两篇文章写的很好了 我就写一点点就行了

SerializationBinder

我就来跟一下这个SerializationBinder吧 写一下流程 说明一下Binder使用不当造成绕过

Binder和java中的那个resovleclass过滤黑名单差不多

.Net中是使用Binder来进行过滤的

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
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Serialize
{
internal class Program
{
static void Main(string[] args)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream();
RCE calc = new RCE("calc");
binaryFormatter.Serialize(memoryStream, calc);


memoryStream.Position = 0;
binaryFormatter.Binder = new MyBinder();
object v = binaryFormatter.Deserialize(memoryStream);
Console.WriteLine(v);
Console.ReadKey();
}
}

[Serializable]
class RCE
{
public string cmd;

public RCE(string cmd)
{
this.cmd = cmd;
}

public override string ToString()
{
return $"exec cmd:{cmd}";
}
}
class MyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Console.WriteLine($"assemblyName:{assemblyName},typeName:{typeName}.");
Type typeToDeserialize = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));

if (typeToDeserialize.Equals(typeof(RCE)))
{
//throw new Exception("can't deseriliza rce class.");
Console.WriteLine("can't deseriliza rce class.");
return null;
}
return typeToDeserialize;
}
}
}

image-20240414170206206

自己定义一个可以进行反序列化的类

image-20240414170242423

自己写个Binder来进行定义 如果匹配到RCE这个类就禁止进行反序列化操作

(简单点说 如果能让BindToType这个类返回我们序列化的类的话 就能进行反序列化操作)

image-20240414170345077

序列化和反序列化操作

image-20240414170632975

这里就是有个奇怪的点了 就是我们明明在BindToType这个的函数的时候 匹配到了RCE这个类 return null了 为什么还能进行反序列化操作 我们给BindToType这个函数下个断点来进行分析

分析

image-20240414171101772

因为这里呢 在刚开始的时候 匹配到了我们的RCE类 然后return null了 那么type的值就是null了 所以进行到下面的if判断中 进入到FastBindToType中

image-20240414171406086

先根据TypeName中缓存中获取assemblyName 这里是没获取到 接着往下看

image-20240414171630245

image-20240414171614670

这里的bSimple默认值为true

image-20240414171740943

最后通过这里拿到了我们的assemblyName了 第一个从缓存中没拿到 然后第二次在这拿到了

image-20240414171953627

最后呢 在断点处拿到了这个type值 然后赋值给typeNassembly.type 最后return返回 那么我们的BindToType函数还是回去到我们最终想要回去到Type值 所以就能反序列化成功 这样的话就没有受限于这个Binder的限制

修复方法就是在匹配的时候直接抛出异常 不返回null

修复

image-20240414172245670

这样子的话就能成功过滤黑名单 不会被绕过

其他绕过方法的话就看xz写的那个文章了 这里就不写了

https://exp10it.io/2024/02/dotnet-serializationbinder-%E7%BB%95%E8%BF%87/