安全团队经常通过对父子进程间关系的检测来判断该进程是否存在异常,但是,很多攻击者可以使用Parent PID (PPID) Spoofing这一技术来绕过检测,并允许从任意父进程执行恶意进程。该技术在Cobalt Strike和Didier Stevens等活动中被使用。
在这篇博客中,我们会深入探讨此技术的工作原理以及防御者如何利用ETW(Windows事件跟踪)检测此技术。我们还将演示如何通过PowerShell脚本执行Parent PID (PPID) Spoofing和DLL注入,以及python编写的检测脚本,该脚本使用了pywintrace库。
在过去,攻击者经常能在不被检测到的情况下通过网络,但随着EDR(Endpoint detection and response,终端检测和响应)的增加和威胁检测的提升,这种情况出现转变,尤其是对父子进程关联关系的分析,更是成为了检测攻击链的常用技术。
我们在Countercept(英格兰伦敦的计算机安全服务)中使用了父子进程关联关系的分析,下面是一些例子:
1.Macro payload delivery – WinWord spawning processes(宏交互过程)
2.JS/VBS C# payload delivery – cscript spawning csc(JS/VBS交互过程)
3.Lateral movement – services/wmiprvse spawning new processes(服务交互过程)
这促使攻击者重新评估他们的攻击方法,并使用诸如Parent PID (PPID) Spoofing等技术,以绕过防御。
对父进程进行欺骗有许多方法,本文中着重介绍通过调用CreateProcessA函数进行实现,该方法最简单也最常用。
CreateProcessA函数允许用户创建新进程,默认情况下,会通过其继承的父进程完成创建。该函数有一个名为“lpStartupInfo”的参数,该参数允许使用者自定义要使用的父进程。该功能最初用于Windows Vista中设置UAC。
lpStartupInfo参数指向一个名为“STARTUPINFOEX”的结构体,该结构包含变量“lpAttributeList”,这个变量在初始化时可以调用“UpdateProcThreadAttribute”回调函数进行属性添加,你可以通过“PROC_THREAD_ATTRIBUTE_PARENT_PROCESS”属性从而对父进程进行设置。
另外,此方法也可用于权限提升,Adam Chester有一个博客,演示了如何利用该方法进行Windows系统权限获取:Alternative methods of becoming SYSTEM。
现在最常见的网络传播方式是利用带有恶意宏的文档,当宏触发后,通常会启用新的进程,例如:cmd, PowerShell, regsvr32 和 certutil等,下图显示了winword进程生成rundll32进程的实例。然而,这种行为通常很容易被检测到。
攻击者可以通过CreateProcessA函数,实现以预期的父进程(比如Explorer或cmd)启动有效负载。下图显示了该技术的调用过程。
但是,我们能够进一步避免使用Windows中常见的应用程序吗?其中的一种方法是使用DLL文件或内存注入来加载想要运行的有效负载。
为了说明该情况,我们创建了一个PowerShell脚本,该脚本基于Didier Stevens的代码,该脚本可以进行父进程欺骗并在其中注入一个DLL。
如下图所示,我们可以看到Windows 10上的正常进程“svchost.exe”,它启动了一个进程“RuntimeBroker.exe” 。
运行我们的PowerShell脚本后,我们同样从“svchost.exe”生成合法的“RuntimeBroker.exe”进程,然后注入并执行DLL有效载荷。如下图所示:
此类技术可以绕过父子关系的检测规则。
在上一节中,我们演示了通过CreateProcessA函数进行父进程欺骗的方法,如果你使用任务管理器或 Process Explorer(进程查看工具)可以看到正在运行的进程,以及欺骗的进程,但却没办法找出真正的进程ID。
ETW(Event Tracing for Windows,windows事件跟踪)是Windows中最好的取证工具之一,ETW提供系统上发生的实时数据流。尤其是Microsoft-Windows-Kernel-Process模式提供了一些信息,可以帮助我们检测进程欺骗。如下图所示,你可以观察到如何从“winword.exe”(PID 9224)生成“rundll32.exe”(PID 5180):
如下图所示,查看ETW数据,你可以看到多个ProcessId字段,包括EventHeader ProcessId,actual event ProcessID和ParentProcessID,通过阅读MSDN文档,我们发现EventHeader ProcessId标识了生成事件的进程—即父进程。
在这个例子中,我们可以观察到EventHeader ProcessId和ParentProcessId正确匹配。
在第二个事例中,我们执行了恶意的PowerShell脚本,并从“svchost.exe”(PID 4652)生成了“RuntimeBroker.exe”(PID 4976)进程。如下图所示:
如下图所示,我们从ETW观察到,这次的EventHeader ProcessId和ParentProcessID是不同的,实际上,EventHeader ProcessId显示真正的父ID,即“winword.exe” (PID 9224)。
然而,事情远非那么简单,如果你试图大规模的通过此方法进行检测,可能会出现误报情况,常见的例子是UAC(用户账户控制),该工具用于提升进程权限。在Windows 10中,当UAC执行后,应用程序信息服务(通过svchost)启动被提升权限的进程,但随后会显示该进程的原始调用进程。如下图所示,被提升权限的进程cmd.exe显示explorer.exe为父进程,实际父进程为svchost.exe。
另外一个误报相关的例子发生于WerFault的崩溃处理。如下图所示,当MicrosoftEdge崩溃时,svchost会启动WerFault.exe,但其父进程显示为MicrosoftEdge.exe。
我们创建了一个python脚本,该脚本使用pywintrace记录来自ETW的事件,然后通过比较PID,对一些事件进行过滤,以消除误报情况,如下图所示:
PowerShell脚本的代码以及检测脚本可以在Github找到。
在本文中,我们演示了攻击者如何利用合法的Windows功能进行欺骗,绕过父子进程关系相关检测的技术。
从防御的角度,我们也展示了如何通过ETW事件分析检测真正的父进程,这项研究表明,防御者必须突破当前界限,始终领先于攻击者一步。