该漏洞主要是由于开发者使用SerializationBinder后的逻辑判断有问题,同时配合exchange不那么严格的反序列化黑名单,造成了认证后的RCE。
大约是21年下半年更新的exchange2016及2019。
了解SerializationBinder:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace deserialDemo
{
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.");
throw new Exception("error");
}
return typeToDeserialize;
}
}
}
在MyBinder 里实现具体逻辑,判断即将要被反序列化的类的Type-typeToDeserialize是否等于typeof(RCE)。
在反序列化之前,设置binaryFormatter.Binder = new MyBinder();
尝试反序列化,被阻止,弹出异常:
C:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.Compliance.dll中的Microsoft.Exchange.Compliance.Serialization.Formatters.TypedBinaryFormatter的DeserializeObject方法:
传入SerializationBinder实例但没有被使用
通过CreateBinaryFormatter生成BinaryFormatter对象:
其中初始化的时候指定了Binder,为ChainedSerializationBinder函数的结果:
此时传入的参数为:
strictMode = false
allowList = "System.DelegateSerializationHolder"
allowedGenerics = null
ChainedSerializationBinder重写了父类SerializationBinder的BindToType和BindToName方法
进入ValidateTypeToDeserialize函数
!this.strictMode=true 此时默认情况为真。
this.allowedTypesForDeserialization.Contains(text) 此时allowedTypesForDeserialization是我们传入的"System.DelegateSerializationHolder",text为即将被反序列化的类的类名。
ChainedSerializationBinder.GlobalDisallowedTypesForDeserialization为反序列化的黑名单:
此时flag=this.strictMode为false:
此时抛出的BlockedDeserializationException 异常会被捕获,因为flag=false,整个ChainedSerializationBinder不会抛出异常。因此可以造成不在黑名单中的任意类的反序列化。如果进入InvalidOperationException就会直接进入异常,不会进入反序列化的逻辑。
寻找使用DeserializeObject函数的地方:
ClientExtensionCollectionFormatter没找到相关的调用,查看继承的接口在哪里实现:
发现TryDeserialize方法:
发现来自UserConfiguration,在exchange2010的反序列化漏洞中通过ews设置账户属性进行触发。这里我们只要找到一个属性可以设置为binary的地方就可能触发。
Microsoft.Exchange.Data.Storage.UserConfiguration:
可以看到UserConfiguration的类型有xml形式:
接下来就是怎么通过ews设置用户设置,主要是如何传递二进制的问题,网上已经有人审计的ews找到了解决办法,在我们前面的文章也提及过如何找到xml对应的类:
设置完反序列化之后需要触发:
通过获取用户ExtesionDataList触发,通过ews调用此接口:
至此我们获得了完整的利用链。
TypeConfusedDelegate、ClaimsPrincipal及ActivitySurrogateSelector ,这三个链没有在这个版本exchange的黑名单中。ActivitySurrogateSelector 可以直接执行dll文件,但在exchange上会报错。
关于反序列化链的研究以后的文章再详细分析。
实际在利用的过程中遇到的500错误,之前朋友在利用的时候遇到过,应该是w3wp进程启动进程被Definder拦截了。这样的话只要修改ysoserial的代码功能为写文件即可利用。
关于如何绕过definder阻止启动新进程的方式,以后会有相关的文章专题。
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -o base64 -c "1" -t
成功生成文件
前面修改了以下poc xml中的ExtensionMasterTable就发现漏洞不能顺利触发,能创建配置但调用会失败。
在最终利用的地方Microsoft.Exchange.Data.ApplicationLogic.Extension.OrgExtensionSerializer的TryDeserialize函数中,要被反序列化的实例userConfiguration的configName为ExtensionMasterTable:
反序列化触发已经限制死了配置名为ExtensionMasterTable的配置。
KB5007409得到修复,最终反序列化的地方:
此处this.formatter为IClientExtesionCollectionFormatter的实现,仅剩Microsoft.Exchange.Data.ApplicationLogic.Extension.ClientExtensionCollectionFormatter.Deserialize(Stream) : Collection
https://github.com/DarkSprings/CVE-2021-42321 https://github.com/7BitsTeam/exch\_CVE-2021-42321
参考: