前言
这里分析的为Cobalt Strike的Powershell Beacon Payload ,主要目的为方便更好免杀和学习一下样本分析。
代码不多,可以看到主要分为3个部分
第一部分
我们从主入口<span class="ne-text">IF</span>
部分开始分析:
<span class="ne-text">[IntPtr]::size -eq 8</span>
这里返回一个<span class="ne-text">True</span>
;
<span class="ne-text">[IntPtr]::size</span>
的功能为获取当前的powershell环境为x86还是 x64
<span class="ne-text">x86 为“4”,x64 为“8” ;</span>
<span class="ne-text">更多信息:</span>``<a href="https://blog.kenaro.com/2010/12/08/how-to-determine-current-powershell-session-is-x86-or-x64/" data-href="https://blog.kenaro.com/2010/12/08/how-to-determine-current-powershell-session-is-x86-or-x64/" target="_blank" class="ne-link"><span class="ne-text">https://blog.kenaro.com/2010/12/08/how-to-determine-current-powershell-session-is-x86-or-x64/</span></a>
因为我们生成的为<span class="ne-text">x64</span>
的所以这里判断是否为<span class="ne-text">”8“</span>
;
同时我们可以看到<span class="ne-text">x86</span>
和<span class="ne-text">x64</span>
的区别。
接下来就是解密一个<span class="ne-text">base64</span>
并将其转换为字节数组。
<span class="ne-text">[Byte[]]$var_code = [System.Convert]::FromBase64String('bnlicXZrqsZros8DIy</span>
例如:
<span class="ne-text">$ EncodedText =“VABoAGkAcwAgAGkAcwAgAGEAIABzAGUAYwByAGUAdAAgAGEAbgBkACAAcwBoAG8AdQBsAGQAIABiAGUAIABoAGkAZABlAG4A”</span>
<span class="ne-text">$ DecodedText = [System.Text.Encoding] :: Unicode.GetString([System.Convert] :: FromBase64String($ EncodedText))</span>
<span class="ne-text">$ DecodedText</span>
然后到了一个<span class="ne-text">for</span>
语句;
<span class="ne-text">$var_code.Count</span>
为
<span class="ne-text">-lt</span>``<span class="ne-text"> :小于</span>
<span class="ne-text">-bxor</span>
位异或,两个输入不同时为1,相同时为0(相异为真,否则为假)
例如;我们取<span class="ne-text">$x=1</span>
那么<span class="ne-text">$var_code[$x] -bxor 35</span>
为
也就是说把所有的数据都<span class="ne-text">bxor</span>
然后存放起来。
接下来我们可以看到一个<span class="ne-text">GetDelegatForFunctionPointer</span>
它允许通过委托实例调用方法,并且<span class="ne-text">GetDelegateForFunctionPointer</span>
可以将非托管函数指针转换为委托。
<span class="ne-text">当我们实例化委托时,我们可以将其实例与具有兼容签名和返回类型的任何方法相关联。那么可以通过委托实例调用(或调用)该方法。</span>
传递给委托方法的第一个参数是对<span class="ne-text">VirtualAlloc</span>
的调用:
第二个参数是动态创建的程序集:
然后在下面调用它:
<span class="ne-text">[System.Runtime.InteropServices.Marshal]::Copy:</span>``<span class="ne-text">将数据从非托管内存指针复制到托管单精度浮点数数组</span>
使用<span class="ne-text">GetDelegateForFunctionPointer</span>
,<span class="ne-text">VirtualAlloc</span>
传入创建的缓冲区。
然后可以对委托进行实际的调用:
func_get_proc_address
然后我们可以看函数<span class="ne-text">func_get_proc_address</span>
部分了
这个函数接受两个参数:
<span class="ne-text">$var_module</span>
<span class="ne-text">$var_procedure</span>
列出*PowerShell 会话中*所有加载的程序集,然后找到在<span class="ne-text">System.dll</span>
中的<span class="ne-text">Microsoft.Win32.UnsafeNativeMethods</span>
<span class="ne-text">([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')</span>
首先获取当前AppDomain中的所有程序集: <span class="ne-text">[AppDomain]::CurrentDomain.GetAssemblies()</span>
然后通过管道输送到<span class="ne-text">Where-Object</span>
获取<span class="ne-text">System.dll</span>
最后调用<span class="ne-text">Microsoft.Win32.UnsafeNativeMethods</span>
;在该对象上,<span class="ne-text">GetType</span>
用于访问<span class="ne-text">UnsafeNativeMethods</span>
.
CS为什么要使用种方法来调用?
<span class="ne-text">Microsoft.Win32.UnsafeNativeMethods is an internal class that cannot be referenced through any direct means. If you try to reference the class, you will get an error stating that its module is not loaded. Microsoft.Win32.UnsafeNativeMethods is implemented within System.dll in the GAC.</span>
<a href="https://twitter.com/mattifestation" data-href="https://twitter.com/mattifestation" target="_blank" class="ne-link"><span class="ne-text">https://twitter.com/mattifestation</span></a>
此时,<span class="ne-text">Microsoft.Win32.UnsafeNativeMethods</span>
已经实现了对类的访问。
接下来就是
<span class="ne-text">$var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleRef', 'string'))</span>
那么在微软文档中我们知道
<span class="ne-text">GetMethod(String, Type[])</span>
搜索参数与指定参数类型匹配的指定公共方法。
<a href="https://docs.microsoft.com/en-us/dotnet/api/system.type.getmethod?view=netcore-3.1#System_Type_GetMethod_System_String_System_Type___" data-href="https://docs.microsoft.com/en-us/dotnet/api/system.type.getmethod?view=netcore-3.1#System_Type_GetMethod_System_String_System_Type___" target="_blank" class="ne-link"><span class="ne-text">https://docs.microsoft.com/en-us/dotnet/api/system.type.getmethod?view=netcore-3.1#System_Type_GetMethod_System_String_System_Type___</span></a>
func_get_delegate_type
此函数被调用两次,并接受以下参数:
<span class="ne-text">func_get_delegate_type @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]) </span>
<span class="ne-text">func_get_delegate_type @([IntPtr]) ([Void]) </span>
第一个参数是方法期望的参数类型,第二个是返回类型。
<span class="ne-text">Param([Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters, </span>
<span class="ne-text">[Parameter(Position = 1)][Type]$var_return_type = [Void])</span>
然后是一个<span class="ne-text">AssemblyBuilder.DefineDynamicAssembly </span>
方法,主要用来定义动态程序集。
<span class="ne-text">DefineDynamicAssembly(AssemblyName,AssemblyBuilderAccess) 定义具有指定名称和访问权限的动态程序集。 DefineDynamicAssembly(AssemblyName, AssemblyBuilderAccess, IEnumerable<CustomAttributeBuilder>) 定义具有指定名称、访问权限和属性的新程序集。 </span>
在msdn中我们可以看到定义具有指定名称和访问权限的动态程序集的例子
<span class="ne-text">public static System.Reflection.Emit.AssemblyBuilder DefineDynamicAssembly (System.Reflection.AssemblyName name, System.Reflection.Emit.AssemblyBuilderAccess access); </span>
方便理解我们可以分解为
<span class="ne-text">$1 = [AppDomain]::CurrentDomain.DefineDynamicAssembly($2,$3)</span>
<span class="ne-text">$2 = New-Object System.Reflection.AssemblyName('ReflectedDelegate')</span>
<span class="ne-text">$3 = [System.Reflection.Emit.AssemblyBuilderAccess]::Run</span>
然后是定义模块:
<span class="ne-text">.DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])</span>
<span class="ne-text">AssemblyBuilder.DefineDynamicModule:</span>``<span class="ne-text">在这个程序集中定义一个动态模块。</span>
<span class="ne-text">ModuleBuilder.DefineType:定义类型</span>
往下看就是一个<span class="ne-text">TypeBuilder.DefineConstructor</span>
向动态类型添加一个新的构造函数。
传递给此调用的第一个值是一个逗号分割的属性列表
<span class="ne-text">RTSpecialName:表示公共语言运行时检查名称编码。 </span>
<span class="ne-text">HideBySig:表示方法按名称和签名隐藏;否则,仅通过名称。 </span>
<span class="ne-text">Public:表示该方法可被此对象在其范围内的任何对象访问。 </span>
第二个参数是<span class="ne-text">CallingConventions</span>
,在本例中设置为<span class="ne-text">Standard</span>
<span class="ne-text">指定由公共语言运行时确定的默认调用约定。将此调用约定用于静态方法。例如或虚拟方法使用HasThis.</span>
接下来是使用<span class="ne-text">SetImplementationFlags</span>
设置实现标志。
传递的属性是<span class="ne-text">MethodImplAttribute</span>``<span class="ne-text">s</span>
:
这里定义了2个值:
<span class="ne-text">Runtime: 指定方法实现由运行时提供</span>
<span class="ne-text">Managed:</span>``<span class="ne-text">指定在托管代码中实现该方法。</span>
往下看还是在定义一个方法:
跟上面差不多,主要是用了<span class="ne-text">DefineMethod</span>
。
<a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.typebuilder.definemethod?view=netcore-3.1#System_Reflection_Emit_TypeBuilder_DefineMethod_System_String_System_Reflection_MethodAttributes_System_Reflection_CallingConventions_System_Type_System_Type___System_Type___System_Type___System_Type_____System_Type_____" data-href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.typebuilder.definemethod?view=netcore-3.1#System_Reflection_Emit_TypeBuilder_DefineMethod_System_String_System_Reflection_MethodAttributes_System_Reflection_CallingConventions_System_Type_System_Type___System_Type___System_Type___System_Type_____System_Type_____" target="_blank" class="ne-link"><span class="ne-text">https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.typebuilder.definemethod?view=netcore-3.1#System_Reflection_Emit_TypeBuilder_DefineMethod_System_String_System_Reflection_MethodAttributes_System_Reflection_CallingConventions_System_Type_System_Type___System_Type___System_Type___System_Type_____System_Type_____</span></a>
它向类型添加一个新方法,具有指定的名称、方法属性、调用约定、方法签名和自定义修饰符。
by:李木
前记 大家好,我是风起,本次给大家分享的是 **Serverless扫描技术* 也是我在SecTime沙龙演讲时讲到的一种隐匿扫描技术,通过 Serverless(云函数) 实现各种扫描器探测功能,以达到绕过态势感知、WAF等安全设备,增大蓝队研判人员溯源难度…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论