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))) { Console.WriteLine("can't deseriliza rce class."); return null; } return typeToDeserialize; } } }
|
自己定义一个可以进行反序列化的类
自己写个Binder来进行定义 如果匹配到RCE这个类就禁止进行反序列化操作
(简单点说 如果能让BindToType
这个类返回我们序列化的类的话 就能进行反序列化操作)
序列化和反序列化操作
这里就是有个奇怪的点了 就是我们明明在BindToType这个的函数的时候 匹配到了RCE这个类 return null了 为什么还能进行反序列化操作 我们给BindToType这个函数下个断点来进行分析
分析
因为这里呢 在刚开始的时候 匹配到了我们的RCE类 然后return null了 那么type的值就是null了 所以进行到下面的if判断中 进入到FastBindToType中
先根据TypeName中缓存中获取assemblyName 这里是没获取到 接着往下看
这里的bSimple默认值为true
最后通过这里拿到了我们的assemblyName了 第一个从缓存中没拿到 然后第二次在这拿到了
最后呢 在断点处拿到了这个type值 然后赋值给typeNassembly.type 最后return返回 那么我们的BindToType函数还是回去到我们最终想要回去到Type值 所以就能反序列化成功 这样的话就没有受限于这个Binder的限制
修复方法就是在匹配的时候直接抛出异常 不返回null
修复
这样子的话就能成功过滤黑名单 不会被绕过
其他绕过方法的话就看xz写的那个文章了 这里就不写了
https://exp10it.io/2024/02/dotnet-serializationbinder-%E7%BB%95%E8%BF%87/