需要云计算吗? 即刻开始体验

奇妙的 RPC 接口以及查找这些接口的方法

Oryan De Paz

寫於

Oryan De Paz

February 22, 2023

Oryan De Paz

寫於

Oryan De Paz

Oryan De Paz is a Security Researcher in the Akamai Technologies Enterprise Security Group. In her daily job, she is doing multiple types of research, from vulnerability research to malware and internal mechanisms of the operating system. She is passionate about the Windows operating system internals, reverse engineering, and solving puzzles, which makes working in security research her dream job. In her free time, she likes to bake, travel, and spend time with her dog, Alice; and she is always up for learning new things.

希望我们的持续研究和存储库中的工具能够给您带来更多启示,帮您进一步了解这种媒介,也希望这些资源能激发其他研究人员深入探究。

编辑和内容补充:Tricia Howard

前言

在过去的几个月里,我们的团队在 MS-RPC 研究方面投入了大量精力,因为它十分复杂,而且相关研究相当不充分。您可能已经看过无数篇关于我们在这项工作中发现的漏洞的帖子,内容涉及 srvsvcWininit.exe等。在整个研究过程中,我们积累了大量的数据和工具,而这些资源只有统合起来才有价值,我们应此推出了 RPC 工具包。 

这个开源存储库包含您开始研究或进一步研究 RPC 所需要的任何资源:工具、文章、博客文章和会议讲座,以及 RPC 漏洞信息和漏洞攻击概念证明。这个存储库的建立是为了让防御者和研究人员更容易获得 RPC 知识;毕竟,协力同心才能全面提高安全性。对于任何了解过我们的工作、使用过我们的工具或分享过我们的一些工作的人,我们借此表示衷心的谢意!很高兴我们的工作能帮到您。 

该工具包中的一个工具是我们的 RPC 接口分析器,它可以协助您这样的安全专家快速、轻松地寻找线索,了解可能有漏洞的接口。这篇博文是为了引导您了解它的预期目的以及发现的结果,并简要介绍 RPC 和它的一些安全机制,供那些可能还不熟悉的人参考。 

什么是 RPC?它的安全机制有哪些?

远程过程调用 (RPC) 是进程间通信 (IPC) 的一种形式,它允许客户端调用一个由 RPC 服务器公开的过程。客户端可以像执行普通过程调用一样来调用此函数,几乎不需要为远程交互的细节编码。服务器可以托管在同一台机器的不同进程中,也可以托管在远程机器上。

Windows 将 MS-RPC(Microsoft 的 RPC 实施)广泛用于许多不同的服务,比如任务调度、服务创建、打印机和共享设置,以及远程存储的加密数据的管理。这种广泛的使用范围和 RPC 作为媒介的远程性质,正是我们今天讨论这个主题的原因,也是我们投入这么多资源研究 RPC 的原因。它拥有大量的功能,因此,从安全的角度来看,它吸引了很多人的注意。

在下面的部分中,我们将深入探讨 RPC 安全回调 ,以及您如何使用自动化来分析它们,并从中探究新的安全性和漏洞研究线索。 

什么是 RPC 安全回调?它的工作原理是怎样的?

简而言之,安全回调是确保 RPC 接口安全的几种方法之一。它是一个由 RPC 服务器开发人员实施的自定义回调。它的逻辑由开发人员决定,它允许开发人员强制执行基于用户的访问控制、身份验证、传输类型,或阻止对服务器公开的特定函数的访问。 

最终,回调返回 RPC_S_OK 以允许客户端与服务器通信,或者返回 RPC 错误代码之一,比如 RPC_S_ACCESS_DENIED,以拒绝通信。

接受或拒绝客户端请求的决策通常依赖于一个属性(或不止一个),我们将在下面探讨这些属性。

协议序列

客户端可以通过几种传输方式与服务器通信:TCP、命名管道、ALPC 等。安全回调可以检查此属性,以便只过滤本地连接请求、只过滤远程请求和 TCP 通信,等等。

虽然文档中未提供协议序列的值,但我们将 RpcCallAttributes 结构中传递给安全回调的协议序列映射为以下值:

#define ncacn_ip_tcp 1
#define ncacn_np 2
#define ncalrpc 3
#define ncacn_http 4

其他协议序列(比如 ncacn_hvsocket)可以由安全回调通过解析字符串绑定 来进行测试

