反恶意软件扫描接口(AMSI)对抗学习 – 作者:dnsill

Amsi(Antimalware Scan Interface)基础知识

The Windows Antimalware Scan Interface (AMSI) is a versatile interface
standard that allows your applications and services to integrate with
any antimalware product that’s present on a machine. AMSI provides
enhanced malware protection for your end-users and their data,
applications, and workloads.

AMSI is agnostic of antimalware vendor; it’s designed to allow for the
most common malware scanning and protection techniques provided by
today’s antimalware products that can be integrated into applications.
It supports a calling structure allowing for file and memory or stream
scanning, content source URL/IP reputation checks, and other
techniques.

AMSI also supports the notion of a session so that antimalware vendors
can correlate different scan requests. For instance, the different
fragments of a malicious payload can be associated to reach a more
informed decision, which would be much harder to reach just by looking
at those fragments in isolation.

从前面微软的文档中我们可以知道Windows防病毒扫描界面(AMSI)是一个通用的接口标准,是开放给防病毒产品调用的一个接口。
这个接口支持允许不单单可以用来扫描脚本、代码、命令或者cmdlet,也可以用来扫描任何文件、内存或者数据流,如字符串、即时消息、图像或者视频等等

我认为这个Amsi(Antimalware Scan Interface)主要是针对脚本来说的,目前来说脚本逐渐成为针对性攻击的武器,诸如JavaScript,VBScript和PowerShell之类的脚本为我们攻击提供了巨大的好处。它们是系统合法的软件,并且执行文件不落地在内存中加载。

脚本语言比exe等等Pe文件要好混淆,可以从远端或注册表加载执行,并且脚本的动态特性允许攻我们容易地逃避反恶意软件和类似的端点防护产品的检测与分析。并且执行文件可以不落地直接在内存中加载。

那么 Windows 10可以通过反恶意软件扫描接口(AMSI)提供查杀脚本的功能,还可以以脚本解释程序的相同方式查看脚本内容 ,这样的话就可以未加密和未混淆的形式来查看我们的攻击脚本。

目前在微软的文档中我们可以知道
AMSI功能已集成到Windows 10的这些组件中。

用户帐户控制或UAC(EXE,COM,MSI或ActiveX)
PowerShell(脚本,交互使用和动态代码评估)
Windows脚本主机(wscript.exe和cscript.exe)
JavaScript和VBScript
Office VBA宏

Amsi(Antimalware Scan Interface)的工作流程。

As an application developer, you can actively participate in malware

  1. Specifically, you can help protect your customers from

  2. script-based malware, and from non-traditional avenues of

cyberattack.

By way of an example, let’s say that your application is scriptable:
it accepts arbitrary script, and executes it via a scripting engine.
At the point when a script is ready to be supplied to the scripting
engine, your application can call the Windows AMSI APIs to request a
scan of the content. That way, you can safely determine whether or not
the script is malicious before you decide to go ahead and execute it.

This is true even if the script was generated at runtime. Script
(malicious or otherwise), might go through several passes of
de-obfuscation. But you ultimately need to supply the scripting engine
with plain, un-obfuscated code. And that’s the point at which you
invoke the AMSI APIs.

从微软的文档中我们可以看到Amsi中的工作流程。
如果有一个应用程序接受任意脚本,并通过脚本引擎执行该脚本。
那么杀毒软件可以调用amsi来查杀脚本。
可能有同学有疑问:杀毒软件不是也能不靠amsi查杀脚本吗?不不不 amsi的意义在于:无论我们的恶意脚本是经过多次模糊处理还是远程执行amsi都可以在脚本注入内存前检测到。而普通的静态杀毒软件是没办法的。

我们可以看微软文档给出的工作流程图来理解:

请输入图片描述

其实不难理解,首先我们要知道我们的恶意脚本是如何注入内存执行的
bypass 杀毒软件时我们的脚本一定是模糊处理的,但是无论我们什么样模糊处理到注入内存执行的时候一定是纯净,清晰的代码,不然脚本引擎无法理解和执行我们的恶意脚本。
那么问题就是在这里,amsi在脚本解密到注入内存之前去扫描查杀。这才是调用amsi的意义。

我们可以调用powershell来执行我们的恶意代码来更好理解Amsi

AMSI的一个简单测试是在PowerShell提示符–中键入AMSI旁路中常用的字符串amsiutils。如果端点安全产品支持AMSI,并且检测到该字符串,那么PowerShell提示符将显示错误,表明输入的命令是恶意的。

1613918189_60326fed7bb4ed4b9008c.png!small?1613918189915

