跳转到帖子

游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

TheHackerWorld官方

从内存加载网程序集(执行装配)的利用分析

精选回复

发布于

0x00 前言

钴罢工3.11中,加入了一个名为"执行-汇编"的命令,能够从内存中加载。网程序集。这个功能不需要向硬盘写入文件,十分隐蔽,而且现有的Powershell利用脚本能够很容易的转换为C#代码,十分方便。

本文将会对"执行-汇编"的原理进行介绍,结合多个开源代码,介绍实现方法,分析利用思路,最后给出防御建议

0x01 简介

本文将要介绍以下内容:

基础知识

正常的实现方法

开源利用代码分析

利用思路

防御建议

0x02 基础知识

1.CLR

全称公共语言运行时(公共语言运行库),是一个可由多种编程语言使用的运行环境

清除(清除的缩写)是100 .净框架的主要执行引擎,作用之一是监视程序的运行:

在清除(清除的缩写)监视之下运行的程序属于"托管的"(托管)代码

不在清除(清除的缩写)之下、直接在裸机上运行的应用或者组件属于"非托管的"(非托管)的代码

2.Unmanaged API

参考资料:

https://份文件。微软。com/en-us/dot net/framework/unmanaged-API/

用于将。网程序集加载到任意程序中的应用程序接口

支持两种接口:

ICorRuntimeHost接口

ICLRRuntimeHost接口

3.ICorRuntimeHost Interface

参考资料:

https://份文件。微软。com/en-us/dot net/framework/unmanaged-API/hosting/icorruntimehost-interface

支持1.0.3705版,1.1.4322版,2.0.50727版和4.0.30319版

4.ICLRRuntimeHost Interface

参考资料:

https://份文件。微软。com/en-us/dot net/framework/unmanaged-API/hosting/iclrruntimehost-interface

支持v2.0.50727和4.0.30319版

在100 .净框架2.0中,ICLRRuntimeHost用于取代ICorRuntimeHost

在实际程序开发中,很少会考虑100 .净框架1.0,所以两个接口都可以使用

0x03 正常的实现方法

使用的实例代码:

https://代码。msdn。微软。com/windows desktop/CppHostCLR-e 6581 ee0 #内容

这里将参考实例代码并做补充

通用的实现方法如下:

1.将CLR加载到进程中

(1)调用CLRCreateInstance函数以获取ICLRMetaHost或ICLRMetaHostPolicy接口

(2)调用ICLRMetaHost:EnumerateInstalledRuntimes,ICLRMetaHost:GetRuntime或者ICLRMetaHostPolicy:GetRequestedRuntime方法以获取有效的ICLRRuntimeInfo指针

三个任选一个

(3)使用ICorRuntimeHost或者ICLRRuntimeHost

二者都是调用ICLRRuntimeInfo:GetInterface方法,但是参数不同

ICorRuntimeHost:

支持1.0.3705版,1.1.4322版,2.0.50727版和4.0.30319版

指定CLSID _ CorRuntimeHost为rclsid参数

指定IID_ICorRuntimeHost为RIID参数

ICLRRuntimeHost:

支持v2.0.50727和4.0.30319版

指定CLSID_CLRRuntimeHost为rclsid参数

指定IID_ICLRRuntimeHost为RIID参数

2.加载.NET程序集并调用静态方法

在代码实现上,使用ICLRRuntimeHost会比使用ICorRuntimeHost简单的多

3.清理CLR

释放步骤一中的指针

下面使用ICLRMetaHost:GetRuntime获取有效的ICLRRuntimeInfo指针,使用ICLRRuntimeHost从文件加载。网程序集并调用静态方法,实现代码如下:

#include 'stdafx.h '

#包括

#包括

#杂注注释(lib,' MSCorEE.lib ')

HRESULT运行时host _ get runtime _ ICLRRuntimeInfo(PCWSTR PSZ版本,PCWSTR pszAssemblyName,PCWSTR pszClassName,PCWSTR pszMethodName,PCWSTR pszArgName)

{

//调用ICLRMetaHost:GetRuntime获取有效的ICLRRuntimeInfo .

//调用ICLRRuntimeInfo:GetInterface方法。

hr结果HR

ICLRMetaHost * pMetaHost=NULL

ICLRRuntimeInfo * pRuntimeInfo=NULL;

ICLRRuntimeHost * pClrRuntimeHost=NULL;

双字

//

//加载并启动100 .净运行时。

//

加载并启动100 .净运行时“%s \n”,PSZ版本);

HR=CLRCreateInstance(CLSID _ CLRMetaHost,IID _ PPV _ ARGS(pMetaHost));

如果(失败(小时))

{

wprintf(L'[!]CLRCreateInstance失败w/HR0xlx\n',hr);

转到清理;

}

