目录导航
网络邮件应用程序使组织能够为其成员托管基于浏览器的集中式电子邮件客户端。通常,用户使用他们的电子邮件凭据登录到 webmail 服务器,然后 webmail 服务器充当组织电子邮件服务器的代理,并允许经过身份验证的用户查看和发送电子邮件。
由于网络邮件服务器受到如此多的信任,它们自然成为攻击者非常感兴趣的目标。例如一个老练的对手可以入侵网络邮件服务器,他们可以拦截每封发送和接收的电子邮件,访问密码重置链接和敏感文档,冒充人员并窃取登录网络邮件服务的用户的所有凭据。
这篇博文讨论了 Sonar 研发团队在 Horde Webmail 中发现的一个漏洞。一旦受害者打开攻击者发送的电子邮件,该漏洞允许攻击者完全接管实例。在撰写本文时,还没有官方补丁可用。
影响
发现的漏洞标号为 (CVE-2022-30287) 允许经过身份验证的 Horde 实例用户在底层服务器上执行任意代码。
该漏洞可以通过单个 GET 请求来利用,该请求可以通过 Cross-Site-Request-Forgery 触发。为此,攻击者可以制作恶意电子邮件并包含外部图像,该图像在呈现时利用漏洞而无需受害者进一步交互:唯一的要求是让受害者打开恶意电子邮件。
该漏洞存在于默认配置中,并且可以在不了解目标 Horde 实例的情况下被利用。我们确认它存在于最新版本中。在撰写本文时,供应商尚未发布补丁。
此漏洞的另一个副作用是触发漏洞的受害者的明文凭据被泄露给攻击者。然后,攻击者可以使用它们来访问组织的更多服务。这在我们的视频中得到了展示:
技术细节
在以下部分中,我们将详细介绍此漏洞的根本原因以及攻击者如何利用它。
背景 – Horde通讯录配置
Horde Webmail 允许用户管理联系人。从 Web 界面,他们可以添加、删除和搜索联系人。管理员可以配置这些联系人的存储位置并创建多个地址簿,每个地址簿都由不同的后端服务器和协议提供支持。
以下代码片段摘自默认通讯簿配置文件,显示了 LDAP 后端的默认配置:
turba/config/backends.php
$cfgSources['personal_ldap'] = array(
// Disabled by default
'disabled' => true,
'title' => _("My Address Book"),
'type' => 'LDAP',
'params' => array(
'server' => 'localhost',
'tls' => false,
// …
可以看出,此 LDAP 配置被添加到存储在$cfgSources数组中的可用地址簿后端数组中。配置本身是一个键/值数组,包含用于配置 LDAP 驱动程序的条目。
CVE-2022-30287 – Factory 类中缺少类型检查
当用户与与联系人相关的端点交互时,他们应该发送一个字符串来标识他们想要使用的地址簿。Horde 然后从$cfgSources数组中获取相应的配置,并管理与地址簿后端的连接。
以下代码片段演示了此模式的典型用法:
turba/merge.php
14 require_once __DIR__ . '/lib/Application.php';
15 Horde_Registry::appInit('turba');
16
17 $source = Horde_Util::getFormData('source');
18 // …
19 $mergeInto = Horde_Util::getFormData('merge_into');
20 $driver = $injector->getInstance('Turba_Factory_Driver')->create($source);
21 // …
30 $contact = $driver->getObject($mergeInto);
上面的代码片段显示了如何接收参数$source并将其传递给Turba_Factory_Driver的create()方法。Turba 是 Horde 通讯录组件的名称。
查看create()方法时,事情开始变得有趣:
turba/lib/Factory/Driver.php
51 public function create($name, $name2 = '', $cfgSources = array())
52 {
53 // …
57 if (is_array($name)) {
58 ksort($name);
59 $key = md5(serialize($name));
60 $srcName = $name2;
61 $srcConfig = $name;
62 } else {
63 $key = $name;
64 $srcName = $name;
65 if (empty($cfgSources[$name])) {
66 throw new Turba_Exception(sprintf(_("The address book \"%s\" does not exist."), $name));
67 }
68 $srcConfig = $cfgSources[$name];
69 }
在第 57 行,检查$name参数的类型。此参数对应于前面显示的$source参数。如果它是一个数组,则通过将其设置为$srcConfig变量直接用作配置。如果是字符串,则使用它访问全局$cfgSources并获取相应的配置。
这种行为对攻击者来说很有趣,因为 Horde 期望行为良好的用户发送一个字符串,然后导致使用受信任的配置。但是,没有适当的类型检查可以阻止攻击者发送数组作为参数并提供完全受控的配置。
几行代码之后,create()方法使用攻击者控制的数组中的值动态实例化驱动程序类:
turba/lib/Factory/Driver.php
75 $class = 'Turba_Driver_' . ucfirst(basename($srcConfig['type']));
76 // …
112 $driver = new $class($srcName, $srcConfig['params']);
通过这种级别的控制,攻击者可以选择实例化任意地址簿驱动程序并完全控制传递给它的参数,例如主机、用户名、密码、文件路径等。
实例化使攻击者能够执行任意代码的驱动程序
攻击者的下一步将是注入驱动程序配置,使他们能够在他们所针对的 Horde 实例上执行任意代码。
我们发现 Horde 支持连接到IMSP 服务器,该服务器使用 1995 年起草但从未最终确定的协议,因为它已被ACAP协议取代。当连接到这个服务器时,Horde 会获取各种条目。其中一些条目被解释为 PHP 序列化对象,然后被反序列化。
以下来自 IMSP驱动程序类的_read()方法的代码摘录显示了如何检查__members条目的存在。如果存在,则对其进行反序列化:
turba/lib/Driver/Imsp.php
223 if (!empty($temp['__members'])) {
224 $tmembers = @unserialize($temp['__members']);
225 }
由于Steven Seeley发现了可行的 PHP 对象注入小工具,攻击者可以强制 Horde 反序列化导致任意代码执行的恶意对象。
通过 CSRF 利用漏洞
默认情况下,Horde 会阻止 HTML 电子邮件中没有data: URI 的任何图像。攻击者可以通过使用 HTML 标签<picture>和<source>绕过这个限制。<picture>标签允许开发人员指定根据访问站点的用户的尺寸加载的多个图像源。以下示例绕过外部图像的阻止:
<picture>
<source media="(min-width:100px)" srcset="../../?EXPLOIT">
<img src="blocked.jpg" alt="Exploit image" style="width:auto;">
</picture>

修补
在撰写本文时,还没有官方补丁可用。由于 Horde 似乎不再积极维护,我们建议考虑替代 webmail 解决方案。
时间线
日期 | 行动 |
---|---|
2022-02-02 | 我们将问题报告给供应商并告知我们的 90天披露政策 |
2022-02-17 | 我们要求更新状态。 |
2022-03-02 | Horde 发布了针对我们之前报告的另一个问题的修复程序并确认此报告。 |
2022-05-03 | 我们通知供应商 90 天的披露期限已过 |
概括
在这篇博文中,我们描述了一个漏洞,该漏洞允许攻击者通过向受害者发送电子邮件并让受害者阅读电子邮件来接管 Horde 网络邮件实例。
该漏洞发生在通常使用动态类型的 PHP 代码中。在这种情况下,如果用户控制的变量是数组类型,则进入安全敏感分支。我们强烈建议开发人员不要根据变量的类型做出安全决策,因为通常很容易错过特定于语言的怪癖。
转载请注明出处及链接