DropSpawn 是一个 CobaltStrike BOF,用于通过一种相对不为人知的 DLL 劫持方法来生成额外的 Beacon。支持 x86-x86、x64-x64 以及 x86-x64/反向组合。可作为进程注入的替代方案使用。
Windows 可执行文件在加载未指定绝对路径的 DLL 时会遵循 DLL 搜索顺序:

DLL 劫持通常需要满足以下任一条件:
A. 用户在某个文件夹中拥有写入权限,且该文件夹的搜索顺序优先级高于真实 DLL 所在的文件夹
或
B. 目标 DLL 在系统上不存在,此时可以将其放置在用户 %PATH% 变量中可写的文件夹内(例如 %USERPROFILE%\appdata\local\microsoft\windowsapps)。
这些要求排除了对位于 C:\Windows\System32 中的可执行文件进行 DLL 劫持的可能性,因为这些可执行文件加载的几乎所有 DLL 也都位于 System32 中。将 System32 可执行文件复制到用户可写的位置并从中执行是一种选择,但 OPSEC 安全性不高,因为从其他位置运行的 System32 二进制文件很容易被识别。
DropSpawn 通过将“应用程序加载目录”伪装为任意用户指定的目录,实现了对 System32 可执行文件(以及其他位于非用户可写文件夹中的可执行文件)的 DLL 劫持。
DropSpawn 的公开版本与非公开版本略有不同。非公开版本利用专有的载荷生成器,为操作员提供了更加无缝的体验。公开版本经过略微修改,以适应用户将使用自己的方式来生成兼容 DLL 劫持的载荷这一事实。已包含一个 Python3 脚本以及一个演示 DLL 的源代码,以帮助用户集成和使用 dropspawn。
识别一些尝试加载 DLL 但未指定其绝对路径的目标可执行文件。你可以通过将 exe 复制到用户可写目录并在使用 Procmon 监控的同时执行它来完成此操作。在此示例中,我们将使用通常位于 C:\Windows\System32\WerFault.exe 的 WerFault.exe

在上述示例中,cryptsp.dll、wer.dll、dbghelp.dll 和 bcrypt.dll 都是可行的候选对象,因为 WerFault 中未指定它们的绝对路径;因此,WerFault 将首先尝试从其应用程序目录加载它们,然后再使用其余的 DLL 搜索顺序。请注意,这通常不是问题,因为 WerFault 的应用程序目录就是 System32。
从目标系统下载其中一个可劫持的 DLL。
这是必要的,以便我们可以提取其导出函数并将其包含在我们的载荷 DLL 中。重要的是从你希望使用 DropSpawn 的同一台机器上获取可劫持的 DLL,因为 DLL 会随 Windows 版本而变化。此外,如果你正在运行 x86 beacon 并希望使用 DropSpawn 生成 x64 beacon,请确保通过指定 'C:\windows\sysnative...' 而不是 'C:\windows\system32...' 来下载真实 DLL 的 x64 版本。
运行 generate_dll.py,传入下载的 DLL 和所需的载荷架构。Generate_dll.py 是此脚本的修改版本。它将解析提供的 DLL,创建一个包含 DLL 导出函数的 .def 文件,并调用 MingW 来编译我们的演示载荷 DLL。当被生成的进程尝试调用伪装 DLL 中的真实函数时,我们的载荷 DLL 会将调用转发到位于 System32 中的真实 DLL,以便宿主进程不会崩溃。

