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

VSole2022-07-05 06:17:35

概述

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

使用 `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 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` :

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

小结

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

漏洞序列化
本作品采用《CC 协议》,转载必须注明作者和本文链接
最近两个月我一直在做拒绝服务漏洞相关的时间,并收获了Spring和Weblogic的两个CVE但DoS漏洞终归是鸡肋洞,并没有太大的意义,比如之前有人说我只会水垃圾洞而已,所以在以后可能打算做其他方向早上和pyn3rd师傅聊天
浅谈Java反序列化漏洞
2022-05-17 17:48:01
Java序列化与反序列化Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。
序列化漏洞汇总
2022-01-07 22:17:34
漏洞出现在WLS Security组件,允许远程攻击者执行任意命令。攻击者通过向TCP端口7001发送T3协议流量,其中包含精心构造的序列化Java对象利用此漏洞。然后将其序列化,提交给未做安全检测的Java应用。Java应用在进行反序列化操作时,则会触发TransformedMap的变换函数,执行预设的命令。
序列化的核心思维旨在,将A变成B,最后再从B还原回A。 总之,在一些条件苛刻或者变化无常的环境与需求中,产生了这种灵活的可逆性的B的中间体。 理解不安全反序列化的最好方法是了解不同的编程语言如何实现序列化和反序列化。这里的序列化与反序列化指的是程序语言中自带的实施与实现。而非自创或者自定义的序列化与反序列化机制(比如:N进制形式hashmap树型等其他数据结构里的序列化中间体)。
漏洞影响版本 Jboss 漏洞搭建 在阿里云端,用docker 搭建测试环境jboos使用的漏洞库是 vulhub ,进入漏洞库选择jboos里面有三个选项选择第一个cve.输入 docker-compose up -d 启动 本地测试,在浏览器输入访问 /invoker/readonly,若显示HTTP Status 500,则说有反序列化漏洞。使用工具测试验证漏洞是否存在,工具下载地址: ... 执行whoami命令
前置知识分析Transformer接口及其实现类。transform()传入对象,进行反射调用。构造调用链调用链构造原则:找调用关系要找不同名的方法,如果找到同名,再通过find usages得到的还是一样的结果。找到InvokerTransformer类中的transform(),右键,点 Find Usages,找函数调用关系,最好找不同名的方法,调用了transform()。因为transform()调用transform()不能换到别的方法里,没有意义。如果有一个类的readObject()调用了get(),那我们就可能找到了调用链。最终选择TransformedMap这个类,因为TransformedMap类中有好几处都调用了transform()。
使用 SerializationBinder 无法完全修复反序列化漏洞隐患。经过深入研究总结了两种不安全 SerializationBinder 限定的绕过方式,下面分享给大家。
近日Oracle通报了一个反序列化漏洞CVE-2022-21445,未经身份认证的远程攻击者可利用该漏洞实现反序列化操作导致任意代码执行。任何基于ADF Faces框架开发的程序都受到此漏洞的影响,包括Oracle的多个产品。
Fastjson Develop Team发布安全公告,修复了一个存在于Fastjson1.2.80 及之前版本中的反序列化漏洞漏洞编号:暂无,漏洞威胁等级:高危。
JDK7u21的核心点是我们在cc1中也出现过的AnnotationInvocationHandler,在cc1中我们用到了他会触发this.memberValues.get(var4);这个点,而在JDK7u21中利用到了他里面的equalsImpl。先来看一下equalsImpl。
VSole
网络安全专家