PS C:\Users\(123223Li)> amsiutils
所在位置 行:1 字符: 1
+ amsiutils
+ ~~~~~~~~~
此脚本包含恶意内容,已被你的防病毒软件阻止。
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ScriptContainedMaliciousContent

很好Amsi查杀并阻止了power shell执行命令。
我们来处理一下amsiutils,比如我们常用的base64加密和XOR编码技术。

$bytes = [convert]::FromBase64String('YW1zaXV0aWxz') # YW1zaXV0aWxz为amsiutils的base64编码
$string = -join ($bytes | % {[char] ($_ -bxor 0x33)}) #进行XOR编码
iex $string #执行命令

然后我们使用powershell ISE 执行来模拟我们在实战中的无文件落地直接内存加载执行的手法

1613918180_60326fe4790c16ab764ef.png!small?1613918180846

毫不意外,amsi检测到并拦截了powershell去执行我们的脚本。

我们可以使用下面命令来查看amsi中的查杀结果

Get-WinEvent 'microssoft-windows-windows defender/operational' | Where-Object id -EQ 1116 | format-list

1613918169_60326fd967d9843af1bd7.png!small?1613918169825

当然amsi也可以检测vba和Java script
在实战中,使用宏攻击(钓鱼)也是我们常用的手法,所以我们要知道amsi对宏文件的检测流程

在微软文档中我们可以看到

The user receives a document containing a (malicious) macro, which
evades static antivirus software scans by employing techniques such as
obfuscation, password-protected files, or other. The user then opens
the document containing the (malicious) macro. If the document opens
in Protected View, then the user clicks Enable Editing to exit
Protected View. The user clicks Enable Macros to allow macros to run.
As the macro runs, the VBA runtime uses a circular buffer to log [1]
data and parameters related to calls to Win32, COM, and VBA APIs. When
specific Win32 or COM APIs that are considered high risk (also known
as triggers) [2] are observed, macro execution is halted, and the
contents of the circular buffer are passed to AMSI. The registered
AMSI anti-malware service provider responds with a verdict to indicate
whether or not the macro behavior is malicious. If the behavior is
non-malicious, then macro execution proceeds. Otherwise, if the
behavior is malicious, then Microsoft Office closes the session in
response to the alert [3], and the AV can quarantine the file.

微软文档中也给出了一个流程图

请输入图片描述

通过阅读理解微软文档我们可以知道amsi对宏的检测查杀流程:

1.word等等钓鱼文件加载宏
2.VBA宏运行时,运行时会有一个循环的缓冲区中记录数据和参数调用Win32,COM, VBA等等api的情况。
3.amsi监控着缓冲区中的情况,一旦我们的宏调用了一些敏感的API或一些敏感的数据交互,就会触发amsi的触发器。
4.amsi停止宏执行并从循环缓冲区取出内容传递。
5.amsi从循环缓冲区取出内容传递给杀毒软件。
6.杀毒软件拿到数据后判断宏是否为恶意的。
6.如果行为是无恶意的,那么宏可以执行。否则,关闭宏会话并发出响应警报和处理恶意文件。

我们可以看一个例子来理解amsi检测查杀vba的流程:
跟powershell一样我们也使用远程加载powershell恶意代码。这样更贴近实战。

1.使用cobat Strike生成我们的恶意代码

1613918155_60326fcbb7a020b072baf.png!small?1613918156403

2.使用宏远程加载我们的恶意代码

#使用宏调用powershell远程加载ps1
 Sub AutoOpen()
        Call Shell("powershell -Sta -Nop -Window Hidden -EncodedCommand shell")
End Sub

在没有开amsi的情况下可以执行上线!

1613918146_60326fc2640886bdac4cb.png!small?1613918146879

在开了amsi的情况下无法执行了

1613918140_60326fbc7081f554464fe.png!small?1613918141067

amsi是所有杀毒软件都可以调用吗?并不是!

amsi是在Windows 10 和Windows Server 2016 之后才有的,然后并不是所有的杀毒软件都可以调用amsi接口。国内的基本不可以哈哈哈。

在github上有一个项目记录了可以调用amsi的杀毒软件

https://github.com/subat0mik/whoamsi/wiki/Which-Endpoint-Protection-is-Using-AMSI%3F

杀软对抗是一个动态对抗的过程,杀毒有新技术,免杀就有新手法。只有熟透杀软才能更好免杀。

amsi解决的是远程加载执行恶意脚本无文件落地的攻击手法,过两天看看跟大家学习一下bypass AMsi的手法。