使用生成的载荷 DLL 调用 dropspawn。
dropspawn <载荷 DLL> <x86|x64> <要生成的程序> [可写目标文件夹] [父进程]
载荷 DLL - 生成的 DLL 载荷的完整路径。 架构 - 你希望生成的进程的架构 要生成的程序 - 你希望生成的进程的名称/路径。如果此进程位于 System32(或 syswow64)中,你可以仅指定名称。否则,请指定完整路径。你还可以向进程提供命令行参数。如果路径中包含空格/或使用参数,请将整个内容用引号括起来。 可写目标文件夹 - 可选。如果留空,dropspawn 将尝试使用 Beacon 的当前目录。如果路径中有空格,请使用引号。 父进程 - 可选。用于对新建进程进行 PPID 欺骗的进程名称。如果指定的进程有多个不同权限级别的运行实例(例如 svchost.exe),dropspawn 将尝试识别一个可用于 PPID 欺骗的实例。
示例:dropspawn /root/dbgcore.dll x64 "WerFault.exe -u -p 4352 -s 160" C:\users\user\appdata\local\temp explorer.exe
这将把载荷 DLL 'dbgcore.dll' 写入磁盘上的 'c:\users\user\appdata\local\temp\dbgcore.dll',并生成一个带有命令行参数 '-u -p 4352 -s 160' 的 x64 WerFault.exe 进程,以 explorer.exe 作为父进程。


清理很简单。通过在写入磁盘的载荷 DLL 中包含自删除功能,它将在我们的新进程生成并加载它后立即被删除。这是一个重大改进,因为通常情况下,只要加载了 DLL 的进程继续运行,DLL 就会被锁定在磁盘上。如果自删除技术因某种原因失败(或进程无法生成),DropSpawn 将尝试从磁盘删除载荷 DLL,并无论操作结果如何都会告知用户。
进程注入通常遵循打开远程进程 -> 分配远程内存 -> 写入远程内存 -> 执行远程内存的链条,并可以选择在开始时生成一个新进程而不是使用现有进程。DropSpawn 仅创建新进程;新生成的进程负责分配、写入和执行 shellcode,因此我们可以避免许多通常与远程进程注入相关的 IOC。
当然,这种技术的好坏取决于你的 DLL 载荷的质量。但我们可以看看 Windows 看到了什么(下一节使用 DropSpawn 的私有版本并生成 Beacon)。
就事件查看器而言,一切看起来都很正常:

在 MDE 中几乎看不到什么。
运行 dropspawn:

MDE 日志:
使用 PPID 欺骗:

不使用 PPID 欺骗:

在两种情况下,我们都能看到我们原始的 beacon 进程(也是一个 werfault)将 dbgcore.dll 写入磁盘,创建一个新的 WerFault.exe 进程,新生成的进程加载 dbgcore.dll,然后重命名(删除)它。关键的是,dbgcore.dll 没有受到通常伴随 DLL 劫持而来的额外审查,因为我们没有将其写入任何经常被劫持的位置,而且 WerFault.exe(或你选择使用的任何进程)与 DLL 劫持的关联程度不像 WmiPrvSE.exe 等那样高。
有趣的是,使用 PPID 欺骗执行此操作几乎比不使用更显眼。然而,这可能因安全产品而异。
如前所述,用户必须从他们计划使用 DropSpawn 的目标机器上下载真实的 DLL。使用错误版本的 DLL 可能导致生成的进程在尝试调用不存在的函数时崩溃。
DropSpawn 可用于 System32 之外的可执行文件;但请注意,如果进程尝试从进程的真实应用程序目录加载其他 DLL,可能会出现一些问题。由于我们已经将应用程序目录伪装到其他地方,如果真实应用程序目录无法通过 DLL 搜索顺序以其他方式访问,进程将因无法定位必要的 DLL 而崩溃/无法启动。在生产环境中使用之前,请务必在开发机器上测试潜在的劫持!
这项研究最初源于我探索进程如何组装其最终的 DLL 搜索顺序(由于可执行文件位于不同目录、当前目录是搜索路径的一部分等原因,必须在运行时确定)。我的研究引导我找到了这个论坛帖子,它是该技术核心的两个关键未文档化 API 的起源。
前面已经链接过,但这篇关于避免加载程序锁的文章、这个用于生成 DLL 代理 .def 文件的脚本以及这项关于启用运行中可执行文件自删除的研究对于生成适合 DropSpawn 的有效、武器化的 DLL 载荷至关重要。
当我首次在Twitter上发布这项技术时,其他几个人也加入了讨论并制作了 POC。SecurityAndStuff 制作了这个,而 Snovvcrash 的在这里