身份验证级别

检查客户端的 身份验证级别 在安全回调中是很常见的做法。通过这种方式,服务器可以定义它预计从客户端那里获得的最小身份验证级别。

有多个身份验证级别,每个级别都是对前一个级别的扩展:

#define RPC_C_AUTHN_LEVEL_DEFAULT 0
#define RPC_C_AUTHN_LEVEL_NONE 1
#define RPC_C_AUTHN_LEVEL_CONNECT 2
#define RPC_C_AUTHN_LEVEL_CALL 3
#define RPC_C_AUTHN_LEVEL_PKT  4
#define RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
#define RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6

例如,服务器预计身份验证级别为 RPC_C_AUTHN_LEVEL_PKT_PRIVACY ,以确保通信数据只对客户端和服务器可见,或者预计身份验证级别为 RPC_C_AUTHN_LEVEL_NONE ,以表示没有身份验证。

身份验证服务

身份验证 服务 指定了负责验证身份验证策略(由身份验证级别提供)的服务。 

身份验证服务常量值是:

#define RPC_C_AUTHN_NONE  0
#define RPC_C_AUTHN_DCE_PRIVATE  1
#define RPC_C_AUTHN_DCE_PUBLIC  2
#define RPC_C_AUTHN_DEC_PUBLIC  4
#define RPC_C_AUTHN_GSS_NEGOTIATE  9
#define RPC_C_AUTHN_WINNT  10
#define RPC_C_AUTHN_GSS_SCHANNEL  14
#define RPC_C_AUTHN_GSS_KERBEROS  16
#define RPC_C_AUTHN_DPA  17
#define RPC_C_AUTHN_MSN  18
#define RPC_C_AUTHN_DIGEST  21
#define RPC_C_AUTHN_NEGO_EXTENDER  30
#define RPC_C_NETLOGON   68(文档中未提供相关信息)
#define RPC_C_AUTHN_MQ   100
#define RPC_C_AUTHN_DEFAULT  0xffffffff

例如,RPC_C_AUTHN_NONE将关闭身份验证,而 RPC_C_AUTHN_WINNT 将使用 NTLM 协议。

身份验证服务的完整列表和它们的值可以在这个 GitHub 页面上找到。 

NULL 会话

NULL 会话是一个匿名连接。在这种情况下,客户端与服务器通信时没有身份验证;也就是说,不使用用户名或密码。 

在大多数情况下,如果注册了安全回调,那么,除非在服务器注册时提供了 RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH 标志,否则 NULL 会话将被默认阻止(在 此处了解其他情况)。安全回调也可以检查 NULL 会话。 

通过阻止对这些会话的访问,安全回调可以保护 RPC 接口,避免未经身份验证的用户访问。 

操作号 (opnum)

操作号代表客户端请求运行的接口函数。更准确地说,操作号是 RPC 服务器函数表的索引。

通过检查操作号值,服务器可以限制或阻止客户端对特定函数的访问,例如为远程客户端处理敏感数据的函数、为用户模式客户端访问内核内存和/或功能的函数,等等。

Akamai 安全研究团队发表了一篇博文, 介绍了一个有趣的安全回调示例, 那个回调依靠的就是此检查。 

其他安全回调检查可以是:

  • 调用者来源 ——检查调用者是来自用户模式还是内核模式

  • 客户端 PID ——只允许特定的进程

  • 字符串绑定 ——验证 RPC 连接属性,比如协议序列、网络地址、端点信息等

  • 仿冒 ——确保服务器可以在客户端的安全上下文中运行代码

还有一些复杂的检查。例如,在 lsasrv.dll 的 LsaCapRpcIfCallbackFn 回调中,如果身份验证服务是 netlogon,身份验证级别应该小于 RPC_C_AUTHN_LEVEL_PKT_INTEGRITY。

RPC 接口分析器——实操导览

RPC 接口分析器是一个用于研究 RPC 接口的自动化工具。它允许研究人员从两个不同的来源(接口定义 (IDL) 文件或 PE 文件)查找并分析 RPC 接口。

IDL 文件

IDL 文件 是定义 RPC 接口及其函数的文件。通过分析公开的 IDL 文件,我们可以得到关于 RPC 接口和其服务器公开的函数的信息,以及它们的参数和返回值类型。借助这些信息,研究人员可以寻找可能有漏洞的函数;例如 PetitPotam等漏洞中接收路径参数的函数。 