我们学习了Antimalware Scan Interface(AMSI)的一些知识。作为渗透测试的我们了解杀软是为了更好地进行免杀。

在对抗杀毒软件的手法中,在大层面来说:

一就是破坏杀毒软件,使其无法正常运行;
二是绕过杀毒软件,使其无法检测到。

从小的层面来说:

静态免杀
动态免杀
沙盒对抗
等等

前面我们说到AMSI是windows开放的一个接口,注册的杀毒软件可以通过调用amsi接口来完成监控查杀。
既然是接口,那么我们是不是可以使杀毒软件无法调用这个amsi接口来bypass?

首先我们得知道杀毒软件是如何调用amsi的:

在微软文档中给出了2种调用amsi接口的方法

There are two ways in which you can interface with AMSI in your application.

By using the AMSI Win32 APIs. By using the AMSI COM interfaces.

分别是:
1.通过使用AMSI Win32 API

Functions that your application can call to request a scan. AMSI provides the following functions. 
#函数,应用程序可以通过调用amsi,amsi提供以下函数

Function #函数    Description #功能
AmsiCloseSession    Close a session that was opened by AmsiOpenSession.#关闭打开的会话
AmsiInitialize    Initialize the AMSI API.#初始化AMSI API。
AmsiOpenSession    Opens a session within which multiple scan requests can be correlated.#打开一个会话中关联多个扫描请求。
AmsiResultIsMalware    Determines if the result of a scan indicates that the content should be blocked.#    确定扫描的结果表明,内容应该是屏蔽
AmsiScanBuffer    Scans a buffer-full of content for malware. #    扫描恶意软件的缓冲区已满的内容。
AmsiScanString    Scans a string for malware.#恶意软件扫描一个字符串。
AmsiUninitialize    Remove the instance of the AMSI API that was originally opened by AmsiInitialize.#删除的实例AMSI API,

其中每个函数的调用方法有兴趣可以去微软种查看。

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

2.通过使用AMSI COM接口

这个中调用的是IAmsiStream接口(amsi.h)代表一个流被扫描,微软文档中给出了示例,

https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-iamsistream-getattribute

Inheritance The IAmsiStream interface inherits from the IUnknown
interface. IAmsiStream also has these types of members:
 
Methods Methods The IAmsiStream interface has these methods.
 
METHODS Method    Description IAmsiStream::GetAttribute    Returns a
requested attribute from the stream. IAmsiStream::Read    Requests a
buffer-full of content to be read. Requirements REQUIREMENTS
            Minimum supported client    Windows 10 [desktop apps only] 
          Minimum supported server    Windows Server 2016 [desktop apps only] Target
Platform    Windows Header    amsi.h

然后上面我们知道了如何调用amsi,但是调用amsi还要注册才能调用,所以我们也得看看amsi是如何注册的:

As a creator of antimalware products, you can choose to author and
register your own in-process COM server (a DLL) to function as an AMSI

  1. That AMSI provider must implement the IAntimalwareProvider
    interface, and it must run in-process.

Note that, after Windows 10, version 1709 (the Fall 2017 Creators’
Update), your AMSI provider DLL may not work if it depends upon other
DLLs in its path to be loaded at the same time. To prevent DLL
hijacking, we recommend that your provider DLL load its dependencies
explicitly (with a full path) using secure LoadLibrary calls, or equivalent.
We recommend this instead of relying on the LoadLibrary search behavior.

The section below shows how to register your AMSI provider. For full
sample code showing how to author your own AMSI provider DLL, see the
IAntimalwareProvider interface sample application.

Register your provider DLL with AMSI To begin with, you need to ensure
that these Windows Registry keys exist.

HKLMSOFTWAREMicrosoftAMSIProviders HKLMSOFTWAREClassesCLSID An
AMSI provider is an in-process COM server. Consequently, it needs to
register itself with COM. COM classes are registered in
HKLMSOFTWAREClassesCLSID.

当然在微软文档中也给出了示例,但是我们是要做免杀,理解一些必要的东西就行。
在微软的文档中我们可以知道

Note that, after Windows 10, version 1709 (the Fall 2017 Creators’
Update), your AMSI provider DLL may not work if it depends upon other
DLLs in its path to be loaded at the same time. To prevent DLL
hijacking, we recommend that your provider DLL load its dependencies
explicitly (with a full path) using secure LoadLibrary calls, orequivalent.
We recommend this instead of relying on the LoadLibrarysearch behavior.search behavior.

微软中说:

1613918109_60326f9de9dd51c727742.png!small?1613918110354

也就是说存在dll劫持的例子。我们复现一下历史上的amsi.dll劫持吧。

劫持amsi.dll bypass amsi复现

我们以powershell为例子吧:
我们在学习了上面的基础之后我们可以知道powershell中调用amsi的过程

当打开一个PowerShell时,poweershell会从磁盘把AMSI.DLL加载到powershell的地址空间。
然后会调用AMSI.DLL中函数AmsiScanBuffer()的功能用来扫描脚本的内容。
PowerShell中任何提供的脚本内容会先被送到AmsiScanBuffer()检测查杀后再执行。
随后,AmsiScanBuffer()将与注册杀毒检查,确定是否创建了签名。
如果内容被认为是恶意的,它将被处理

我们可以知道powershell是加载amsi.dll的,那么这里就存在一个可劫持点。就是劫持amsi.dll来bypass amsi

DLL(Dynamic Link
Library)文件为动态链接库文件,又称”应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。

如果在进程尝试加载一个DLL时没有指定DLL的绝对路径,那么Windows会尝试去按照顺序搜索这些特定目录时下查找这个DLL,只要黑客能够将恶意的DLL放在优先于正常DLL所在的目录,就能够欺骗系统优先加载恶意DLL,来实现”劫持”

dll的劫持需要满足两个条件(这里指win7以上的版本)

1.目标DLL没有在HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerKnownDLLs注册表中

凡是此项下的DLL文件就会被禁止从exe自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用

dll没有在KnownDLLs注册表中就会以下顺序加载

1. 进程对应的应用程序所在目录(可理解为程序安装目录比如C:\ProgramFiles\uTorrent)
2. 系统目录(即%windir%system32);
3. 16位系统目录(即%windir%system);
4. Windows目录(即%windir%);
5. 当前目录(运行的某个文件所在目录,比如C:\Documents and Settings\Administrator\Desktop\test);
6. PATH环境变量中的各个目录

2.目标文件目录或者我们需要写进dll的目标我们具有可写权限

默认情况下,如果软件安装在c盘根目录,而不是c:\Program Files,那经过身份验证的用户具有该目录的写权限,另外,perl,python,ruby等软件通常都添加到path变量中。那攻击者可以在当前目录中编写恶意DLL,只要重新运行exe程序就会中招。

ok我们知道powershell是amsi.dll来监控查杀脚本的,我们可以使用Process Mointor来监控powershell进程在运行中执行了那些API调用,打开/创建了注册表项,加载了DLL等。

设置process中的过滤器规则来查看只有powershell.exe的进程。

1613918093_60326f8d0deb72e279f40.png!small?1613918093409

应用规则,我们可以看到只有powershell.exe进程的所有调用情况。

1613918060_60326f6ccd796604a5070.png!small

太多事件了,我们可以加一条规则来查看在powershell中仅仅是调用amsi.dll的事件。

1613918047_60326f5feeb5e77bc6053.png!small?1613918048478

查看ProcMon的输出,我们发现了第一个可能的DLL劫持。

1613918039_60326f57dd119578bb981.png!small?1613918040498

我们直接跳转过去文件的路径中

1613918032_60326f500fcd3723cd8dc.png!small?1613918032534

可以看到路径中并没有amsi.dll,那么我们可以写入一个恶意的amsi.dll进去。这里使用cobalt strike生成的恶意dll来演示,当然这个dll我们也进行了免杀处理。

1613918026_60326f4a1a3e752eba43f.png!small?1613918026534

把生成的恶意dll更改名字为amsi.dll后拉进我们上面的文件路径中

1613918019_60326f434e828d12e6e83.png!small?1613918019694

然后打开powershell 可以看到powershell中出错了,然后Cobalt strike上线了(打开powershell直接上线)。但是没关系,一般在实战中我们会处理我们的恶意dll来同时实现目标dll的功能和执行我们的恶意函数来上线的,这里不多说。

1613918011_60326f3bd9e3335236c31.png!small?1613918012508

在powershell加载amsi.dll过程中还存在一个劫持点,就是:

C:\Windows\System32\WindowsPowerShell\v1.0

有兴趣的同学可以自行了解下

破坏amsi.dll bypass Asmi

国外有个老哥写了个脚本直接破坏amsi来执行命令。
在复现他的手法时我们要知道powershell与amsi.dll之间的一些知识:
amsi.dll会为每一个powershell.exe进程加载一个amsi.dll.

然后因为那个老哥的github上的ps1不在了,我修改下然后上传到我的GitHub上去了,方便以后使用。

