此时,我似乎拥有了发送我自己的信息所需的一切。但是,当我发送时,我看到目标服务没有任何反应。我查看了InfoRail服务日志文件,发现了这些有趣的行:
InfoRail日志文件——删除未经身份验证的消息
我似乎漏掉了一个重要的部分:身份验证。有了有关协议和加密的所有详细信息,我能够快速识别网络流量中的注册消息。这是负载不以XML形式存储的罕见示例之一。下面的截图展示了一个注册消息的片段:
注册消息的片段
这里研究人员发现了几件重要的事情:
· --reg.appident——指定尝试注册的服务的名称。
· --reg.uname/reg.puname——指定看起来像用户名的东西。
· --reg.cred/reg.pcred——指定看起来像哈希密码的东西。
经过大量的代码分析,我确定了以下内容:
· --Uname和puname是部分随机的。
· --Cred和pcred值是MD5哈希值,基于以下值:
· --用户名(.anonymous.0.digits)。
· --密钥的适当片段,在源代码中被硬编码。
同样,唯一需要的秘密在源代码中是可见的。攻击者可以检索密钥并构造他自己的有效注册消息。
最后,我们可以正确注册InfoRail服务并将我们自己的消息发送到任何Avalanche服务。
在这个阶段,可以验证ObjectGraph类中没有实现allowlist的服务。我找出了其中的5个:
· 数据存储服务(ZDI-CAN-15169)。
· StatServer服务(ZDI-CAN-15130)。
· 通知服务器服务(ZDI-CAN-15448)。
· 证书管理服务器服务(ZDI-CAN-15449)。
· Web文件服务器服务(ZDI-CAN-15330)。
我们有五个XStream反序列化终端,可以反序列化我们提供的任何东西。人们可以立即开始考虑利用这种反序列化的方法。首先,XStream对其安全性非常透明。他们的安全页面(可在此处获得)基于Java运行时中可用的类提供多个小工具。遗憾的是,没有合适的小工具适用于我试图利用的前四个服务,因为没有加载所需的类。
XStream试图允许尽可能多的对象图,默认转换器几乎是steroid上的Java序列化。除了对第一个不可序列化的父构造函数的调用之外,Java序列化可以实现的一切似乎都可以通过XStream实现(括代理构造)包。
在较新版本的XStream中似乎没有代理构造。但是,我们仍然应该能够使用ysoserial小工具来利用它。那时还没有用于XStream的Ysoserial小工具,所以我自己创建了几个。它们可以在这个GitHub存储库中找到。
使用我的ysoserialXStream小工具,我成功地在四个Avalanche服务中执行了重构代码。以下是我能够利用的服务的摘要,以及所需的小工具:
· StatServer:使用AspectJWeaver和CommonsBeanutils1利用。
· 数据存储库:使用C3P0和CommonsBeanutils1进行利用。
· 证书管理服务器:使用CommonsBeanutils1利用。
· Avalanche通知服务器:使用CommonsBeanutils1利用。
没有特别的原因,让我们关注StatServer。首先,我们必须找到将反序列化包含的XML有效负载的消息的主题和子类别。据此,InfoRail协议消息标头应包含以下键和值:
· h.distlist=255.3.2.12
· h.msgsubcat=3502(GetMuCellTowerData消息)
在本例中,我们将使用AspectJWeaver小工具,它允许我们上传文件。下面是XStream的AspectJWeaver小工具:
AspectJWeaver.xml
这个小工具任务如下:
· iConstant标签包含Base64文件内容。
· folder标签包含上传目录的路径。我的目标是AvalancheWeb应用程序根目录。
• key标记指定文件的名称。
有了所有需要的数据,我们就可以开始利用过程了:
StatServer利用——上传Webshell
以下屏幕截图展示了上传的webshell和whoami命令的执行。
StatServerExploitation——Webshell和命令执行
成功!综上所述,可以向Avalanche服务发送消息的攻击者可以在4个不同的服务中滥用XStream反序列化。
我还在第五个服务上实现了远程代码执行。然而,利用这个服务要复杂得多。
Java命名和目录接口(JNDI)查找有很长的历史,在Log4Shell漏洞出现之前,许多研究人员就已经熟悉了这个向量。CVE-2021-39146就是一个证明,它是一个触发查找的XStream反序列化小工具。它是唯一一个对Web File Server服务有效的XStream小工具,对此我无法制作一个有效的ysoserial小工具。
尽管如此,我们仍在处理一个新的Java版本。因此,我们不能滥用远程类加载。此外,攻击者不能滥用LDAP反序列化向量(此处有描述[PDF])。使用JNDI注入,我们可以交付序列化的有效负载,然后由目标反序列化。然而,我们没有意识到任何反序列化小工具可能被滥用在Web文件服务器。如果有任何gadget,我们首先就不需要JNDI查找。幸运的是,在Web文件服务器类路径中包含了几个有趣的JAR包。
Web文件服务器- Tomcat jar
可以看到,Web File Server加载了几个Tomcat JAR包。你可能还熟悉MichaelStepankin发现的技术,它滥用TomcatBeanFactory中的不安全反射通过JNDILookup执行任意命令。
总之,我们可以执行以下攻击:
· 设置恶意LDAP服务器,该服务器将为恶意BeanFactory提供服务。我们将使用RogueJNDI工具。
· 注册InfoRail服务。
· 发送包含CVE-2021-39146小工具的消息,以指向在步骤1中定义的服务器的Web文件服务器为目标。
· Web文件服务器进行LDAP查找并从恶意服务器检索数据。
· 远程代码执行。
LDAP服务器的设置如下图所示:
RogueJndi的设置
下一个片段展示了用于此概念证明的CVE-2021-39146小工具:
jndiGadget.xml
如果一切顺利,并且成功地执行了查找,那么Rogue JNDI应该显示以下消息,并且应该在目标系统上执行代码。
被触发的JNDI查找
总而言之,我们能够滥用自定义的IvantiAvalanche协议和XML消息反序列化机制来利用五种不同的服务并以SYSTEM权限远程执行代码。我在IvantiAvalanche中发现了更多反序列化漏洞。接下来,我将继续讨论协议和跨服务通信。
如上所述,各种Avalanche服务在InfoRail的帮助下相互通信。当服务提供响应时,该响应将再次通过InfoRail服务转发。这项研究的想法是:攻击者是否有可能欺骗响应?如果是这样,就有可能滥用IvantiAvalanche行为并执行潜在的恶意操作。
我重点研究了身份验证操作,如下图所示:
当用户通过AvalancheWeb应用程序登录面板进行身份验证时,后端会将身份验证消息传输到EnterpriseServer。此服务验证凭据并发回适当的响应。如果提供的凭据正确,则用户将通过身份验证。
在这个研究过程中,我学到了两件重要的事情:
· 攻击者可以注册为任何服务。
· 身份验证消息分布在注册的Enterprise Server的每个实例中。
据此,攻击者可以将自己注册为企业服务器,并截获传入的身份验证消息。但是,这种行为并没有什么直接的后果,因为传输的密码是经过哈希和加密的。
下一个问题是是否可以将攻击者自己的响应传递给AvalancheWeb,以及它是否会被接受。事实证明,是的,这是可能的!如果你想提供自己的响应,则必须在消息标头中正确设置两个值:
· Origin——发送消息的AvalancheWeb后端的主题(ID)。
· MsgId——原始身份验证消息的消息ID。
这两个值都比较容易获得,因此攻击者可以对消息提供自己的响应。它将被正在等待响应的服务接受。下图展示了一个攻击场景示例。
攻击场景如下:
——攻击者尝试使用错误的凭据登录Web应用程序。
——Web应用程序发送认证消息。
——InfoRail服务将消息发送到两台企业服务器:合法服务器和恶意服务器。
——攻击时间:
——合法服务器以“错误凭据”消息响应。
——恶意服务器以“credentialsOK”消息响应。如果攻击者的服务器首先传递消息,则将其转发到AvalancheWeb应用程序。
——攻击者获得身份验证。
请注意,针对攻击者服务器的“登录消息”不是故意存在的(尽管它实际上是传输给攻击者的)。我想强调一个事实,即可以在不可能读取消息的情况下利用这个问题。在此攻击中,攻击者必须暴力破解已经提到的消息ID值。它使整个攻击复杂化,但仍然有可能被利用。
总结这一部分,攻击者可以设置自己的恶意Enterprise Server,并滥用攻击条件来向Web应用程序交付自己的身份验证响应。还有两件事需要调查:响应消息是什么样的,我们能否缓解攻击?
以下代码段提供了对登录消息的示例响应。请注意,这些消息在合法使用期间会更大。但是,对于概念验证,我已将它们最小化并仅存储了开发所需的那些部分。
响应消息由几个重要部分组成:
· 它包含一个responseObject标记,它是一个序列化的用户对象。
· 它包含一个非常重要的responseCode标签。
· 在身份验证期间的某个时刻,Web后端调用UserService.doLogin方法:
doLogin.java
在[1]处,UserCredentials对象被实例化。然后,设置其成员。
在[2]处,将调用authenticate方法,并将在[1]处初始化的对象作为参数传递:
authenticate.java
在[1]处,初始化UserLogin对象。
在[2]处,UserCredentials对象被序列化。
在[3]处,消息正在发送到企业服务器,Web后端等待响应。
在[4]处,验证响应中包含的responseCode。我们希望它等于0。
在[5]处,userLogin.authenticated设置为True。
在[6]处,userLogin.currentUser被设置为包含在responseObject中的对象。
在[7]处,该方法返回userLogin对象。
基本上,响应应该有一个等于0的responseCode。它还应该在responseObject标记中包含一个正确序列化的User对象。
最后,我们分析负责调用doLogin函数的UserBean.loginInner方法的片段。
loginInner.java
在[1]处,调用doLogin方法。它检索UserLogin类型的对象。
在[2]处,它将this.currentUser设置为userLogin.currentUser。
在[3]处,它设置各种其他设置。
有一件非常重要的事情需要注意:Web后端不会将登录面板中提供的用户名与企业服务器检索到的用户名进行比较。因此,攻击者可以:
· 触发用户名为“poc”的身份验证。
· 赢得攻击并在响应中提供用户“amcadmin”。
· 然后攻击者将被认证为“amcadmin”。
总而言之,攻击者似乎没有任何障碍,他的响应应该由WebBackend处理,没有任何问题。接下来,我们将注意力转向防御。
在默认安装中,EnterpriseServer和InfoRail服务与Web后端位于同一主机上。这使得攻击条件的利用变得更加困难,因为合法的通信由本地接口处理,这比通过外部网络接口的通信要快得多。
尽管如此,攻击者还是有一些优势。例如,他不必生成动态响应,因为响应负载可以在漏洞利用中进行硬编码。下表概述了攻击者和合法EnterpriseServer必须执行的操作。
从原始登录消息中获取消息ID,并将其放置在标头中。
发送静态响应。
从原始登录消息中获取消息ID并将其放在标头中。
解密并验证用户的凭据。
检索用户的详细信息并创建用户对象。
动态创建响应。
远程攻击者需要执行的操作要少得多,可以更快地准备响应。它使攻击可以顺利进行。
未经身份验证的攻击者可以修改Avalanche系统设置。这是由于一个单独的漏洞允许绕过域身份验证(ZDI-CAN-15919)。远程攻击者可以启用基于LDAP的身份验证并为LDAP服务器配置设置任何地址。在这种情况下,合法的EnterpriseServer将首先尝试访问这个“非法”身份验证服务器。这将给攻击者额外的1 - 2秒时间(如果使用得当,甚至更多)。这样,攻击者就可以获得更多的时间来发起攻击。
参考及来源:https://www.zerodayinitiative.com/blog/2022/7/19/riding-the-inforail-to-exploit-ivanti-avalanche