为了运行我们的 IDL 分析器,请运行下列命令:

1.使用 idl_scraper 脚本,从 Microsoft 网站将所有 IDL 文件下载到您的机器上:

idl_scraper.py [-h] [-o OUTPUT] [-p PROTOCOL]

2.然后运行 idl_parser,以便分析这些 IDL 文件:

idl_parser.py [-h] [-r] input_path [output_path]

您将获得的输出是一个 CSV 文件,包含 RPC 接口名称、通用唯一标识符 (UUID)、公开的函数名称和签名。

PE 文件

分析 IDL 文件可能很有用,但我们只能访问公开的 IDL 文件,所以可能会遗漏一些 RPC 接口。另一种方法是在本地文件系统中寻找 RPC 接口,也就是在 PE 文件(.exe 或 .dll 文件)中寻找。我们发现这种方法比检查实时进程更好,因为这样一来,我们就不会遗漏那些并非实时的 RPC 服务器,或在受保护进程中运行的 RPC 服务器。

RPC PE 分析器 将寻找由 RpcServerRegisterIf 函数(及其变体)注册的 RPC 接口,并对传递给它的参数执行分析(假设提供了反汇编程序)。在没有它的情况下运行时,在默认模式下,分析器会使用正则表达式查找 RPC 接口。此 讲座 详细介绍了搜索过程。

为了在默认模式下使用 RPC PE 分析器,请运行以下命令:

pe_rpc_scraper.py <scrape_path> <output_path>

此命令会给您提供基本输出,包括接口的 UUID、它的角色(客户端/服务器)以及它的函数名称和地址。

如果您想获得更详细的信息,可以向脚本提供一个反汇编程序及其路径(如果不是默认设置):

pe_rpc_scraper.py [-d {idapro,radare}] [-P DISASSEMBLER_PATH] <scrape_path> <output_path>

使用反汇编程序选项将同时添加接口注册信息,包括:

  • 在服务器注册中提供的标志

  • 接口的安全回调名称和地址

  • RPC 服务器的安全描述符(如有)

  • 是否 为安全回调 启用了全局缓存

与这篇博文同时发布的新功能还支持分析安全回调本身。 

使用示例

假设我们想扫描我们机器上所有可用的 RPC 接口。我们可以运行 RPC PE 分析器,提供一个 C:\Windows\System32 的副本作为我们的 scrape_path,并查看输出。 

pe_rpc_scraper.py -d idapro “C:\Users\User\Documents\System32_Copy”

输出为 JSON 格式,因此,很容易对其进行迭代并寻找具体信息。例如:

  • 查找 DLL 文件中的所有 RPC 客户端/服务器

  • 查找一台机器上的所有 RPC 客户端/服务器

  • 查找某个特定 RPC 接口的客户端

  • 查找某个 RPC 服务器的 RPC 安全回调

  • 查找哪些 RPC 接口使用了接口级缓存(阅读这篇 博文 ,详细了解这种类型的缓存为什么会存在问题)

这些用途只是该输出的众多用途中的一部分。我们很乐意了解更多的使用方法和想法。

新功能——安全回调信息

RpcCallAttributes 结构 

RPC_CALL_ATTRIBUTES 是一个结构,其中有关于客户端请求的数据。服务器端的接口安全回调可以通过调用 RpcServerInqCallAttributes 函数获得这些信息。 

typedef struct tagRPC_CALL_ATTRIBUTES_V3_W

{
    unsigned int Version;
    unsigned long Flags;
    unsigned long ServerPrincipalNameBufferLength;
    unsigned short *ServerPrincipalName;
    unsigned long ClientPrincipalNameBufferLength;
    unsigned short *ClientPrincipalName;
    unsigned long AuthenticationLevel;
    unsigned long AuthenticationService;
    BOOL NullSession;
    BOOL KernelModeCaller;
    unsigned long ProtocolSequence;
    RpcCallClientLocality IsClientLocal;
    HANDLE ClientPID; 
    unsigned long CallStatus;
    RpcCallType CallType;
    RPC_CALL_LOCAL_ADDRESS_V1 *CallLocalAddress;
    unsigned short OpNum;
    UUID InterfaceUuid;
    unsigned long          ClientIdentifierBufferLength;
    unsigned char          *ClientIdentifier;
} RPC_CALL_ATTRIBUTES_V3_W;