https://github.com/dnsil/bypassAsmi

使用手法不难,直接加载执行就行。

1613918004_60326f3428e8de6c04e53.png!small?1613918004680

但是windwos defender已经报毒,自行处理一下就好

1613917996_60326f2cd87248c7b7b07.png!small?1613917997233

然后这里还要注意一个点,打开一个powershell.exe加载一个amsi.dll
不同的powershell.exe都有自己的amsi.dll守护,然后上面的脚本只会破坏在运行时powershell.exe进程的amsi.dll,如果再打开一个powershell的话还是会加载amsi.dll。

我们可以看一个例子:

1613917988_60326f24eb103c1be4b4d.png!small?1613917989395

powershell ISE中是执行了脚本的,可以看到成功执行“amsiscanbuffer”,而在powershell.exe中就不可以,提示amsi查杀了。

呃呃呃呃,我们看看在powershel ISE中的情况吧

1613917980_60326f1cd117caaf98bf0.png!small?1613917981397

哈哈哈,还是严谨一点好

其它的话,大家可以自行测试。

二是绕过amsi

AMSI使用“基于字符串”的检测措施来确定PowerShell代码是否为恶意代码。

例子:“amsicanbuffer”

1613917972_60326f14bd921d92d9ee6.png!small?1613917973167

可以看到“amsicanbuffer”触发了amsi,amsi监控查杀了。

我们都知道,字符串检测(特征码)非常容易绕开,只是不要从字面上使用禁止的字符串。使用编码或将其拆分为多个块,然后重新组合可以绕过。那么我们看看能不能绕过amsi监控

PS C:\Users\(123223Li)> $a = "amsis"
PS C:\Users\(123223Li)> $b = "canbuffer"
PS C:\Users\(123223Li)> $c = $a + $b
PS C:\Users\(123223Li)> $c

定义一个变量a 赋值“amsis” 定义一个变量b 赋值“canbuffer”
然后定义一个变量c 赋值为a+b 那么c = a+b = “amsis” + “canbuffer” = amsiscanbuffer
然后直接执行变量c ok 我们来看看能不能绕过amsi吧

哈哈哈哈
我认为行的

1613917964_60326f0c4a913131e6bb8.png!small?1613917964798

果不其然,当然这个不能表示什么,因为一个恶意脚本远不止几个特征码,从定位到修改最后到免杀才是真正的难点,这里变量的转换是一个绕过点

我们来看下一种常见手法,字符串分割:amsicanbuffer

PS C:\Users\(123223Li)> "amsican" + "buffer"
amsicanbuffer

也是可以绕过的

1613917954_60326f02890961f890947.png!small?1613917954890

上面是绕过的,下面是没有绕过的,对比一下。

我们来看第3种的常见绕过手法base64编码

我们base64编码一下:

1613917946_60326efab0c9a59266571.png!small?1613917947170

然后在使用powershell来解码base64并执行。这里为大家好理解,我把命令一步一步来执行

PS C:\Users\(123223Li)> $a = [Convert]::FromBase64String("YW1zaXNjYW5idWZmZXI=") //解码base64
PS C:\Users\(123223Li)> $b = [Text.encoding]::UTF8.GetString($a) //Utf-8转换
PS C:\Users\(123223Li)> $b //执行$b
amsiscanbuffer

也是可以绕过amsi的

1613917936_60326ef037178e7a630fb.png!small?1613917936624

这里要注意,[Convert]::FromBase64String(“YW1zaXNjYW5idWZmZXI=”) 解码出来powershell是不能识别的所以我们要转换一下

1613917927_60326ee764e252b9f1afa.png!small?1613917927971

这里说一句题外话,我们可以看看Cobalt strike中的powershell的木马

1613917918_60326ede421ae145f8761.png!small?1613917918609

可以看到也是经过base64编码的,但是为什么不免杀?单字符免杀不难,但是一个恶意脚本远不止几个特征码,从定位到修改最后到免杀才是真正的难点,当然这里并没有考虑动态,沙盒这些东西。

字符串的免杀的还要10进制编码,16进制编码,hex编码,加密,ox等等手法,也可以多个手法反复使用等等这里就不一一演示,免杀是一个动态对抗的过程。

加油,同路人

给你们看看静态全0的ps1,免杀手法也是基于上面说的。

1613917907_60326ed39a53f4f4663cc.png!small?1613917908227微信图片_20201228235233.png

末完。。。。。

标签: none

来源:freebuf.com 2021-02-21 22:37:45 by: dnsill

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论