.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定

渗透技巧 2年前 (2022) admin
835 0 0

★且听安全-点关注,不迷路!



.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定

★漏洞空间站-优质漏洞资源和小伙伴聚集地!


概述


很多 .NET 应用程序在修复 `BinaryFormatter` 、 `SoapFormatter` 、`LosFormatter` 、 `NetDataContractSerializer` 、`ObjectStateFormatter ` 等反序列化漏洞时,喜欢通过自定义 `SerializationBinder` 来限定类型,从而达到缓解反序列化攻击的目的。历史上很多 .NET 反序列化漏洞都采用了这种方法,但是我们查看微软官方的警告说明:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


使用 `SerializationBinder` 无法完全修复反序列化漏洞隐患。最近看到老外发了一篇相关文章,感觉很有价值,自己也深入研究总结了两种不安全的 `SerializationBinder` 限定方式,下面分享给大家。


SerializationBinder 绑定限制


常见修复方式就是对 `BinaryFormatter` 反序列化过程绑定 `Binder` 对象,通过 `SerializationBinder` 来检查反序列化类型。构建如下 `demo`。


反序列化操作如下:


using (var fileStream = new FileStream(file, FileMode.Open)){    BinaryFormatter formatter = new BinaryFormatter();    fileStream.Position = 0;    formatter.Binder=new SafeDeserializationBinder();    formatter.Deserialize(fileStream);}


自定义 `SafeDeserializationBinder` 继承于 `SerializationBinder` ,通过黑名单机制进行检查,当发现存在恶意类型时,比如 `System.Data.DataSet` ,将阻断反序列化过程:


public class SafeDeserializationBinder : SerializationBinder{    List<String> blackTypeName = new List<string> { };
private void _AddBlackList() { blackTypeName.Add("System.Data.DataSet"); }
public override Type BindToType(string assemblyName, string typeName) { this._AddBlackList(); foreach (var t in blackTypeName) { if (typeName.Equals(t)) { //todo } } return Type.GetType(typeName); }}


Bypass 1 :无效的 null 返回值


大家很容易想到,当检测到反序列化黑名单,直接返回 `null` :


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


这样真的可以阻断反序列化漏洞吗?我们可以进行测试。利用 `YSoSerial.Net` 特定生成 `System.Data.DataSet` 的反序列化载荷:


ysoserial.exe -o raw -f BinaryFormatter -g DataSet -c calc >payload.txt


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


确实返回了 `null` ,但是发现最终还是执行了反序列化操作并触发了 RCE:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


为什么呢?下面调试分析一下原因。`BinaryFormatter` 反序列化时将调用 `ObjectReader#Bind` 来获取 `Type` 类型:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


首先调用自定义的 `SafeDeserializationBinder#BindToType` ,当返回 `null` 时,函数并没有直接结束,而是继续调用 `FastBindToType` 来获取 `Type` 对象:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


首先尝试从 `typecache` 缓存中提取,程序首次调用获取不到值,继续判断 `bSimpleAssembly` 的取值(默认始终为 `true`),进而尝试调用 `GetSimplyNamedTypeFromAssembly` :


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


通过 `FormatterServices#GetTypeFromAssembly` 最终取到了 `type` 的值:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


所以尝试在 `SerializationBinder` 加载恶意 `Type` 时通过返回 `null` 是无法阻断反序列化漏洞的。比如 Exchange CVE-2022-23277 就是由于在遇到黑名单时最终返回 `null` 从而导致被绕过。要想 `SerializationBinder` 有效,正确的做法是抛出异常,修改 `demo` 如下:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


抛出异常将中断后续处理流程,导致反序列化绑定的 `Type` 最终确定为 `null` ,从而无法触发反序列化漏洞。


Bypass 2 :抛出异常真的安全吗?


上面通过抛出异常的方式真的能够完全修复漏洞吗?答案是否定的。我们思考下既然反序列化操作可以通过 `BindToType` 检查 `Type` 和 `Assembly` ,那么在生成序列化载荷时,就可能可以自定义 `Type` 和 `Assembly` ,查看  `YSoSerial.Net` 生成 `System.Data.DataSet` 的反序列化载荷的代码段 ( `/Generators/DataSetGenerator.cs` ):


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


我们可以手动去修改 `Type` 的赋值过程,确保让其不位于黑名单之中,比如:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


重新编译生成 `YSoSerial.Net` ,并再次生成新的 `DataSet` 反序列化载荷:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


此时 `typeName` 并不在黑名单之中,所以不会抛出异常,但是却成功返回了正确的 `Type` 类型,从而绕过检查进而实现了 RCE :


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定


比如 DevExpress CVE-2022-28684 反序列化漏洞就是通过类似上面这种方式实现 Bypass 的。


小结


通过 `SerializationBinder` 绑定 `Type` 类型来缓解反序列化漏洞,无论是直接返回 `null` 还是抛出异常,都存在被绕过的风险,最好的修复方式其实微软官方已经给出了答案,那就是不要使用 `BinaryFormatter` 这类反序列化类:


.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定



由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用本人负责,且听安全团队及文章作者不为此承担任何责任。



★且听安全-点关注,不迷路!

.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定



★漏洞空间站-优质漏洞资源和小伙伴聚集地!

.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定

原文始发于微信公众号(且听安全):.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定

版权声明:admin 发表于 2022年7月5日 上午8:11。
转载请注明:.NET反序列化漏洞之绕过 SerializationBinder 不安全的类型绑定 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...