我们已经提到了安全回调运行的测试。它们可以单独查询其中的一些值(例如, RpcStringBindingParseW 用于接收协议序列, RpcBindingInqAuthClient 用于身份验证信息,等等),也可以使用这个包含所有信息的结构,此时仅需要一次函数调用。事实上,在我们分析的大多数安全回调中,它们都调用 RpcServerInqCallAttributes 并使用 RPC_CALL_ATTRIBUTES 结构来同时查询所有属性。所以这个结构非常值得关注,可以帮您了解安全回调的逻辑。

该结构目前有三个不同的版本——1、2 和 3,每个版本都在其之前版本的基础上进行了扩展,并且有 ANSI 和 Unicode 版本。您可以在这个 GitHub 页面上找到不同的版本和它们的成员。 

安全回调信息

我们的 RPC 工具包新添加了 安全回调信息,它是 RPC PE 分析器的一部分。可以通过它来了解安全回调在批准/拒绝客户端请求之前所做的检查和验证。 

通过分析 RPC 接口的安全回调(特别是它对 RPC_CALL_ATTRIBUTES 结构的访问),可以对该接口有所了解。这样,如果您想过滤使用(或不使用)特定 身份验证 协议的 RPC 接口,就可以查找检查身份验证服务属性的安全回调。您也可以查询那些在允许客户端请求之前(以及在其服务器注册标志允许 NULL 会话 之前),不检查 NULL 会话的 RPC 接口,以发现可能有漏洞的 RPC 接口。

工作原理

对于每个安全回调,分析器将:

  • 确定正在使用的 RPC_CALL_ATTRIBUTES 结构版本,并在 IDA 的本地类型中定义相关结构

  • 查找 RpcCallAttribute 本地变量并应用 RPC_CALL_ATTRIBUTES 结构作为其类型

  • 解析安全回调使用该结构执行的检查,并输出正在测试的成员、与之比较的值以及使用的运算符(== / != / > / < / 等)。

我如何使用它?

使用方法并没有改变:每次您运行带有 IDA 反汇编程序标志的 RPC PE 分析器时,每个 RPC 接口的输出现在都会包括其安全回调信息——它是否访问 RpcCallAttributes 结构成员,以及它测试什么。

  • 注意:此新增功能目前只适用于 IDA,运行带有 Radare 选项的分析器时,不会包括安全回调信息。

在您获得输出后,可用它来查找可能有漏洞的 RPC 接口,并根据您的需求进行过滤。一些示例包括:

  • 获取一个只使用 RPC_C_AUTHN_LEVEL_PKT_PRIVACY 身份验证级别的 RPC 接口

  • 获取预计进行本地连接的 RPC 接口

  • 获取预计只接受内核模式调用者的 RPC 接口

  • 获取检查操作号的 RPC 接口(在存在缓存漏洞的情况下)

总结

很明显,RPC 是一个成熟的研究领域,特别是考虑到它有着如此长久的发展历程,并集成到如此之多的关键进程中。近一年来,我们一直在我们的存储库中汇集资源,但要充分认识 RPC 的潜在威胁,还有很多东西需要涉猎。它的研究仍然相当不充分,尽管它最近获得了更多的关注,但仍有许多信息尚待发现,以便了解攻击者可能滥用它的无数方式。

RPC 的内在性质要求我们对每个潜在的危险角度进行研究。希望我们的持续研究和存储库中的工具能够给您带来更多启示,帮您进一步了解这种媒介,也希望这些资源能激发其他研究人员深入探究。无论您是负责保护 RPC 的防御者,还是寻找下一个目标的研究人员,RPC 都有很多知识和见解值得挖掘。

准备好开始了吗?查看 存储库,别忘了到 Twitter 上与我们分享您的发现!



Oryan De Paz

寫於

Oryan De Paz

February 22, 2023

Oryan De Paz

寫於

Oryan De Paz

Oryan De Paz is a Security Researcher in the Akamai Technologies Enterprise Security Group. In her daily job, she is doing multiple types of research, from vulnerability research to malware and internal mechanisms of the operating system. She is passionate about the Windows operating system internals, reverse engineering, and solving puzzles, which makes working in security research her dream job. In her free time, she likes to bake, travel, and spend time with her dog, Alice; and she is always up for learning new things.