攻击者是如何利用Memcache注入漏洞来窃取Zimbra Email用户的明文凭证的
窃取受害者的密码
Zimbra是一个企业级的电子邮件解决方案,类似于Microsoft Exchange。它提供了邮件服务器、负载平衡功能、一个强大的Web界面等等。根据该供应商的网站,全球有超过20万家企业、大学、金融和政府机构在使用它,用户可以登录其Zimbra邮件账户来阅读和发送私人电子邮件。
我们在Zimbra中发现了一个漏洞,该漏洞允许攻击者从部署了Zimbra解决方案的用户那里窃取登录凭证。一旦能够访问受害者的邮箱,攻击者就能进一步升级对目标组织的访问权限,进而获得对各种内部服务的访问权并窃取高度敏感的信息。通过邮件访问,攻击者可以重置密码,冒充受害者,并悄悄地阅读目标公司内的所有私人信件。就在几个月前,Volexity发布了一项关于0day漏洞的研究,其中指出有攻击者正在利用安全漏洞攻击Zimbra实例,特别是那些由政府机构部署的实例。
在本文中,我们将为读者介绍一个新的漏洞,该漏洞允许未经认证的攻击者在没有任何用户交互的情况下从Zimbra实例中窃取明文凭证。我们将考察Memcache注入漏洞的工作原理以及攻击者是如何利用它们的。鉴于这个安全问题的严重性,我们敦促Zimbra用户立即进行升级。
漏洞的影响
以下视频演示了未经认证的攻击者是如何窃取目标实例的已知用户的密码的。当受害者下次使用邮件客户端连接到其组织的Zimbra服务器时,该漏洞就会被触发,演示视频地址:
经验证,我们发现该漏洞(CVE-2022-27924)存在于Zimbra的8.8.x和9.x所有分支中,同时影响开源和商业版本。准确来说,这些代码缺陷影响了Zimbra的反向代理,并且可以被未经认证的攻击者用默认配置来发动攻击。已经修复该漏洞的版本分别是8.8.15和9.0.0,其补丁级别为31.1和24.1。
正如本文后面所详述的,攻击者可以使用两种策略来利用这个漏洞。第一个策略要求攻击者知道受害者的电子邮件地址,以便能够窃取他们的登录凭证。通常情况下,一个组织会为其成员的电子邮件地址使用某种格式,如{firstname}.{lastname}@example.com。而电子邮件地址列表则可以通过OSINT源获取,如LinkedIn。
第二种攻击技术则利用“响应走私(Response Smuggling)”技术来绕过第一种策略所施加的限制,并允许攻击者从任何易受攻击的Zimbra实例中窃取明文凭证,而不需要对该实例有任何了解。并且,这两种策略都不需要用户进行交互。
技术细节
在下面的章节中,我们将对Zimbra的架构进行概要介绍。尽管安全问题的根本原因在于源代码,但要了解该漏洞以及攻击者如何利用该漏洞,就必须了解这些知识。
背景知识:Zimbra代理
在默认情况下,Zimbra的安装脚本会将所有必要的服务安装在一台服务器上。这样做的好处是,可以很容易地添加额外的后端服务器来分担繁重的电子邮件交换工作负荷。
为了管理这种负载平衡功能,Zimbra使用Nginx作为反向代理来接收所有传入的HTTP和电子邮件(IMAP与POP3)流量,并将其转发到注册的某个后端服务器。由于Zimbra的架构的缘故,Nginx会以循环方式将请求转发给后端服务器的默认行为是无法满足需求的。其原因是,存储在不同后端服务器上的数据可能不会在所有服务器上都有镜像,而且不同的后端服务器负责不同的用户。
为了解决这个问题,Zimbra的开发人员维护了一个Nginx的修改版本,以及自定义的Nginx模块。这些定制的模块能够确保Nginx将特定用户发送的流量转发到正确的后端服务器。
正确的路由是通过Zimbra Lookup Service实现的。当Zimbra的反向代理收到一个连接(1)时,它会尝试通过各种方法来识别发出请求的用户,比如通过URL来识别用户:当一个传入的HTTP请求被发送到示例网址https://example.com/service/home/exampleUser/file时,服务器就可以藉此识别出相应的用户为exampleUser。
然后,Zimbra的Nginx(2)将向内部的ZimbraLookup Service发出HTTP请求,并要求它为该用户提供正确的后端服务器。该服务随后将返回一个IP和端口,并将传入的流量转发到该端口(3)。
下面给出了这一过程的示意图:
需要注意的是,即使只注册了一个后端服务器,这个过程也会发生,并且结果总是相同的。因此,即使没有添加其他服务器,也可以利用这些漏洞。
背景知识:使用Memcached进行后台路由缓存
在上一节中,我们描述了Zimbra的反向代理如何在将流量转发到正确的后端服务之前,为它接收到的每个连接向Zimbra查找服务发出HTTP请求。
由于这个额外的HTTP请求对性能的影响很大,因此,所有用户都会通过一个Memcached实例来缓存结果。在向查找服务发出HTTP请求之前,将检查缓存中的现有路由。如果存在缓存项,则无需发送查找请求。
Memcached是一个存储键/值对的服务器,可以使用简单的基于文本的协议来设置和检索这些键/值对。
接下来,让我们继续以前面的exampleUser发出HTTP请求为例进行介绍。一旦从Zimbra查找服务中获取了正确的后端服务器,就会向对应的Memcached服务发送以下消息,并将后端服务器的地址添加到缓存中:
上图表明,add命令被用来设置keyroute:proto=httpssl;user=exampleUser@example.com。下图给出了所发送的Memcached消息的不同组成部分:
请注意,我们这里显式使用(\r\n)来表示Memcache示例消息中的新行,因为它们对理解下面的漏洞很重要。
然后,服务器用一个简单的消息进行响应,以告诉Memcached客户端(本例中为Zimbra的反向代理)存储成功了:
在这些数据被添加到缓存中之后,在exampleUser每次发出HTTP请求时,Zimbra的反向代理都会尝试获取这些数据。为了做到这一点,它将向Memcached服务器发送以下消息:
然后,Memcached服务器将发送以下响应:
我们可以看到缓存条目的键是可预测的,其格式为route:proto=PROTOCOL;user=EMAIL。其中,这里的协议可以是httpssl、imap或pop3协议。我们将在后面讨论后两个选项。
漏洞(CVE-2022-27924):Memcached查询过程中的CRLF注入漏洞
Memcached使用一个基于文本的协议,逐行解释传入的数据。这意味着,如果攻击者能够将换行符注入Memcached查询的用户名中,他们就可以执行恶意的Memcached命令。
在前面的章节中,我们描述了对URLhttps://example.com/service/home/exampleUser/file的HTTP请求是如何导致以下Memcached查询的:
如果URL包含换行符,并且后面跟着注入的命令,将会发生什么?让我们假设攻击者创建了以下URL(为了清晰起见,未进行编码):
由于在构造Memcached查询之前实际上没有对换行符进行转义处理,因此,以下数据将由Zimbra的反向代理发送给Memcached服务器:
然后,该服务器会逐行处理输入,并用以下数据进行响应:
响应的第一行包含END(\r\n),表示get命令执行失败了,因为route:proto=httpssl;user=example键并不存在。在下一行中,Memcached使用各种运行时统计信息作为对注入的stats命令的响应进行响应。最后一行用于指出user@example.com字符串的错误:虽然该字符串位于自己的行中,但并不代表有效的命令。
上面的例子展示了攻击者是如何执行任意的Memcached命令的。最重要的是,攻击者可以创建并覆盖任意的缓存条目,只要他们知道他们想覆盖的密钥。这可以通过注入add或set命令来实现。
窃取已知用户的明文凭证
在前面的章节中,我们已经看到了攻击者是如何覆盖目标Zimbra安装的Memcached实例中的缓存条目的。为了了解攻击者是如何利用这个漏洞的,我们需要搞清楚哪些缓存条目是可以被覆盖的,以及这可能对目标Zimbra实例产生什么样的安全影响。
路由缓存条目是一种非常有价值的覆盖目标,因为路由键是可预测的。我们之前已经看到exampleUser的路由是如何用route:proto=httpssl;user=exampleUser@example.com的键来进行缓存的。这里,协议是httpssl,因为用户是通过HTTP(s)请求的URL进行识别的。然后,紧跟字符串exampleUser@example.com。就这里来说,用户名是可预测的,因为它受制于我们。而example.com则是从同一HTTP请求中的Host头部中得到的。
我们之前说过,Zimbra是使用Nginx来代理IMAP和POP3流量的。考虑到所有这些,我们意识到攻击者可以覆盖目标安装的任何已知用户的IMAP路由缓存条目,例如通过发出以下HTTP请求就可以达到上述目的:
结果是,下面的信息会被发送到服务器:
当缓存“中毒”后,下次victim@example.com用户通过IMAP连接到他们的Zimbra实例时,NginxProxy将使用中毒的值,并将所有IMAP流量转发到攻击者控制的服务器。因此,明文凭证将一起转发到攻击者的服务器。
实际上,所有这些都是在后台发生的,而受害者用户毫不知情。通常来说,邮件客户端(如Thunderbird、Microsoft Outlook、macOS邮件应用程序和智能手机邮件应用程序)将用户用于连接IMAP服务器的凭据存储在磁盘上。当邮件客户端重新启动或需要重新连接时,它将对目标Zimbra实例重新进行身份验证。
对于大部分组织来说,其成员的电子邮件地址通常会利用某种特定的格式进行命名,例如,{firstname}.{lastname}@company.tld。如果具有针对性的攻击者能够获得一个组织的成员名单,例如通过使用LinkedIn等信息源,他们就可以对所有已知用户的缓存进行投毒,当受害者电子邮件客户端重新连接到目标公司的Zimbra实例时,然后攻击者就能收到受害者的明文凭证。
演示视频地址:https://youtu.be/GIgHZrPrGug。
注入Memcache响应以窃取任意凭证
在上一节中,我们演示了攻击者如何通过对IMAP路由缓存条目进行投毒来窃取目标Zimbra实例用户的用户名和密码。
然而,为了令这种攻击得手,必须满足以下要求:(1)攻击者必须知道一个或多个受害者的电子邮件地址,以便能够给他们的缓存条目投毒;2)受害者必须实际使用一个IMAP客户端。Zimbra提供了一个网络客户端,它绕过了代理路由查找,直接与后端服务器进行对话,因此,这种情况下证书就不会被盗。尽管我们认为在一个拥有数百名成员的组织中,至少有一部分用户使用邮件客户端(包括那些安装在手机上的)是非常合理的,但攻击者所知道的用户可能不会使用它们。
攻击者可以以一种有趣的方式利用Zimbra的Memcached客户端来绕过这些限制,并从任何使用电子邮件客户端的用户那里窃取凭证。
在默认情况下,Zimbra会使用4个工作进程来处理传入连接。在默认配置中,每个工作进程可以处理10240个连接。而连接插槽可能被HTTP请求或IMAP或POP3会话所填充。
引起我们注意的是,Zimbra的Nginx会为每个进程而不是每个用户连接建立了一个到Memcached服务器的连接。
在底层代码中,每当处理用户连接的工作线程需要从Memcached获取缓存项时,该线程就会通过共享套接字将消息发送到Memcached服务器,然后将工作项放入在工作进程的所有线程之间共享的队列中。
假设同时有3个用户(A、B和C),其路由查找任务都位于工作队列中。一旦Memcached服务器处理完所有3个查找任务,它就会将这3个查找的结果发送回客户端。我们可以用下图来演示这种过程:
提醒一下,如果用户A、B和C都要发送HTTP请求的话,将向服务器发送以下Memcached命令:
然后,Memcached将使用以下数据进行响应:
其中,用户A的查找响应在共享工作队列中排在第一位。在进行处理时,只处理响应流中与该工作项目相关的字节:就本例来说,即第一个值,也就是用户A的工作项目。在处理完A的工作项目后,就会处理B的工作项目,然后继续处理剩下的字节,以此类推。
这种行为可以通过注入比队列中的工作项更多的获取请求的响应来加以利用。让我们再次假设,用户A、B和C的缓存查找都位于共享工作队列中。然而,用户A是恶意的,他滥用了之前讨论的CLRF,迫使Zimbra向Memcached服务器发送以下流量:
如果攻击者之前将route:proto=httpssl;user=和A@example.com缓存条目设置为处于攻击者控制之下的服务器的值,那么响应流可能会是下面这样:
此外,我们也可以用下图来说明这种状态:
上图展示了响应流中的项目是如何多于工作队列中的项目的。如果这个状态是强制的,A的缓存查询请求将只处理第一个结果,即结果A1。当B的缓存查询请求被处理时,它将使用结果A2的值,而这个值是处于攻击者控制之下的。
我们的想法是,通过不断向Memcached的共享响应流注入比工作项目更多的响应,来迫使随机的Memcached查找使用注入的响应,而不是正确的响应。这种攻击方法之所以能够奏效,是因为Zimbra在消费Memcached响应时没有验证其键。
通过利用这种行为,我们可以劫持连接到我们IMAP服务器的随机用户的代理连接,而无需知道他们的电子邮件地址。这种利用策略也不会破坏任何东西,因为使用中毒值的HTTP查找请求会退回到Round Robin方法。
漏洞补丁
Zimbra通过在将所有Memcache键发送到Memcache服务器之前创建一个SHA-256哈希值来修补这个漏洞。由于SHA-256的十六进制字符串不能包含空格,因此不能再注入新行。
修复版本分别是补丁级别为31.1的8.8.15版本,以及补丁级别为24.1的9.0.0版本。
时间线
- 2022-03-11:我们向Zimbra报告这个安全问题。
- 2022-03-11:Zimbra确认了该报告。
- 2022-03-16:Zimbra确认他们能够重现该漏洞。
- 2022-03-31:Zimbra为8.8.15和9.0.0分支发布了漏洞补丁。
- 2022-04-01:我们通知Zimbra,这些补丁是不充分的。
- 2022-04-05:我们在Webex电话会议上与Zimbra开发人员讨论了不充分的补丁和补丁策略。
- 2022-05-01:我们要求Zimbra提供有关补丁的最新信息。
- 2022-05-02:Zimbra告诉我们,他们正在测试一个补丁。
- 2022-05-06:Zimbra向我们发送了补丁以进行测试。
- 2022-05-06:我们验证该补丁是否有效。
- 2022-05-10:Zimbra通知我们该补丁即将发布。
- 2022-05-22:我们通知Zimbra有关该公告的发布日期。
小结
在这文章中,我们为读者介绍了在Zimbra中发现的一个Memcache注入漏洞,该漏洞的根本原因为没有对不可信的用户输入的换行字符(\r\n)进行转义处理。这个代码漏洞最终允许攻击者窃取目标Zimbra实例的用户的明文凭证。
尽管诸如跨站脚本和SQL注入之类的漏洞仍然存在,并且也是由于缺乏输入转义而发生,但它们几十年来一直是众所周知并被记录在案的。大多数开发者都了解这些漏洞,并了解在将某些特定上下文的字符传递给潜在的危险函数之前,应对其进行转义处理。然而,正如我们所看到的,其他的注入漏洞也会发生,这些漏洞不太为人所知,但会产生重要的影响。
我们建议开发者在处理那些关于潜在漏洞的文档和研究较少的技术时,要始终关注需要转义处理的特殊字符。
参考资料
- Zimbra 8.8.15 - Webmail compromise via Email
- PHP Supply Chain Attack on Composer
- NodeBB 1.18.4 -Remote Code Execution With One Shot
原文地址:https://blog.sonarsource.com/zimbra-mail-stealing-clear-text-credentials-via-memcache-injection/
最新评论