ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Sliver 植入体中 go-clr 库版本演进全解析:从 v1.0.0 到 v1.0.3 的 CLR 托管能力变迁

Sliver 植入体中 go-clr 库版本演进全解析:从 v1.0.0 到 v1.0.3 的 CLR 托管能力变迁 网络安全【免费下载链接】sliverAdversary Emulation Framework项目地址https://gitcode.com/gh_mirrors/sl/sliver点击查看免费下载本篇技术指南围绕随 Sliver 植入体源码一并 vendored 的第三方依赖 go-clr 变更日志 展开完整梳理该库四个已发布版本v1.0.0 ~ v1.0.3的每一次变更背景并结合仓库内 go-clr 源码接口封装、STDOUT/STDERR 重定向、HRESULT 处理与 Sliver 植入体在taskrunner中的实际集成调用链说明这些版本演进如何影响 Windows 端进程内 .NET 程序集执行能力。读完本文你将掌握 go-clr 各版本核心修复的底层原理以及 Sliver 如何通过LoadCLR/LoadAssembly/InvokeAssembly组合复用它执行内存中的 .NET 程序集。一、go-clr 是什么为什么它出现在 Sliver 仓库中go-clr 是一个用纯 Go 编写的 PoC 级库目标是在 Go 进程内托管 CLRCommon Language Runtime从而直接从磁盘加载 .NET DLL或从内存加载 .NET 程序集assembly并执行。它的实现方式是不依赖 cgo而是通过封装 Windows 系统调用syscall与大量unsafe.Pointer操作从内存中按 COM 接口 vtable 布局装载结构体逐一调用ICLRMetaHost、ICLRRuntimeInfo、ICORRuntimeHost等托管宿主接口。该库以 vendored 依赖的形式被固定在 Sliver 仓库中目录 implant/vendor/github.com/Ne0nd0g/go-clr并在植入体侧的 dotnet_windows.go 中被显式导入使用其角色是支撑 Windows 植入体执行execute-assembly类任务。其自述文档README.md也坦诚说明这是实验性 PoC大量使用unsafe并非生产级稳定代码但作为攻防对抗Adversary Emulation框架的进程内 .NET 执行组件其价值在于完全用 Go 复刻了 CLR 托管的关键路径。二、版本 1.0.02021-04-08从 fork 出发的初始标签版变更日志对本版本的描述是Initial tagged version from forked——即从上游 fork 后打出的第一个正式标签。2.1 新增STDOUT/STDERR 重定向缓冲本版本最重要的新增特性被明确记录为Added buffer to collect redirected STDOUT/STDERR新增缓冲区以收集重定向后的 STDOUT/STDERR。这一能力在今天的源码中依然保留构成了 io.go 的核心包级声明了Stdout、Stderr两个bytes.Buffer见 io.go以及用于串行化读写的mutexRedirectStdoutStderr()通过os.Pipe()分别为 STDOUT/STDERR 创建新的读写文件句柄再用windows.SetStdHandle将STD_OUTPUT_HANDLE与STD_ERROR_HANDLE指向新句柄见 io.go随后启动BufferStdout()/BufferStderr()两个 goroutine以 4KB 缓冲区循环读取管道内容并调用bytes.TrimRight(buf, \x00)剔除空字节后写入Stdout/Stderr缓冲见 io.go。之所以必须重定向原因在代码注释中写得很清楚CLR 执行托管程序集时运行在 Go 进程之外无法用普通的 Go 方式捕获输出因此只能把进程级句柄换掉再收回来。这一点正是 C2 框架需要拿到程序集输出并回传的关键机制Sliver 正是这一设计的直接受益者。三、版本 1.0.12021-04-08标签与导入路径的修正变更日志用一句带过Learned how to correctly use tags and updated import学会正确使用标签并更新了导入路径。从仓库现状可以印证这次修正的结果项目模块从github.com/ropnop/go-clr迁至github.com/Ne0nd0g/go-clrREADME 中的安装示例使用go get github.com/ropnop/go-clr而 Sliver 的导入语句已是clr github.com/Ne0nd0g/go-clr见 dotnet_windows.go模块元数据在 implant/go-mod 与 implant/go-sum 中记录为github.com/Ne0nd0g/go-clr该版本同日发布与 v1.0.0 在同一天说明这是对初版标签的快速修正而不是功能性迭代。对使用者而言这个版本变化意味着导入路径从原作者 fork 的仓库切换到了维护者的新仓库Sliver 仓库内记录的正是修正后的版本路径。四、版本 1.0.22022-04-02目标程序集加载修复与依赖升级本版本有两项变更4.1 修复正确加载目标程序集变更日志记录合并了来自 audibleblink 的 Pull 2fixed an error when attempting to load correctly targeted assemblies修复了尝试加载正确目标程序集时出现的错误。结合源码可以理解这项修复对应的执行路径。程序集从字节数组加载的完整链路位于 go-clr.go 的ExecuteByteArray中通过CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost)创建 metahost调用GetInstalledRuntimes枚举已安装运行时并按目标版本筛选如v4取得ICLRRuntimeInfo后调用IsLoadable()校验可加载性取得ICORRuntimeHost并获取默认 AppDomain将原始字节构造为 SafeArrayCreateSafeArray调用appDomain.Load_3(safeArrayPtr)从内存加载程序集通过assembly.GetEntryPoint()取入口方法再依据方法签名是否接收参数来决定是否用PrepareParameters构造参数 SafeArray最后methodInfo.Invoke_3执行。任何一步的 HRESULT 非零都会返回错误——v1.0.2 的修复正是针对加载到的程序集并非调用方所期望的目标程序集这类寻址/加载问题确保Load_3与后续入口点解析能命中正确的程序集映像。4.2 变更升级支撑 Go 模块同步更新了所依赖的 Go 模块版本。仓库内 hresult.go 依赖golang.org/x/sys/windowsio.go 中大量使用其句柄与 DLL 函数这类基础设施模块的升级通常伴随接口签名或常量定义的同步更新也是该版本Change而非Fix的原因。五、版本 1.0.32022-11-10错误处理与无控制台输出两大修复这是变更日志中记录的最新一个版本包含一次行为变更和一次缺陷修复也是 Sliver 仓库 vendored 到的版本。5.1 行为变更返回错误而非直接退出程序合并自 mec07 的 Pull 3return errors instead of exiting the program返回错误而非直接退出程序。这一变更把库的失败模式从进程级os.Exit改为函数级返回 error对库的宿主尤其是 C2 植入体至关重要——如果 .NET 程序集执行失败就令整个植入体进程退出后果是灾难性的。从当前源码看这一设计已贯穿所有对外 APIExecuteDLLFromDisk在ExecuteInDefaultAppDomain返回非零值时会返回the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned a non-zero return value: %d错误见 go-clr.goLoadCLR对运行时枚举失败返回包装错误见 go-clr.goInvokeAssembly在执行出错时仍继续读取重定向缓冲区并返回 stdout/stderr注释明确Dont return because there could be data on STDOUT/STDERR见 go-clr.go。5.2 缺陷修复无控制台应用无法返回输出对应 Issue 4 ——Applications Without A Console Will Not Return Output无控制台的应用程序不会返回输出。该问题的根因与修复逻辑完全保留在 io.go 中kernel32 : windows.NewLazySystemDLL(kernel32.dll) getConsoleWindow : kernel32.NewProc(GetConsoleWindow) // Ensure the process has a console because if it doesnt there will be no output to capture hConsole, _, _ : getConsoleWindow.Call() if hConsole 0 { // https://learn.microsoft.com/en-us/windows/console/allocconsole allocConsole : kernel32.NewProc(AllocConsole) ret, _, err : allocConsole.Call() if ret 0 { return fmt.Errorf(there was an error calling kernel32!AllocConsole with return code %d: %s, ret, err) } // Get a handle to the newly created/allocated console hConsole, _, _ getConsoleWindow.Call() // Hide the console window user32 : windows.NewLazySystemDLL(user32.dll) showWindow : user32.NewProc(ShowWindow) ret, _, err showWindow.Call(hConsole, windows.SW_HIDE) ... }修复逻辑分三步先用GetConsoleWindow探测当前进程是否有控制台若没有hConsole 0典型场景即 C2 植入体这种无控制台的 GUI/服务进程则调用AllocConsole分配一个隐藏控制台再用ShowWindow(..., SW_HIDE)将其隐藏最后才执行SetStdHandle重定向。这一步顺序非常关键重定向到管道的前提是进程存在可写的标准输出设备没有控制台时重定向无从谈起。代码注释还记录了一个容易踩的坑被重定向的 STDOUT 写入端一旦被关闭后续的Invoke_3会触发COR_E_TARGETINVOCATION0x80131604定义见 hresult.go因此缓冲读取采用永不关闭写入端、依赖 goroutine 持续读管道的模式。六、Sliver 侧的真实消费方式从版本能力到实战链路go-clr 的 API 在 Sliver 植入体中被组织成单例 CLR 程序集缓存的使用模式见 dotnet_windows.goCLRInstance结构体持有一个*clr.ICORRuntimeHost与sync.Mutex通过GetRuntimeHost懒加载首次调用时执行clr.LoadCLR(runtime)并在失败时尽力clr.RedirectStdoutStderr()见 dotnet_windows.goLoadAssembly(data, assemblyArgs, runtime)先按sha256.Sum256计算程序集哈希并查询assemblies缓存未命中才调用clr.LoadAssembly(rtHost, data)加载随后统一走clr.InvokeAssembly(methodInfo, assemblyArgs)执行见 dotnet_windows.go一个细节处理当参数为[]时会改写为[ ]因为空字符串切片会让 CLR 加载器去匹配无参方法导致Main(String[] args)无法命中见 dotnet_windows.go。再往上task_windows.go 的InProcExecuteAssembly在调用LoadAssembly前还会视开关执行 AMSI 补丁patchAmsi与 ETW 补丁patchEtw形成完整的进程内 execute-assembly链路。可以说go-clr 各版本积累的错误返回、无控制台输出捕获、目标程序集加载修复最终都转化为 Sliver Windows 植入体执行 .NET 程序集时的稳定性和可观测性。七、版本采纳与升级建议当前 Sliver 仓库 vendored 的 go-clr 即为变更日志中的最新版v1.0.32022-11-10可通过 modules.txt 与 go-sum 核实其精确依赖版本。结合各版本变更点可以得出以下采纳要点版本日期核心变更对 Sliver 类宿主的意义v1.0.02021-04-08fork 初始标签新增 STDOUT/STDERR 重定向缓冲奠定进程内输出捕获基础v1.0.12021-04-08修正标签与导入路径导入路径固定为github.com/Ne0nd0g/go-clrv1.0.22022-04-02修复目标程序集加载升级 Go 模块提升从内存加载程序集的命中准确性v1.0.32022-11-10错误返回替代进程退出修复无控制台输出丢失植入体健壮性与输出完整性的关键版本在将 go-clr 集成进长驻进程如 C2 植入体时应从 v1.0.3 起步它保证 .NET 执行失败不会拖垮宿主进程且为无控制台进程补齐了AllocConsole 隐藏窗口的兜底路径。同时需要注意其 PoC 定位——代码大量依赖unsafe与 COM vtable 手动布局如ICLRRuntimeInfoVtbl的逐方法指针定义见 iclrruntimeinfo.go在引入生产环境前应充分评估其稳定性边界并在植入体侧如 Sliver 所做的那样以互斥锁、程序集缓存与独立的 stdout/stderr 缓冲来隔离其不确定性。赞分享网络安全【免费下载链接】sliverAdversary Emulation Framework项目地址https://gitcode.com/gh_mirrors/sl/sliver点击查看免费下载相关推荐从 v1.0.0 到 v1.0.3Sliver 内置 go-clr 库的版本演进与 .NET 内存执行实现解析从 v1.0.0 到 v1.0.3Sliver 内置 go clr 库的版本演进与 .NET 内存执行实现解析 本文以 Sliver 仓库中内置的 githu网络安全Podman 中的 go-zfs 库演进全解析从 v1.0.0 到 v3.0.0 的 ZFS 管理能力变迁Podman 中的 go zfs 库演进全解析从 v1.0.0 到 v3.0.0 的 ZFS 管理能力变迁 go zfs github.com/mistif容器运行时云原生CLI深入 go-clr在 Go 进程中托管 .NET CLR 并执行 DLL 与内存程序集的技术剖析深入 go clr在 Go 进程中托管 .NET CLR 并执行 DLL 与内存程序集的技术剖析 本文基于 Sliver 仓库内 vendored 的 git网络安全创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表