使用 RPC 检测恶意攻击

Windos 中利用 RPC 检测恶意攻击

前置知识

  • RPC(Remote Procedure Call)原理
  • ETW(Event Tracing for Windows)

背景

RPC 是 Windows 的一种 IPC(Inter-Process Communication,进程间通信)机制,可以用于同一台机器上的进程通信,也可以与远程机器上的进程通信,是许多 Windows 功能和第三方工具的基础。例如计划任务(at、schtasks)和 sc、wmi、psexec 等。这些工具也常被攻击者使用。既然这些工具都使用了 RPC 作为底层技术,我们自然可以通过检测 RPC 的方式来检测这些攻击方式。

监控 RPC 行为的方法

本文中会介绍两种检测 RPC 的方法:抓包和使用 ETW。

  • 抓包:抓取 RPC Client 和 Server 端的通信。使用此方法需要确保能拦截到 Client 和 Server 通信的流量。本文中演示了物理机攻击虚拟机的过程,使用 Wireshark 拦截虚拟网卡,同时 Wireshark 提供了默认的过滤器 dcerpc,可以方便地观察 RPC 通信内容。
  • 使用 ETW:Windows 中存在一个 ETW Provider,Microsoft-Windows-RPC.xml,其中提供了关于 RPC 调用的事件,与使用抓包方式获取的信息基本相同。使用 ETW 的优势在于只需在靶机上捕捉事件,在实际检测中比较合理。

如无特殊说明,实验环境为:

Vmware 靶机 Win 10,192.168.3.131。

物理机 IP 192.168.3.1。

检测计划任务

Windows 中提供了两个管理计划任务的工具,At 和 Schtasks。At 自 Win 8 起弃用,因此我们首先从 Schtasks 开始。Windows 中使用了一种基于 RPC 的协议来管理计划任务,MS-TSCH

注意,对于检测计划任务来说,使用 ETW Provider Microsoft-Windows-TaskScheduler 也许是更好的方式,这里只为演示如何检测基于 RPC 的行为。

Schtasks

在目标机器上启动事件记录,并启动 Wireshark 抓取 Vmware NAT 网卡上的流量。

1
logman create trace rpc -p Microsotf-Windows-RPC -ets

进行攻击

1
2
3
4
5
6
# 目标机器运行以下命令,授予 Administrator 和 SYSTEM 对 task 目录的完全访问权限
cacls c:\windows\tasks /T /E /P Administrators:F
cacls c:\windows\tasks /T /E /P SYSTEM:F

# 攻击机器上执行,添加任务
schtasks /create /tn te /tr c:\Windows\System32\calc.exe /sc weekly /mo 6 /s 192.168.3.131 /u Administrator

停止记录

1
logman stop rpc -ets

结束后我们就得到了事件文件 rpc.etl 和使用 dcerpc 过滤后的 schtasks.pcapng

抓包

首先来看 schtasks.pcapng,显示了调用的过程:

  • 3 号包,Client 向 EndPoint Manager 查询希望使用的 RPC 接口的 UUID 为 86d35949-83c9-4044-b424-db363231fd0c,希望获得对应 RPC Server 运行的端口

    image-20221124101318594

  • 4 号包,EPM 回应,该 Server 运行在 TCP 19667

    image-20221124101532087

  • 5、6、7 号包,Client 连接指定的端口,并进行认证

    image-20221124101911309

  • 8 号包开始,Client 调用该接口的方法,可以看到 OpNum,即调用的方法在接口中的顺序。例如 8 号包中,OpNum 为 0,可知调用的是接口中的第一个方法,查询接口的定义(SchRpc.idl 或 在 RPC interfaces RS5 中搜索对应的接口)可知调用的 OpNum 为 0 的方法是 SchRpcHighestVersion,由名可知是个查询版本的方法。

    image-20221124102458354

附件的包可能由于过滤后保存的包不全的原因没有最后一个对 OpNum 为 1 的方法调用,在保存完整的包中可以看到,读者可自行实验。

ETW

第二种方式是使用 ETW,Microsoft-Windows-RPC中包含了 Provider 的定义,由于我们是做检测,是在服务端捕获日志,因此我们重点关心 Event ID 6,即 RpcServerCallStart,该事件包含了以下信息:

1
2
3
4
5
6
7
8
9
10
11
<template tid="RpcClientCallStartArgs_V1">
<data name="InterfaceUuid" inType="win:GUID"/>
<data name="ProcNum" inType="win:UInt32"/>
<data name="Protocol" inType="win:UInt32" map="ProtocolSequences"/>
<data name="NetworkAddress" inType="win:UnicodeString"/>
<data name="Endpoint" inType="win:UnicodeString"/>
<data name="Options" inType="win:UnicodeString"/>
<data name="AuthenticationLevel" inType="win:UInt32"/>
<data name="AuthenticationService" inType="win:UInt32" map="AuthenticationServices"/>
<data name="ImpersonationLevel" inType="win:UInt32"/>
</template>

