在SOLARWINDS平台中查找反序列化错误
2023-10-31 11:35:0 Author: www.4hou.com(查看原文) 阅读量:13 收藏

我们会在本文中详细介绍四个在去年被修复的旧漏洞:

CVE-2022-38108;

CVE-2022-36957;

CVE-2022-36958;

CVE-2022-36964;

CVE-2022-38108

这个漏洞已经在这篇博客文章中提到了。

简单来说,几个SolarWinds服务通过RabbitMQ实例相互通信,该实例可通过端口5671/TCP访问。虽然访问它需要凭据,但是高权限用户可以通过SolarWinds Orion平台提取这些凭据,攻击者利用CVE-2023-33225,它允许低权限用户提取这些凭证。

该漏洞针对的是SolarWinds信息服务。为了向信息服务发送AMQP消息,必须将消息的Routing-Key设置为SwisPubSub, Routing Key就是路由规则,消息对应的队列。

1.png

AMQP消息中的Routing-Key

现在,让我们来验证SolarWinds是如何处理这些消息的,可以从EasyNetQ.Consumer.HandleBasicDeliver方法开始:

在[1]处,代码检索AMQP消息的属性,这些属性由发送消息的攻击者控制。

在[2]处,它创建了一个执行上下文,其中包含AMQP消息属性和消息正文。

在[3]处,它执行一个任务来使用消息。

这就需要Consume方法。

在[1]处,EasyNetQ.DefaultMessageSerializationStrategy.DeserializeMessage被调用,它接受输入的消息属性和消息正文。调用名为DeSerialize的方法并返回type类型的输出,作为输入,它从消息中接受Type属性。

我们可以通过AMQP消息属性控制messageType类型!

在[2]处,它调用BytesToMessage,同时接受攻击者控制的类型和输入的消息正文。

在[1]处,消息正文被解码为UTF-8字符串。它应该包含JSON格式的数据。在[2]处,执行反序列化。我们控制目标类型和序列化负载。在[3]处,可以看到TypeNameHandling反序列化设置被设置为Auto。

现在,我们需要远超需要实现的远程代码。要做到这一点,我们必须发送一个AMQP消息,其中Type属性设置为危险类型。

2.png

通过AMQP属性控制反序列化类型

在消息正文中,我们必须传播相应的JSON.NET gadget(有潜在可以被利用的代码片段)。本文使用了ysosserial.net中的一个简单的WindowsPrincipal gadget,它是内部存储的BinaryFormatter gadget的桥梁,JSON反序列化后,RCE将通过底层BinaryFormatter反序列化来实现。

这样,就可以通过远程执行恶意代码来控制目标系统的漏洞!

CVE-2022-36957

在之前的漏洞中,我们能够通过AMQP属性完全控制目标反序列化类型。当发现这样的漏洞时,我们需要知道合法消息是什么样子?我们经常检查在典型产品操作过程中反序列化的类型。

我们很快意识到SolarWinds只发送一种类型的信息,即SolarWinds.MessageBus.Models.Indication。

现在我们分析一下这种类型:在[1]和[2]处,我们可以看到两个类型为SolarWinds.MessageBus.Models.PropertyBag的公共成员。

在[1]处,您可以看到所讨论的类的定义,SolarWinds.MessageBus.Models.PropertyBag。

在[2]处,为该类注册了一个自定义转换器SolarWinds.MessageBus.Models.PropertyBagJsonConverter。它实现了ReadJson方法,该方法将在反序列化过程中调用。

在[1]处,代码遍历JSON属性;在[2]处,检索JSON值并将其转换为jobobject类型;在[3]处,根据存储在t键中的值检索Type;在[4]处,存储在v键中的对象被反序列化,此时我们再次控制目标反序列化类型。

你可以看到,我们再次控制了反序列化类型,该类型通过JSON键传播,序列化的有效负载通过v键传播。

现在,我们可以获取任何属性,例如:IndicationId。然后,我们需要:

1.将t键的值设置为恶意类型的名称。

2.在v键的值中放入恶意序列化的有效负载。

由于JSON反序列化设置被设置为TypeNameHandling.Auto。现在,让我们看一下上面描述的第一个漏洞,CVE-2022-38108,通过将目标反序列化类型硬编码到SolarWinds.MessageBus.Models.Indication来修复。毕竟,这是唯一需要反序列化的合法类型。

这个修正是不够的,因为SolarWinds.MessageBus.Models.Indication可以用来传播一个攻击者控制类型的内部对象。通过控制类型,我们就可以通过远程执行恶意代码来控制目标系统的漏洞!

CVE-2022-36958

SolarWinds定义了一些称为“SWIS动词”的内部方法/操作。这些动词可以是:

1.通过API直接调用。

2.通过Orion平台Web UI间接调用(Orion平台内部调用动词)。

关于SWIS动词,我们需要了解以下2点:

1.它们是使用XML结构中的有效负载调用的。

2.它们接受预定义类型的参数。

例如,Orion.AgentManagement.Agent.Deploy动词接受12个参数。下面的屏幕截图显示了这些参数及其相应的类型。

33.png

Orion.AgentManagement.Agent.Deploy的参数

参数的处理是通过方法SolarWinds.InformationService.Verb. VerbExecutorContext.UnpackageParameters(XmlElement[], Stream)执行的。

