IVANTIAVALANCHE是美国Ivanti公司的一套企业移动设备管理系统。该系统主要用于管理智能手机、平板电脑等设备。2021年该系统就出现过,权限许可和访问控制问题漏洞,该漏洞存在于读取存储的头像图片位置,未进行限制格式与目录,造成了任意文件读取。
经综合分析,IvantiAvalancheWeb应用程序中会出现三个漏洞链:
ZDI-21-1298(CVE-2021-42124):会话接管漏洞,需要用户交互。
ZDI-21-1300(CVE-2021-42126):权限提升漏洞,允许攻击者获得管理权限。
ZDI-21-1299(CVE-2021-42125):远程代码执行漏洞,可以从管理员帐户级别利用。
后来,研究人员发现了一些关于IvantiAvalanche的有趣事实:
· 它的目录中包含多个XStream1.4.12jar包。
· 它实现了多个ObjectGraph类,这些类封装了XStream序列化程序。
其中一些类定义了允许反序列化的类的允许列表,而其他类则缺少这样的允许列表。
这让研究人员怀疑产品中存在多个不受信任的反序列化漏洞。但是,我还不能确定如何访问那些反序列化例程。经过进一步研究,研究人员发现了更多零日漏洞。
首先,让我们看一下Avalanche服务:
IvantiAvalanche服务
我们发现我们正在处理TomcatWeb应用程序以及其他服务,“Wavelink信息路由器”似乎是其中最有趣的。
在这个阶段,一切似乎都很复杂。正因为如此,我使用了以下方法来获得更多的分析:
· 网络流量分析;
· 静态分析;
· 日志文件分析;
不一会儿,我们就会看到AvalancheWeb应用程序似乎无法自行执行任务,甚至无法进行登录操作。但是,它可以自由地使用不同的服务来执行任务。信息路由器,也称为InfoRail服务,位于两者之间,负责服务之间的消息传播。InfoRail服务默认侦听TCP端口0.0.0.0:7225。
服务间通信
从上图可以看出,通信流很简单。Web后端创建一条消息并将其发送给informail服务,后者将其转发到适当的目标服务。目标服务处理消息并将响应返回给Web后端,同样是通过informail服务。在默认安装中,所有这些服务都运行在同一台主机上。但是,可以将其中一些服务放置在远程计算机上。
另一方面,要获得有关消息的更详细信息并不容易。网络流量分析没有多大用处,因为消息似乎被混淆或加密了。为了更多地了解它们,我不得不进行详细的代码分析。
以下部分概述了InfoRail协议以及所需的所有基础知识:
· 重新创建协议和消息。
· 了解其基础知识。
· 了解有效载荷传递机制。
I· nfoRail协议基础知识
一个典型的informail消息包含三个主要部分:
· 序言;
· 标头;
· 可选的XML有效负载;
下图展示了一个消息结构:
消息结构
序言的长度总是24字节。它由以下部分组成:
· 字节1-4:整个消息的长度。
· 字节5-8:标头的长度。
· 字节9-12:有效负载的长度。
· 字节13-16:未压缩有效载荷的长度(可以选择压缩有效载荷)。
· 字节17-20:消息ID(通常是从1开始递增的数字)。
· 字节21:协议版本(通常为0x10)。
· 字节22-23:保留•字节24:加密标志(有效载荷和报头可以选择加密)-0或1。
典型的消息头由多个键及其对应的值组成。这些键和值以以下方式包含在标头中:
· 3个空字节。
· 0x02字节。
· 3个空字节。
· 1个字节,提供密钥的长度(例如0x08)。
· 3个空字节。
· 1个字节,提供值的长度(例如0x06)。
· 键+值。
下面是一个key和value的例子:
\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\x06h.msgcat999999
如前所述,标头可以包含多个键。大多数或所有消息中出现的最重要的是:
· h.msgcat——在典型请求中,它等于10(请求)。
· h.msgsubcat——有关请求类型的信息,因此它对于有效负载处理至关重要。
· h.msgtag——通常存储JSESSIONID cookie,尽管没有发现验证此cookie的方法,因此该值可以是随机的。
· h.distlist——指定InfoRail将消息转发到的一个或多个服务;
由于可以应用可选的加密,标头必须用空字节填充到16字节的倍数。
如前所述,大多数消息都包含XML有效负载。XStream序列化器用于有效负载序列化和反序列化操作。
根据目标服务和消息子类别,可以传输不同的序列化对象。但是,在大多数情况下,我们处理的是RequestPayload对象。以下代码段提供了在身份验证操作期间发送的XML示例。在本例中,AvalancheWeb后端将此XML发送到EnterpriseServer服务,然后验证用户凭据。
RequestPayload.xml
如你所见,此消息包含一个序列化的UserCredentials对象,该对象由loginName、加密密码、域和clientIpAddress组成。你还可以看到RequestPayload包含Webcookie(sessionId)。但是,此cookie从未经过验证,因此可以将其设置为任何MD5哈希值。由于可以选择对有效负载进行加密和压缩,因此必须将其填充为16字节的倍数。
通常,每个服务都实现自己的ObjectGraph类,该类定义并配置XStream序列化程序的实例。下面是一个示例实现的片段:
ObjectGraphPart.java
当服务接收到XML有效负载时,它会使用ObjectGraph.fromXML方法对其进行反序列化。
加密
正如前面提到的,可以对消息的标头和有效负载进行加密。此外,有效载荷可以被压缩。inforeail不使用SSL/TLS加密协议。相反,它使用硬编码的加密密钥手动应用加密算法。
由于加密算法和加密密钥都可以从源代码中提取,所以潜在的攻击者可以毫无障碍地同时进行解密和加密操作。
InfoRail服务需要知道将收到的消息转发到哪里。此信息存储在消息标头的h.distlist键中。可以使用的值存储在IrConstants类中。以IR_TOPIC开头的变量定义了可以转发消息的服务。以下代码片段显示了几个硬编码变量:
DistributionVariables.java
如果发件人希望将消息转发到许可证服务器,则h.distlist值必须设置为255.3.2.8。
这可能是协议描述中最重要的部分。如前所述,消息类别包含在h.msgsubcat键下的消息标头中。如下面代码片段的最后一行所示,服务保护自己免受未知消息的处理,如果提供的消息子类别未实现,则删除该消息。
根据服务的不同,消息处理的实现方式可能略有不同。在这里,我们将简要介绍一下Avalanche通知服务器。以下代码片段表示MessageDispatcher类中的processMessage方法:
processMessage.java
在[1]处,从标头中检索消息子类别。然后,它被传递给MessageProcessorVector.getProcessor方法以获取对适当消息处理程序的引用。
在[2]处,switch-case语句开始。
如果类别等于10(请求),则在[3]处调用processInfoRailRequest方法。它的参数包含在步骤[1]中检索到的处理程序。我们可以在这里快速浏览一下这个方法:
processInfoRailRequest.java
基本上,如果处理程序不为空,代码将调用handler.ProcessMessage方法。
最后,我们必须研究如何检索处理程序。最重要的部分如下:
MessageProcessorVector.java
在[1]处,定义了HashMap
在[2]和后续行中,代码调用setProcessor方法。它接受消息子类别整数和实现IMessageProcessor的相应对象,例如AnsCredentialsHandler。
在[3]处,定义了setProcessor方法。它将子类别和适当的对象插入到[1]中定义的HashMap中。
在[4]处,getProcessor根据提供的子类别检索处理程序。
总而言之,有一个HashMap存储消息子类别及其对应的处理程序对象。如果我们向AvalancheNotificationServer发送子类型等于3706的消息,则会调用AnsTestHandler.processMessage方法。
让我们看一个消息处理程序的示例,AnsTestHandler:。
AnsTestHandler.java
在[1]处,定义了SUBCATEGORY变量。消息处理器定义这样一个变量是很常见的。
在[2]处,定义了processMessage方法。
在[3]处,它从消息中检索XML有效负载。
在[4]中,它使用ObjectGraph.fromXML方法反序列化有效负载。然后它将它转换为AnsTestPayload,尽管转换发生在反序列化之后。据此,如果ObjectGraph没有实现任何额外的保护(例如白名单),我们应该可以在这里实现攻击。
成功!我们已经确定了消息处理例程。此外,我们能够快速将子类别映射到将处理我们的消息的相应代码片段。现在看来,我们应该能够创建自己的信息。
参考及来源:https://www.zerodayinitiative.com/blog/2022/7/19/riding-the-inforail-to-exploit-ivanti-avalanche