可以看到其中包含了许多有效的信息,其中 ProcNum 就是抓包中的 OpNum。使用 Powershell 提取 rpc.etl 中的信息:

1
$events = Get-WinEvent -Path .\rpc.etl -Oldest

由于 Microsoft-Windows-RPC 会产生大量事件,我们只筛选出我们关心的事件,即 Event Id 为 6,UUID 为 86d35949-83c9-4044-b424-db363231fd0c,Protocol 为 1(TCP,数字与协议的对应关系为 1 - TCP,2 - NamedPipe,3 - ALPC),查看这些事件调用的方法(ProcNum):

1
2
3
4
5
6
7
8
9
> foreach($e in $events){
if($e.Id -eq 6 -and $e.Properties[0].Value -eq "86d35949-83c9-4044-b424-db363231fd0c" -and $e.Properties[2].Value -eq 1){
$e.Properties[1]}}

Value
-----
0
7
1

由此可知调用的顺序是 0(SchRpcHighestVersion),7(SchRpcEnumTasks),1(SchRpcRegisterTask)。其中最重要的是 SchRpcRegisterTask。因此进行检测时,调用 86d35949-83c9-4044-b424-db363231fd0c 接口 OpNum 为 1 的方法的行为即为注册计划任务的行为。

At

根据上面对 Schtasks 进行研究的过程进行总结,可以发现对于基于主机的检测来说,使用 ETW 是更好的方案,研究时也比较方便。在研究 At 时使用类似于 Schtasks 的 ETW 方法,具体过程略,结果是使用 At 添加计划任务时调用的是接口1FF70682-0A51-30E8-076D-740BE8CEE98BOpNum 为 0 的方法 NetrJobAdd。

检测服务创建

创建服务的常用方式包括 sc、wmi、psexec 等,研究方法也与 Schtasks 类似。与计划任务相比,服务创建这一部分体现了利用 RPC 进行检测的一个优势,即可以从更底层获得不同创建服务方式的共同点,从而帮助检测。创建服务时,Windows 使用的是另一个基于 RPC 的协议MS-SCMR Service Control Manager Remote Protocol

类似于计划任务,ETW Provider Microsoft-Windows-Service 也提供了服务相关的事件。但是该 Provider 不提供服务创建时的事件,可以与 RPC 结合判断。

SC

具体过程略,我们关注的还是 Microsoft-Windows-RPC 的 Event ID 为 6 的方法,同时我们在 MS-SCMR 协议中找到了接口定义,UUID 为 367ABB81-9844-35F1-AD32-98F038001003,据此我们可以得知调用函数的顺序:15(ROpenSCManagerW),12(RCreateServiceW),0(RCloseServiceHandle)。这其中最重要的一步应该是 12 CreateService。在查阅该接口时,发现还有一些其他的创建服务的函数,24 RCreateServiceA,44 RCreateServiceWOW64A,45 RCreateServiceWOW64W,这几个函数从函数名上就可以知道它们的不同,在检测服务创建行为时应该一并检测。

PsExec

PsExec 是 Sysinternals 中的工具,渗透中十分常用。基本原理是:首先将 PsExec.exe 通过文件共享发送到目标机器,然后启动服务,通过服务执行操作,最后删除服务。其与服务有关的操作也是通过同样的接口367ABB81-9844-35F1-AD32-98F038001003实现的,执行函数的顺序为 12 RCreateServiceW,29 RStartServiceW,1 RControlService,2 RDeleteService。可以看到 PsExec 与 Sc 使用了相同的接口和相同的方法(RCreateSeerviceW)。

另外一个特征是,Psexec 会比较快地执行上面四个步骤。

WMI

WMI 用于管理服务的类是 Win32_Service 类,该类有 Create 和 Start 方法用于创建和启动服务。有多种方式与 WMI 进行交互,实验时使用 Powershell。WMI 使用的协议是 MS-WMI

使用 Powershell 创建服务:

1
Invoke-CimMethod -ClassName Win32_Service -MethodName create -Arguments @{PathName=C:\Windows\System32\calc.exe; DisplayName=evilservice DesktopInteract=true; StartName="NT AUTHORITY\SYSTEM"; StartPassword=""; ErrorControl=3; LoadOrderGroup=""; LoadOrderGroupDependencies=""; Name=evilservice; ServiceDependencies=""; ServiceType=16; StartMode=Manual;} 

由于 WMI 包含的接口较多,Full IDL,找到其中用于执行 WMI 方法的接口和方法IWbemServices::ExecMethod,UUID 为 9556dc99-828c-11cf-a37e-00aa003240c7,可以看到 OpNum 为 21 即 ExecMethod 的方法。但受限于 RPC Provider 提供的信息不够,只知道执行了某个 WMI 类的某个方法,但并不能知道是哪个类的哪个方法。因此使用 RPC Provider 很难发现使用 WMI 创建服务的性行为。

对于 WMI 创建服务的行为,需要特定于 WMI 的监控方式来实现,或者仍使用 Microsoft-Windows-Services。

作者

lll

发布于

2022-11-24

更新于

2023-03-23

许可协议