//获取与特定清除(clear的缩写)版本对应的ICLRRuntimeInfo .它

//用启动_加载程序_安全模式取代CorBindToRuntimeEx .

HR=pMetaHost-get runtime(PSZ版,IID _ PPV _ ARGS(pRuntimeInfo));

如果(失败(小时))

{

wprintf(L'[!]ICLRMetaHost:GetRuntime失败w/HR0xlx\n',hr);

转到清理;

}

//检查指定的运行时是否可以加载到进程中。这

//方法将考虑可能已经被

//加载到进程中,并将pbLoadable设置为真(如果此运行时可以)

//以进程内并行方式加载。

布尔浮动;

HR=pRuntimeInfo-可加载(可浮动);

如果(失败(小时))

{

wprintf(L'[!]ICLRRuntimeInfo:IsLoadable失败w/HR0xlx\n',hr);

转到清理;

}

如果(!可浮动)

{

wprintf(L'[!].无法加载。网运行库“% s \ n”,PSZ版本);

转到清理;

}

//将清除(clear的缩写)加载到当前进程中,并返回运行时接口

//指针106 . ICorRuntimeHost和ICLRRuntimeHost是两个清除(clear的缩写)宿主

CLR 4.0支持的接口。这里我们演示ICLRRuntimeHost

//中提供的接口. NET v2.0支持CLR 2.0新

//特性ICLRRuntimeHost。不支持加载. NET v1.x

//运行时。

HR=pRuntimeInfo-get接口(CLSID _ CLRRuntimeHost,IID _ PPV _ ARGS(pClrRuntimeHost));

如果(失败(小时))

{

wprintf(L'[!]ICLRRuntimeInfo:GetInterface失败w/HR0xlx\n',hr);

转到清理;

}

//启动CLR .

HR=pClrRuntimeHost-Start();

如果(失败(小时))

{

wprintf(L'[!]CLR未能启动w/HR0xlx\n',hr);

转到清理;

}

//

//加载网程序集并调用静态方法。

//

wprintf(L '[]加载程序集“%s\n”,pszAssemblyName);

ExecuteInDefaultAppDomain的调用方法必须具有

//以下签名:静态int pwzMethodName(字符串pwzArgument)

//其中pwzMethodName表示被调用方法的名称,而

//pwzArgument表示作为参数传递给

//方法。如果ExecuteInDefaultAppDomain的HRESULT结果返回值为

//设置为S_OK,预返回值设置为

//调用的方法。否则,不设置预转价值.

HR=pClrRuntimeHost-ExecuteInDefaultAppDomain(pszAssemblyName,pszClassName,pszMethodName,pszArgName,dwLengthRet);

如果(失败(小时))

{

wprintf(L'[!]未能调用% s w/HR0xlx\n',pszmethodname,hr);

转到清理;

}

//打印静态方法的调用结果。

wprintf(L '[]Call % s . % s(' % s ')=% d \ n ',pszClassName,pszMethodName,pszArgName,dwlength ret);

清理:

if (pMetaHost)

{

pMetaHost-Release();

pMetaHost=NULL

}

if (pRuntimeInfo)

{

pRuntimeInfo-Release();

pRuntimeInfo=NULL

}

if (pClrRuntimeHost)

{

//请注意,在调用停止之后,CLR不能

//重新初始化到同一进程中。这一步通常不是

//必要。你可以离开100 .净运行库加载到您的进程中。

//wprintf(L '停止100 .净运行时\ n’);

//pClrRuntimeHost-Stop();

pClrRuntimeHost-Release();

pClrRuntimeHost=NULL

}

回报HR;

}

int main()

{

runtime host _ get runtime _ ICLRRuntimeInfo(L ' v 4。0 .30319 ',L'ClassLibrary1.dll ',L'ClassLibrary1.Class1 ',L'TestMethod ',L ' argstring ');

返回0;

}

代码将会加载同级目录下。网络4.0开发的ClassLibrary1.dll,类名为第一类,方法为测试方法,传入的参数为argstring

ClassLibrary1.dll的代码如下:

使用系统;

使用系统。集合。泛型;

使用系统100 . Linq

使用系统。文本;

使用系统。线程。任务;

命名空间类库一

{

公共类1级

{

公共静态int测试方法(字符串str)

{

系统。诊断。过程p=新系统诊断。process();

页(第页的缩写)StartInfo。FileName=' c:\ \ windows \ \ system32 \ \ calc。exe ';

页(第页的缩写)start();

返回0;

}

}

}

0x04 开源利用代码分析

1、Unmanaged CLR Hosting Assembly loader

https://github.com/caseysmithrc/AssemblyLoader

利用清除(清除的缩写)从代码中定义好的数组读取外壳代码,加载到内存并执行

实现方法如下:

1.将CLR加载到进程中

(1)调用CLRCreateInstance函数以获取ICLRMetaHost或ICLRMetaHostPolicy接口

(2)调用ICLRMetaHost:GetRuntime方法以获取有效的ICLRRuntimeInfo指针

(3)使用ICorRuntimeHost

注:

在使用ICorRuntimeHost时,需要添加对mscorlib.tlb的引用,c代码如下:

//导入mscorlib.tlb(微软公共语言运行时类库)。

# import ' mscorlib . TLB ' raw _ interfaces _ only \

high_property_prefixes('_get ',' _put ',' _putref')\

重命名(' ReportEvent ',' InteropServices_ReportEvent ')

使用命名空间mscorlib

#杂注endregion

在ICorRuntimeHost中,读取和装入的方法。来自文件的. NET程序集的定义如下:

虚拟HRESULT __stdcall Load_2(

/*[in]*/BSTR程序集字符串,

/*[out,retval]*/struct _ Assembly * * pret val)=0;

读取和加载的方法。来自内存的. NET程序集的定义如下:

虚拟HRESULT __stdcall Load_3(

/*[in]*/SAFEARRAY *原始程序集,

/*[out,retval]*/struct _ Assembly * * pret val)=0;

注:

方法定义来自mscorlib.tlh

这里,Load_3(…)用于在加载。NET程序集。

2.加载.NET程序集并调用静态方法

3.清理CLR

2、Executing a .NET Assembly from C++ in Memory (CLR Hosting)

https://github.com/etormadiv/HostingCLR

caseysmith的方法和调用ICLRMetaHost:GetRuntime方法获取有效的ICLRRuntimeInfo指针基本相同,使用ICorRuntimeHost接口,使用Load_3(…)读取加载。内存中的. NET程序集。

3、CLR via native code

https://gist . githubusercontent . com/xpn/e 95 a 62 c 6 afcf 06 ede 52568 fcd 8187 cc 2/raw/f 3498245 c 8309d 44 af 38502 a2 cc 7090 c 318 E8 ADF/clr _ via _ native . c

值得注意的是,这里调用iclrmetahost:enumerateinstalleduntimes是为了获取有效的ICLRRuntimeInfo指针。

然后使用ICLRRuntimeHost进行加载。NET程序集并调用静态方法。

4、metasploit-execute-assembly

https://github.com/b4rtik/metasploit-execute-assembly

首先,创建一个进程notepad.exe,然后将HostingCLRx64.dll注入notepad.exe,HostingCLRx64.dll实现内存加载。Net程序集。

这里我们只关注内存加载的细节。Net程序集,代码位置:

https://github . com/B4 rtik/metasploit-execute-assembly/blob/master/hosting clr _ inject/hosting clr/hosting clr . CPP

详情如下:

使用。网络4.0.30319版

调用ICLRMetaHost:GetRuntime方法以获取有效的ICLRRuntimeInfo指针。

使用ICorRuntimeHost接口

使用Load_3(…)进行读取和加载。内存中的. NET程序集。

基本和1、2一样。

0x05 利用思路

综合0x04中的开源代码,execute-assembly通常有以下两种利用思路:

1.从内存中读取shellcode并加载.NET程序集

请调用iclrmetahost:enumerateinstalldruntimes、iclrmetahost: getruntime或iclrmetahostpolicy:getrequestedruntime方法来获取有效的ICLRRuntimeInfo指针。

使用ICorRuntimeHost接口

使用Load_3(…)进行读取和加载。内存中的. NET程序集。

调用静态方法

2.从硬盘读取并加载.NET程序集

请调用iclrmetahost:enumerateinstalldruntimes、iclrmetahost: getruntime或iclrmetahostpolicy:getrequestedruntime方法来获取有效的ICLRRuntimeInfo指针。

使用icorruntimeost(使用Load_2(…))或ICLRRuntimeHost接口。

加载。NET程序集并调用静态方法

第一种利用思路优于第二种,完整的利用过程如下:

创建一个正常流程。

通过DLL反射将DLL注入进程

Dll从内存中读取外壳代码并加载最终。NET程序集。

优点如下:

整个过程在内存中执行,而不是写入文件系统。

Payload以dll的形式存在,不会产生任何可疑的进程。

最终的有效载荷是一个C#程序,通过使用脚本将现有的Powershell转换成C#代码很方便。

0x06 防御建议

必须全程使用dll注入,常见的Dll注入方法(尤其是Dll反射)都可以拦截。

至于dll本身,当使用CLR时,会加载系统的dll,例如:

mscoree.dll

mscoreei.dll

mscorlib.dll

这是可以监控的。

0x07 小结

结合几个开源代码,总结了“执行-汇编”的实现方法和利用思路,分析了其优势,最后给出了一些防御建议。

留下回复

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。