欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

从内存加载.NET程序集(execute-assembly)的利用分析

来源:本站整理 作者:佚名 时间:2019-07-11 TAG: 我要投稿

Cobalt Strike 3.11中,加入了一个名为"execute-assembly"的命令,能够从内存中加载.NET程序集。这个功能不需要向硬盘写入文件,十分隐蔽,而且现有的Powershell利用脚本能够很容易的转换为C#代码,十分方便。
本文将会对"execute-assembly"的原理进行介绍,结合多个开源代码,介绍实现方法,分析利用思路,最后给出防御建议。
0x01 简介
本文将要介绍以下内容:
· 基础知识
· 正常的实现方法
· 开源利用代码分析
· 利用思路
· 防御建议
0x02 基础知识
1.CLR
全称Common Language Runtime(公共语言运行库),是一个可由多种编程语言使用的运行环境。
CLR是.NET Framework的主要执行引擎,作用之一是监视程序的运行:
· 在CLR监视之下运行的程序属于"托管的"(managed)代码。
· 不在CLR之下、直接在裸机上运行的应用或者组件属于"非托管的"(unmanaged)的代码。
2.Unmanaged API
参考资料:
https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/
用于将.NET 程序集加载到任意程序中的API。
支持两种接口:
· ICorRuntimeHost Interface
· ICLRRuntimeHost Interface
3.ICorRuntimeHost Interface
参考资料:
https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-interface
支持v1.0.3705, v1.1.4322, v2.0.50727和v4.0.30319。
4.ICLRRuntimeHost Interface
参考资料:
https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-interface
支持v2.0.50727和v4.0.30319。
在.NET Framework 2.0中,ICLRRuntimeHost用于取代ICorRuntimeHost。
在实际程序开发中,很少会考虑.NET Framework 1.0,所以两个接口都可以使用。
0x03 正常的实现方法
使用的实例代码:
https://code.msdn.microsoft.com/windowsdesktop/CppHostCLR-e6581ee0#content
这里将参考实例代码并做补充。
通用的实现方法如下:
1.将CLR加载到进程中
(1)调用CLRCreateInstance函数以获取ICLRMetaHost或ICLRMetaHostPolicy接口。
(2)调用ICLRMetaHost::EnumerateInstalledRuntimes, ICLRMetaHost::GetRuntime或者ICLRMetaHostPolicy::GetRequestedRuntime方法以获取有效的ICLRRuntimeInfo指针。
三个任选一个。
(3)使用ICorRuntimeHost或者ICLRRuntimeHost。
二者都是调用ICLRRuntimeInfo::GetInterface方法,但是参数不同。
ICorRuntimeHost:
· 支持v1.0.3705, v1.1.4322, v2.0.50727和v4.0.30319
· 指定CLSID_CorRuntimeHost为rclsid参数
· 指定IID_ICorRuntimeHost为RIID参数
ICLRRuntimeHost:
· 支持v2.0.50727和v4.0.30319
· 指定CLSID_CLRRuntimeHost为rclsid参数
· 指定IID_ICLRRuntimeHost为RIID参数
2.加载.NET程序集并调用静态方法
在代码实现上,使用ICLRRuntimeHost会比使用ICorRuntimeHost简单的多。
3.清理CLR
释放步骤1中的指针。
下面使用ICLRMetaHost::GetRuntime获取有效的ICLRRuntimeInfo指针,使用ICLRRuntimeHost从文件加载.NET程序集并调用静态方法,实现代码如下:
#include "stdafx.h"
#include
#include
#pragma comment(lib, "MSCorEE.lib")
HRESULT RuntimeHost_GetRuntime_ICLRRuntimeInfo(PCWSTR pszVersion, PCWSTR pszAssemblyName, PCWSTR pszClassName, PCWSTR pszMethodName, PCWSTR pszArgName)
{
 // Call the ICLRMetaHost::GetRuntime to get a valid ICLRRuntimeInfo.
 // Call the ICLRRuntimeInfo:GetInterface method.
 HRESULT hr;
 ICLRMetaHost *pMetaHost = NULL;
 ICLRRuntimeInfo *pRuntimeInfo = NULL;
 ICLRRuntimeHost *pClrRuntimeHost = NULL;
 DWORD dwLengthRet;
 //
 // Load and start the .NET runtime.
 //
 wprintf(L"Load and start the .NET runtime %s \n", pszVersion);
 hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
 if (FAILED(hr))
 {
  wprintf(L"[!]CLRCreateInstance failed w/hr 0x%08lx\n", hr);
  goto Cleanup;
 }
 // Get the ICLRRuntimeInfo corresponding to a particular CLR version. It
 // supersedes CorBindToRuntimeEx with STARTUP_LOADER_SAFEMODE.
 hr = pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo));
 if (FAILED(hr))
 {
  wprintf(L"[!]ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr);
  goto Cleanup;
 }
 // Check if the specified runtime can be loaded into the process. This
 // method will take into account other runtimes that may already be
 // loaded into the process and set pbLoadable to TRUE if this runtime can
 // be loaded in an in-process side-by-side fashion.
 BOOL fLoadable;
 hr = pRuntimeInfo->IsLoadable(&fLoadable);
 if (FAILED(hr))
 {
  wprintf(L"[!]ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr);
  goto Cleanup;
 }
 if (!fLoadable)
 {
  wprintf(L"[!].NET runtime %s cannot be loaded\n", pszVersion);
  goto Cleanup;
 }
 // Load the CLR into the current process and return a runtime interface

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载