文章前言
Windows提供了反恶意软件扫描接口(AMSI)标准,允许开发人员在其应用程序中集成恶意软件防御,AMSI允许应用程序与系统上安装的任何防病毒软件进行交互,并防止执行基于脚本的动态恶意软件,我们将在本文中了解更多关于AMSI、代码实现和一些众所周知的绕过方法
背景介绍
可以使用一句话描述AMSI:AMSI是微软提供的基于脚本的恶意软件扫描API,可以集成到任何应用程序中,以扫描和检测用户输入的完整性,从而保护应用程序,从而保护消费者免受恶意软件的侵害,例如:在应用程序将消息转发给接收者之前扫描带有AMSI的消息以查找恶意软件
AMSI独立于供应商并提供开放的Win32 API和COM接口供开发人员使用,由于Microsoft自己管理AMSI,因此会自动更新最新的恶意软件签名,因此开发人员可以很容易地集成AMSI以保护其消费者免受基于脚本的动态恶意软件的侵害,您可以点击此处阅读开发人员指南。
AMSI适用于基于签名的检测,这意味着对于每个特定的恶意关键字、URL、函数或过程,AMSI在其数据库中都有一个相关的签名,因此如果攻击者再次在他的代码中使用相同的关键字,AMSI就会立即阻止执行
命名约定
在阅读有关AMSI工作原理的更多信息之前,让我们先了解一下恶意软件是如何命名的,通常在分析中Windows会检测到恶意软件,但分析人员无法识别恶意软件的确切细节和行为,计算机防病毒研究组织(CARO)给出了恶意软件的标准命名约定,例如:基于快捷方式的caphaw后门命名如下
工作原理
作为开发人员,您可以使用AMSI提供的AMSI进行恶意软件防御,假设您创建了一个应用程序,该应用程序输入一个脚本并使用Powershell之类的脚本引擎执行它,在进行输入时可以调用AMSI以首先检查恶意软件,Windows提供COM和Win32 API来调用AMSI,AMSI的工作流程如下:
正如您所见AMSI API是开放的,因此任何AV都可以从其函数中读取数据,在这里正在运行一个Windows脚本,当它通过AMSI时,amsi.dll被注入到与我们程序相同的虚拟内存中,这个amsi.dll有各种可以评估代码的函数,这些功能可以在这里找到,但是实际扫描任务由这两个函数执行
- AmsiScanString()
- AmsiScanBuffer()
如果代码是干净的则结果最终会传递给AV提供程序类,然后使用RPC调用从那里传递给AV服务,如果代码可疑则会被AMSI本身阻止
绕过方法
前面已经讨论了AMSI的基础知识,下面我们将讨论一些非常著名的绕过AMSI的技术,为了执行横向移动/特权升级的任意代码,红队人员通常需要绕过AMSI,涵盖所有绕过方法超出了本文的范围,因为每天都有新方法出现,此处讨论了突出的方法并在Windows 10版本1809上进行了测试,值得注意的是最新版本的Windows 1903之后几乎阻止了Internet上可用的所有方法,因为签名不断更新
需要注意的是AMSI会阻止某些关键字,例如:"invoke-mimikatz"或"amsiutils",因为它们被广泛用于漏洞利用,因此作为概念证明我们只会在绕过后运行这些命令,此处不会绕过实际有效负载
Microsoft已将AMSI集成在powershell终端(powershell.exe应用程序)中,该终端接收输入并通过Powershell引擎对其进行解析,如果我们打开进程黑客并搜索amsi.dll,我们会看到amsi正在powershell终端中运行,任何输入都会首先被它扫描
Method 1: Powershell降级处理
如果您正在运行基于powershell的有效负载并且AMSI阻止了它,您可以将您的powershell版本降级到2.0,因为AMSI仅在v2.0之后受支持,首先您可以看到我们的关键字被amsi屏蔽了
之后检查当前PS版本,然后降级到版本2并再次运行这些被阻止的命令
代码语言:javascript复制$PSVersionTable
"amsiutils"
powershell -version 2
"amsiutils"
正如您所看到的那样我们成功绕过了AMSI,这里最大的缺点是许多现代函数或脚本无法在Powershell 2.0上运行
Method 2: Powershell代码混淆
混淆是指使代码复杂且不可读,AMSI根据某些关键字检测签名,因此对这些关键字进行模糊处理是有效的,例如:混淆invoke-mimikatz
代码语言:javascript复制Invoke-Mimikatz
"Inv” "o "ke" "-Mimi" "katz"
如您所见,只需断开一个字符串并使用 运算符将它们连接起来,我们就可以绕过AMSI,然而这种技术有其自身的缺点,有效载荷可能会触发AMSI一次或多次,在每次运行有效负载后逐个混淆关键字实际上是非常耗时且会产生噪音的,因此我们遵循@ShitSecure的这份手动混淆指南
RhytmStick开发了这个工具AmsiTrigger,它可以针对AMSI扫描脚本/有效负载,并告诉我们哪些行会触发AMSI,然后我们可以混淆它们,您可以访问一下链接来下载该工具:
https://github.com/RythmStick/AMSITrigger
现在我们使用以下命令创建了一个名为demo.ps1的脚本
我想使用AmsiTrigger对照AMSI进行检查,这可以像这样完成
代码语言:javascript复制.demo.ps1
.AmsiTrigger.ps1 -i .demo.ps1
现在该工具告诉我AMSI阻止执行的行,我们可以继续使用字符串连接方法对它们进行混淆,例如:
代码语言:javascript复制"am" "si" "ut" "ils"
"in" "vok" "e" "-" "mi" "mik" "atz"
现在它们可以运行并成功绕过AMSI
您也可以尝试https://amsi.fail来混淆您的代码
Method 3: Powershell强制出错
Matt Graeber在他的推文中谈到了绕过AMSI的方法,如果在上述场景中启动AMSI扫描,则存在一个名为amsiInitFailed()的函数,该函数将抛出 0,这种绕过基本上是为amsiInitFailed分配一个布尔True值,以便AMSI初始化失败- 不会对当前进程进行任何扫描,代码是:
代码语言:javascript复制$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076)
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null, $null);[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static").SetValue($null, [IntPtr]$mem)
从那时起许多人发布了相同方法的不同变体,在某些方法中使用字节码,在其他方法中替换函数或替换字符串,但逻辑相同
Method 4: Powershell内存劫持
Daniel Duggan在他的博客中介绍了关于绕过AMSI的内存劫持技术,逻辑是Hook函数AmsiScanBuffer()以便始终返回句柄AMSI_RESULT_CLEAN指示AMSI没有发现恶意软件,可以使用Rohitab的API监控工具监控API响应,首先下载Invoke-Mimikatz脚本,看看AMSI是否正常工作:
现在此处提供了实际代码,为了减少将代码编译为DLL的麻烦,您可以在此处查看我的fork,下载后确保将主包的名称从AmsiScanBufferBypass更改为Project或任何您喜欢的名称,因为AMSI也会阻止字符串AmsiScanBufferBypass
下载后您转到发布文件夹并看到一个名为ASBBypass.dll的DLL,请注意由于我们现在有一个DLL,它也可以与我们的EXE有效负载集成,并且会在旅途中绕过AMSI,但是在这里我们将使用内联C#代码仅使用powershell终端激活补丁,这可以像这样完成
代码语言:javascript复制[System.Reflection.Assembly]::LoadFile("C:usershexProjectASBBypass.dll")
[Amsi]::Bypass()
如您所见AMSI现在已经被绕过了~
Method 5: 内存劫持 混淆操作
在Rasta Mouse(Daniel Duggan)技术开始被检测到后,人们对代码进行了各种更改以使其再次FUD,Fatrodzianko在他的博客中发布了一种这样的技术,他使用操作码混淆了相同的代码,并将脚本放在gist上:
https://gist.github.com/FatRodzianko/c8a76537b5a87b850c7d158728717998#file-my-am-bypass-ps1
要运行脚本只需下载它并重命名它(以避免AMSI检测关键字):
代码语言:javascript复制"invoke-mimikatz"
.my-am-bypass.ps1
"invoke-mimikatz"
Method 6: 通过反射机制绕过
根据微软的说法Reflection提供了描述程序集、模块和类型的对象(Type类型),您可以使用反射来动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性,如果您在代码中使用属性,反射使您能够访问它们
Paul Laine在此处的contextis.com博客上发布了原始的内存劫持方法,Shantanu Khandelwal使用此处提到的Matt Graeber的反射技术将相同的代码转换为完整的内存补丁,Shantanu使代码更加隐秘,因为现在没有留下任何磁盘上的人工制品,在这里查看他的网站
https://www.redteam.cafe/red-team/powershell/using-reflection-for-amsi-bypass
我们不会演示原始补丁但反射更新是从这里下载的,确保下载并重命名脚本并避免使用amsibypass等关键字,因为它们会被阻止,我已将其重命名为am-bp-reflection.ps1
代码语言:javascript复制"invoke-mimikatz"
.am-bp-reflection.ps1
"invoke-mimikatz"
Method 7: Nishang All in One
Nikhil Mittal在他著名的工具Nishang中添加了一个AMSI绕过脚本,可以在这里找到,该脚本结合了6种不同的方法来一次运行绕过AMSI:
- unload – Matt Graeber的方法,从当前PowerShell会话中卸载AMSI
- unload2 – Matt Graeber的另一种方法,从当前PowerShell会话中卸载AMSI
- unloadsilent – Matt Graeber的另一种方法,卸载AMSI并避免WMF5自动记录
- unloadobfuscated - 上面的卸载方法使用Daneil Bohannon的Invoke-Obfuscation进行了混淆 - 这避免了WMF5自动记录
- dllhijack – Cornelis de Plaa的方法,代码中使用的amsi.dll来自p0wnedshell(https://github.com/Cn33liz/p0wnedShell)
- psv2 – 如果.net 2.0.50727在Windows 10上可用,启动不支持AMSI的PowerShell v2
我们只需下载脚本并运行,该工具将使用有效方法自动绕过AMSI,例如:这里WMF5自动记录绕过已经奏效,此方法从当前终端卸载AMSI并绕过它,从这里下载脚本并将其重命名为nishang.ps1并像这样运行它:
代码语言:javascript复制Import-Module .nishang.ps1
Invoke-AmsiBypass -Verbose
"invoke-mimikatz"
文末小结
在本文中我们讨论了AMSI的基础知识、如何在程序中使用它们、工作流程以及绕过它们的7种方法,需要注意的是还有比这里展示的更多的方法,但本文的目的是讨论最广为人知的7种绕过AMSI的方法,以及这种AMSI规避游戏是如何随着时间的推移而发展起来的,以及复杂性是如何增加的,希望你喜欢这篇文章,谢谢阅读