TheWover/donut

GitHub: TheWover/donut

将 .NET 程序集、原生 PE 文件及脚本转换为位置无关 Shellcode,实现 Windows 载荷内存加载执行的开源安全研究工具。

Stars: 4482 | Forks: 733

[![Issues](https://img.shields.io/github/issues/thewover/donut)](https://github.com/TheWover/donut/issues) [![Contributors](https://img.shields.io/github/contributors/thewover/donut)](https://github.com/TheWover/donut/graphs/contributors) [![Stars](https://img.shields.io/github/stars/thewover/donut)](https://github.com/TheWover/donut/stargazers) [![Forks](https://img.shields.io/github/forks/thewover/donut)](https://github.com/TheWover/donut/network/members) [![License](https://img.shields.io/github/license/thewover/donut)](https://github.com/TheWover/donut/blob/master/LICENSE) [![Chat](https://img.shields.io/badge/chat-%23donut-orange)](https://bloodhoundgang.herokuapp.com/) [![Github All Releases](https://img.shields.io/github/downloads/thewover/donut/total.svg)](http://www.somsubhra.com/github-release-stats/?username=thewover&repository=donut) [![Twitter URL](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?original_referer=https://github.com/TheWover/donut&text=%23Donut+An+open-source+shellcode+generator+that+supports+in%2Dmemory+execution+of+VBS%2FJS%2FEXE%2FDLL+files:+https://github.com/TheWover/donut) ![Alt text](https://github.com/TheWover/donut/blob/master/img/donut_logo_white.jpg?raw=true "Donut Logo")

当前版本:v1.1

目录

  1. 简介
  2. 工作原理
  3. 构建
  4. 使用说明
  5. 子项目
  6. 使用 Donut 开发
  7. 问题与讨论
  8. 免责声明

1. 简介

Donut 是一个位置无关代码,能够实现 VBScript、JScript、EXE、DLL 文件和 dotNET 程序集的内存执行。由 Donut 创建的模块既可以从 HTTP 服务器进行分段加载,也可以直接嵌入到加载器本身。该模块可以选择使用 Chaskey 分组密码和 128 位随机生成的密钥进行加密。文件在内存中加载并执行后,原始引用会被擦除以阻止内存扫描器。生成器和加载器支持以下功能:

  • 使用 aPLib 和 LZNT1、Xpress、Xpress Huffman 通过 RtlCompressBuffer 压缩输入文件。
  • 利用熵生成 API 哈希和字符串。
  • 文件的 128 位对称加密。
  • 覆盖原生 PE 头。
  • 将原生 PE 存储在 MEM_IMAGE 内存中。
  • 修补反恶意软件扫描接口 (AMSI) 和 Windows 锁定策略 (WLDP)。
  • 修补 Windows 事件跟踪 (ETW)。
  • 修补 EXE 文件的命令行。
  • 修补退出相关的 API 以避免终止宿主进程。
  • 多种输出格式:C、Ruby、Python、PowerShell、Base64、C#、Hexadecimal 和 UUID 字符串。

Linux 和 Windows 都有动态和静态库,可以集成到你自己的项目中。还有一个 Python 模块,你可以在 构建和使用 Python 扩展 中了解更多信息。

2. 工作原理

Donut 为每种支持的文件类型包含独立的加载器。对于 dotNET EXE/DLL 程序集,Donut 使用非托管 CLR 托管 API 来加载公共语言运行时。一旦 CLR 加载到宿主进程中,就会创建一个新的应用程序域,以便在可释放的 AppDomain 中运行程序集。当 AppDomain 准备就绪时,dotNET 程序集通过 AppDomain.Load_3 方法加载。最后,用户指定的 EXE 入口点或 DLL 公共方法将附带任何额外参数被调用。有关 非托管 CLR 托管 API 的文档,请参阅 MSDN。有关 CLR 宿主的独立示例,请参阅 此处代码

VBScript 和 JScript 文件使用 IActiveScript 接口执行。还对 Windows Script Host (wscript/cscript) 提供的某些方法提供了最低限度的支持。有关独立示例,请参阅 此处代码。有关更详细的描述,请阅读:JavaScript、VBScript、JScript 和 XSL 的内存执行

非托管或原生 EXE/DLL 文件使用自定义 PE 加载器执行,支持延迟导入、TLS 和修补命令行。仅支持具有重定位信息的文件。阅读 DLL 的内存执行 了解更多信息。

加载器可以禁用 AMSI 和 WLDP,以帮助逃避对内存中执行的恶意文件的检测。欲了解更多信息,请阅读 红队如何绕过 .NET 动态代码的 AMSI 和 WLDP。它还支持使用 aPLib 或 RtlDecompressBuffer API 在内存中解压文件。阅读 数据压缩 了解更多信息。

自 v1.0 起,ETW 也被绕过。与 AMSI/WLDP 一样,这是一个模块化系统,允许你用自己的绕过方法替换默认的。默认绕过源自 XPN 的研究。阅读 隐藏你的 .NET - ETW 了解更多信息。

默认情况下,加载器将覆盖非托管 PE 的 PE 头(从基址到 `IMAGE_OPTIONAL_HEADER.SizeOfHeaders`)。如果未使用诱饵模块(模块重载),则 PE 头将被清零。如果使用了诱饵模块,则诱饵模块的 PE 头将用于覆盖有效载荷模块的 PE 头。这是为了通过比较内存中模块的 PE 头与磁盘上支持它们的文件来阻止检测。用户可以请求将所有 PE 头保留在其原始状态。这对于有效载荷模块需要访问其 PE 头的场景很有帮助,例如查找嵌入式 PE 资源时。

有关使用生成器的详细演示以及 Donut 如何影响战术技术,请阅读 Donut - 将 .NET 程序集作为 Shellcode 注入。有关加载器的更多信息,请阅读 从内存加载 .NET 程序集

希望了解更多内部细节的人应参考 开发者说明

3. 构建

有两种类型的构建。如果你想调试 Donut,请参考 此处的文档。如果不需要,请继续阅读有关发布版构建的内容。

克隆

从 Windows 命令提示符或 Linux 终端克隆仓库。

 

  git clone http://github.com/thewover/donut.git

下一步取决于你的操作系统和你决定使用的编译器。目前,Donut 的生成器和加载器模板可以使用 Microsoft Visual Studio 2019 和 MinGW-64 成功编译。要在你自己的 C/C++ 项目中使用这些库,请参考 此处提供的示例

Windows

要生成加载器模板、动态库 donut.dll、静态库 donut.lib 和生成器 donut.exe。启动 x64 Microsoft Visual Studio 开发人员命令提示符,切换到克隆 Donut 仓库的目录并输入以下内容:


  nmake -f Makefile.msvc

若要在 Windows 或 Linux 上使用 MinGW-64 执行相同操作,请切换到克隆 Donut 仓库的目录并输入以下内容:


  make -f Makefile.mingw

Linux

要生成动态库 donut.so、静态库 donut.a 和生成器 donut。切换到克隆 Donut 仓库的目录并简单地输入 make。

Python 模块

Donut 可以作为 Python 模块安装和使用。要从源代码安装需要 Python3 的 pip。首先,通过在 Linux 终端或 Microsoft Visual Studio 命令提示符中发出以下命令,确保未安装旧版本的 donut-shellcode。


  pip3 uninstall donut-shellcode

确认不再安装旧版本后,发出以下命令。


  pip3 install .

你也可以通过从 PyPi 仓库获取来将 Donut 安装为 Python 模块。


  pip3 install donut-shellcode

欲了解更多信息,请参阅 构建和使用 Python 扩展

Docker

构建 Docker 容器。


  docker build -t donut .

运行 Donut。


  docker run -it --rm -v "${PWD}:/workdir" donut -h

支持工具

Donut 包含其他几个可以单独构建的可执行文件。包括 "hash.exe"、"encrypt.exe"、"inject.exe" 和 "inject_local.exe"。前两个用于 shellcode 生成。后两个用于协助测试 donut shellcode。"inject.exe" 会通过 PID 或进程名将原始二进制文件 (loader.bin) 注入到进程中。"inject_local.exe" 会将原始二进制文件注入到其自己的进程中。

要单独构建这些支持可执行文件,你可以使用 MSVC makefile。例如,要构建 "inject_local.exe" 来测试你的 donut shellcode,你可以运行。


  nmake inject_local -f Makefile.msvc

发布版本

Donut 的每个发布版本都提供了包含已编译可执行文件的标签。

目前,还有两个可用的生成器。

4. 使用说明

下表列出了命令行版本生成器支持的开关。

开关 参数 描述
-a 加载器的目标架构 : 1=x86, 2=amd64, 3=x86+amd64(默认)。
-b level 绕过 AMSI/WLDP 的行为 : 1=无, 2=失败时中止, 3=失败时继续(默认)
-k headers 保留 PE 头。1=覆盖 (默认), 2=全部保留
-j decoy 用于模块重载的诱饵模块的可选路径。
-c class 可选的类名。(.NET DLL 必需)也可以包括命名空间:例如 namespace.class
-d name 为 .NET 创建的 AppDomain 名称。如果启用了熵,则会随机生成一个。
-e level 熵级别。1=无, 2=生成随机名称, 3=生成随机名称 + 使用对称加密 (默认)
-f format 加载器保存到文件的输出格式。1=二进制 (默认), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=PowerShell, 7=C#, 8=十六进制
-m name DLL 的可选方法或函数。(.NET DLL 需要一个方法)
-n name HTTP 分段加载的模块名称。如果启用了熵,则会随机生成一个。
-o path 指定 Donut 应在何处保存加载器。默认为当前目录下的 "loader.bin"。
-p parameters DLL 方法/函数或 EXE 的可选参数/命令行,需在引号内。
-r version CLR 运行时版本。默认使用 MetaHeader,如果不可用则使用 v4.0.30319。
-s server 将托管 Donut 模块的 HTTP 服务器的 URL。凭证可以按以下格式提供:
https://username:password@192.168.0.1/
-t 作为线程运行非托管/原生 EXE 的入口点并等待线程结束。
-w 命令行以 UNICODE 格式传递给非托管 DLL 函数。(默认为 ANSI)
-x option 确定加载器应如何退出。1=退出线程 (默认), 2=退出进程, 3=不退出或清理并无限期阻塞
-y addr 为加载器创建一个新线程,并在相对于宿主进程可执行文件的偏移地址处继续执行。提供的值即为偏移量。此选项支持希望在本 Donut 执行完成后恢复宿主进程执行的加载器。
-z engine 打包/压缩输入文件。1=无, 2=aPLib, 3=LZNT1, 4=Xpress, 5=Xpress Huffman。目前,后三者仅在 Windows 上受支持。

Payload Requirements

你的 Payload 必须满足一些特定要求 Donut 才能成功加载它。

.NET Assemblies

  • 入口点方法必须仅接受字符串作为参数,或不接受参数。
  • 入口点方法必须标记为 public 和 static。
  • 包含入口点方法的类必须标记为 public。
  • 程序集不得是混合程序集(同时包含托管和非托管代码)。
  • 因此,程序集不得包含任何非托管导出。

Native EXE/DLL

  • 不支持使用 Cygwin 构建的二进制文件。

Cygwin 可执行文件使用的初始化例程期望宿主进程从磁盘运行。如果从内存执行,宿主进程很可能会崩溃。

Unmanaged DLLs

  • 用户指定的入口点方法必须仅接受字符串作为参数,或不接受参数。我们提供了一个 示例

5. 子项目

Donut 提供了四个配套项目:

工具 描述
DemoCreateProcess 用于测试的示例 .NET 程序集。接受两个命令行参数,每个参数指定一个要执行的程序。
DonutTest 用于测试 Donut 的简单 C# shellcode 注入器。Shellcode 必须经过 base64 编码并作为字符串复制进去。
ModuleMonitor 概念验证工具,用于检测由 Donut 和 Cobalt Strike 的 execute-assembly 等工具进行的 CLR 注入。
ProcessManager 进程发现工具,攻击性操作员可用其确定注入目标,防御性操作员可用其确定正在运行的进程、这些进程的属性以及它们是否加载了 CLR。

6. 使用 Donut 开发

你可能希望添加对更多类型 Payload 的支持、更改我们的功能集,或将 Donut 集成到你现有的工具中。我们提供了 开发者文档。其他功能留作读者的练习。我们的建议:

  • 添加环境密钥。
  • 通过在每次生成 shellcode 时混淆加载器,使 Donut 具有多态性。
  • 将 Donut 作为模块集成到你最喜欢的 RAT/C2 框架中。

7. 问题与讨论

如果你对 Donut 有任何问题或评论。请加入 BloodHound Gang Slack 中的 #Donut 频道

8. 免责声明

我们不对本软件或技术的任何误用负责。Donut 作为 CLR 注入和通过 shellcode 进行内存加载的演示提供,旨在为红队提供一种模拟对手的方法,并为防御者提供构建分析和缓解措施的参考框架。这不可避免地会带来恶意软件作者和威胁行为者滥用的风险。然而,我们相信净收益大于风险。希望这是正确的。如果 EDR 或 AV 产品能够通过签名或行为模式检测到 Donut,我们将不会更新 Donut 以对抗签名或检测方法。为避免冒犯,请勿询问。

标签:AMD64, AV 规避, DNS 反向解析, Donut, EDR 规避, Hakrawler, meg, .NET Assembly, Payload 生成, PE 加载, Shellcode, Shellcode 生成, UML, x64, x86, 中高交互蜜罐, 位置无关代码, 信息安全, 内存加载, 安全测试, 客户端加密, 恶意软件开发, 技术调研, 攻击性安全, 数据展示, 知识库安全, 端点可见性, 红队, 请求拦截, 逆向工具