前言
.NET Profiling 是一组用于开发性能分析工具的接口,用于监控和分析 .NET 应用程序的各种行为。近日,有研究员将该项技术用于横向移动,本文主要对此技术在红队中的使用做介绍。
01 .Net Profiling
.NET Profiling 用于监控和分析 .NET 应用程序的各种行为。通过调用这些接口,开发人员可以创建自定义的性能分析器,深入了解应用程序的性能瓶颈、内存使用、线程行为等,从而进行优化和改进。
.Net Profiling API分为.Net Framework和.Net Core两个版本,Framework中大部分的API都适用于.Net Core。主要的API接口有两个:
-
ICorProfilerCallback: 定义了所有分析事件的回调接口,例如方法调用、垃圾回收等。
-
ICorProfilerInfo: 提供了查询和控制被分析应用程序的信息,例如获取模块信息、设置分析标志等。
下面列举几个有意思的API:
-
ICorProfilerCallback2::GarbageCollectionFinished GC(垃圾回收)完成时,该回调函数被调用
-
ICorProfilerCallback::JITCompilationStarted 通过该回调函数,我们可以知道哪个函数开始JIT(即时编译)
-
ICorProfilerCallback::AssemblyLoadStarted 通过该回调函数,我们可以知道哪些程序集被加载
-
ICorProfilerInfo4::RequestReJIT 通过该方法,我们可以强制重新JIT某个方法,这意味着可以动态修改IL代码
02 .Net Profiler
.Net Profiler是调用.Net Profiling接口编写的分析器,本身以dll形式出现。这个dll和Java中的agent类似,需要注入到CLR或者CoreCLR中。注入方式也有两种,一种是任意.Net进程启动时由CLR或CoreCLR自动加载,另一种是在任意.Net程序运行中执行Attach。这两种方式类似于Java Agent的premain和agentmain,但实际上比Java要复杂和重型。
第一种方式是通过设置环境变量实现的,适用于.Net Core和.Net Framework 如下所示。
CORECLR_ENABLE_PROFILING为1,代表允许分析器加载到.Net进程
CORECLR_PROFILER 分析器dll将检查传递的CLSID是否正确
CORECLR_PROFILER_PATH 代表分析器dll的路径
setx CORECLR_ENABLE_PROFILING=1
setx CORECLR_PROFILER={805A308B-061C-47F3-9B30-F785C3186E71}
setx CORECLR_PROFILER_PATH=C:DotNextMoscow2019-masterDebugDotNext.Profiler.Windows.dll
设置好上述变量后,任意.Net进程启动都会自动加载分析器Dll
第二种方式,用到了ICLRProfiling::AttachProfile 接口。.Net FrameWork的主要步骤如下:
-
获取ICLRMetaHost
-
枚举加载到目标进程中的 CLR
-
获取目标进程中特定 CLR 的 ICLRRuntimeInfo
-
获取ICLRProfiling接口
-
调用 ICLRProfiling::AttachProfiler 方法,附加成功
可以看到,整个流程前三步和Execute-Assembly技术实现的前三步完全一致
.Net Core则提供了相应库Microsoft.Diagnostics.NETCore.Client,相关代码如下。
using Microsoft.Diagnostics.NETCore.Client;
class profiler_injector
{
static void Main(string[] args)
{
int pid = Int32.Parse(args[0]);
string profilerPath = args[1];
DiagnosticsClient dia = new DiagnosticsClient(pid);
Guid guid = new Guid("{805A308B-061C-47F3-9B30-F785C3186E71}");
dia.AttachProfiler(TimeSpan.FromSeconds(30),guid, path );
}
}
谈完注入方式后,咱们来谈一下分析器Dll本身。分析器dll的工作原理大致如下图所示:
1. CoreCLR 首先Load Profiler这个dll,每个分析器Dll都会有DllGetClassobject这个导出函数。
2. CoreCLR然后调用DllGetClassobject导出函数,该函数通常判断CLSID的正确性,然后返回IClassFactory接口实例对象指针。
3. CoreCLR然后调用IClassFactory::CreateInstance方法,获取ICorCallback接口实例对象指针。
4. CoreCLR调用ICorCallback::Initialize方法,传入指向自己的指针,profiler会保存下来,然后调用SetEventMask通知coreclr 收集什么类的信息。
5. 双方进入正常通信。一旦有事件发生,ICorCallback接口的回调函数会被调用。
详细代码见参考链接3,建议观看 Pavel Yosifovich 的演讲视频”Writing a .NET Core cross platform profiler in an hour”
03 应用
持久化
上文提到,当3个环境变量被设置时,任意.Net进程启动会自动加载环境变量指定路径下的Dll,这意味着可以用来做持久化。需要注意的是,Dll不一定要是分析器Dll,普通的Dll也会被加载,即DllMain函数会被执行,可以把恶意代码放在DllMain中。
横向移动
如果可以通过UNC路径远程加载分析器Dll,并设置环境变量,那么便可以用.Net Profiler来横向移动。利用Win32_Process Create创建进程是一种常见的横向方式。而Win32_ProcessStartup可以为指定进程创建环境变量,这意味着我们可以利用上面两个函数远程执行任意.Net进程并加载分析器Dll。
研究员Daniel Mayer在WMI bof项目的基础上,添加了设置环境变量的功能,并将分析器Dll的路径设置为远程UNC路径,但由于使用了WMI,会有双跳(Double Hop)问题,因此失败。然而,他又发现了一种新方式,即分析器Dll可以从远程WebDAV服务器加载,从而实现了横向移动。
04 总结
.Net Profiling API是一组功能较为强大的接口,本文主要介绍了该技术在红队横向移动和持久化中的使用。由于该组接口的参考文档不多,且使用较为复杂,因此相关研究较少,但该组接口有着不少强大的功能,比如运行时修改.Net程序中的某个方法、挂钩.Net程序的指定方法等,这些技术有待进一步研究。
附录 参考链接
[1] https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/profiling-interfaces
[2] https://github.com/dotnet/coreclr/blob/master/Documentation/Profiling/davbr-blog-archive/Attach.md
[3] https://github.com/zodiacon/DotNextMoscow2019
[4] https://www.youtube.com/watch?v=TqS4OEWn6hQ
[5] https://posts.specterops.io/lateral-movement-with-the-net-profiler-8772c86f9523
天元实验室专注于新型实战化攻防对抗技术研究。
研究目标包括:漏洞利用技术、防御绕过技术、攻击隐匿技术、攻击持久化技术等蓝军技术,以及攻击技战术、攻击框架的研究。涵盖Web安全、终端安全、AD安全、云安全等多个技术领域的攻击技术研究,以及工业互联网、车联网等业务场景的攻击技术研究。通过研究攻击对抗技术,从攻击视角提供识别风险的方法和手段,为威胁对抗提供决策支撑。
M01N Team公众号
聚焦高级攻防对抗热点技术
绿盟科技蓝军技术研究战队
官方攻防交流群
网络安全一手资讯
攻防技术答疑解惑
扫码加好友即可拉群
原文始发于微信公众号(M01N Team):浅谈.Net Profiling在红队中的使用