在[1]处,检索给定动词参数的Type;在[2]处,使用检索到的参数类型初始化DataContractSerializer;在[3]和[4]处,参数被反序列化。

这是正在处理一个DataContractSerializer。不过,这样我们无法控制反序列化类型。

目前已找到了一些可滥用的PropertyBag类,通过进一步分析,有多个SWIS动词接受名为SolarWinds.InformationService.Addons.PropertyBag类型的参数。我们可以提供任意XML,将其反序列化为这种类型的对象。

在[1]处,定义了ReadXml方法,它将在反序列化期间被调用;在[2]处,代码遍历所提供的项;在[3]处,检索到关键元素。如果存在,则继续执行代码;在[4]处,检索type元素的值。人们可以放心地猜测它接下来如何执行;在[5]处,检索到value元素;在[6]处,调用Deserialize方法,输入值和类型标记中包含的数据;在[7]处,序列化的有效负载和类型名称被传播给SolarWinds.InformationService.Serialization.SerializationHelper.Deserialize方法。

同样,类型和序列化的有效负载都由攻击者控制。让我们检查一下这个反序列化方法。在[1]处,代码检查所提供的类型是否被缓存。如果不是,则从[2]处的字符串中检索类型。在[3]处,调用静态的DeserializeFromStrippedXml。静态的DeserializeFromStrippedXml方法通过调用SerializationHelper.serializerCache.GetSerializer(type)来检索序列化器对象。然后,它在检索到的序列化器对象上调用(非静态)DeserializeFromStrippedXml(string)方法。

如何检索序列化器

在[1]处,代码尝试从缓存中检索序列化器。在缓存缺失的情况下,它通过调用GetSerializerInternal([2])来检索序列化器,因此我们继续使用GetSerializerInternal进行调查。

在[3]处,根据攻击者控制的类型检索XmlTypeMapping。它没有执行任何安全措施。它仅用于检索关于给定类型的一些基本信息。

在[4]处,初始化XmlStrippedSerializer对象。为构造函数提供了四个参数:

1.一个新的XmlSerializer实例,其中序列化器的类型由攻击者控制。

2.目标类型的XsdElementName,从XmlTypeMapping获得。

3.该类型的Namespace,也是从XmlTypeMapping获得的。

4.类型本身。

到目前为止,我们有可以发现:

1.我们正在切换反序列化器。使用DataContractSerializer对整个SWIS动词有效负载和参数进行反序列化。但是,PropertyBag对象最终将使用XmlSerializer进行反序列化。

2.我们完全控制提供给XmlSerializer构造函数的类型,这是利用它的关键条件。

似乎我们有它,通过反序列化中的类型控制的另一个RCE。由于XmlSerializer可能会通过ObjectDataProvider被滥用,我们可以将目标反序列化类型设置为以下类型:

3.png

但是,在成功利用漏洞之前,还有必要分析XmlStrippedSerializer.DeserializeFromStrippedXml(String) 。

可以发现,在[1]处,正在创建一个新的XML字符串。它的结构如下:

4.png

综上所述:

1.攻击者的XML被一个从传播的类型派生的标记封装,请参阅GetSerializerInternal方法。

2.检索到的Namespace被插入到xmlns属性中。攻击者控制最终XML的主要片段并控制类型。然而,由于自定义的XML封装,ysosserial.netgadget将无法开箱即用。

生成的gadget如下所示:

第一个标记等于ExpandedWrapperOfLosFormatterObjectDataProvider。此标记将由DeserializeFromStripedXml方法自动生成,因此我们需要将其从生成的有效负载中删除!当我们这样做时,下面的XML将被传播给 XmlSerializer.Deserialize方法。

当你比较原始的ysosserial.net gadget和我们当前的gadget时,可以发现一个很大的区别:

1.原始gadget在根标记中定义了两个名称空间:xsi和xsd。

2.当前gadget仅包含一个空xmlns属性。

ObjectInstance标记依赖于xsi命名空间。因此,反序列化将失败。

幸运的是,不必在根标签(root tag)中专门定义命名空间,RootTag 是用于标记 React Native 原生根视图层的不透明标识符(opaque identifier)。因此,我们可以通过在ProjectedProperty0标记中定义这两个名称空间来修复gadget。

通过这种方式,我们得到了第三个RCE,这样,我们就完全控制了目标反序列化类型。

CVE-2022-36964

技术层面,该漏洞与CVE-2022-36958相同,但是,它存在于共享ReadXml方法的相同实现的不同类中。在本例中,易受攻击的类是SolarWinds.InformationService.Contract2.PropertyBag。

TestAlertingAction SWIS动词接受此类型的参数,因此该漏洞可通过API加以利用。

总结

我们在本文介绍了SolarWinds中的四个不同的反序列化漏洞,攻击者可以使用这些漏洞控制反序列化对象的类型,以及介绍了如何通过使用自定义反序列化gadget绕过它们。目前,SolarWinds也对这些绕过进行了修复。

文章翻译自:https://www.zerodayinitiative.com/blog/2023/9/21/finding-deserialization-bugs-in-the-solarwind-platform如若转载,请注明原文地址


文章来源: https://www.4hou.com/posts/EXpk
如有侵权请联系:admin#unsafe.sh