Zum Inhalt springen
sw
en

Tippe um zu suchen

Scripting & Automatisierung

Skript-Sicherheit: AppLocker, WDAC und Constrained Language Mode

Wie du PowerShell-Skriptausfuehrung mit AppLocker, WDAC und Constrained Language Mode wirklich absicherst - inklusive Audit-Logging und Bypass-Techniken.

13 Min Lesezeit Expert Zuletzt aktualisiert:

Warum ExecutionPolicy dich nicht rettet

Fast jeder IT-Admin kennt Set-ExecutionPolicy RemoteSigned als ersten Reflex, wenn ein Skript nicht laufen will. Das Problem: ExecutionPolicy ist keine Sicherheitsgrenze, sondern ein Komfort-Schalter gegen versehentliches Doppelklicken. Microsoft schreibt das seit Jahren explizit in der eigenen Doku - und trotzdem landet die Policy in praktisch jedem Audit-Bericht als “Kontrolle”, die in Wahrheit keine ist.

Der Beweis ist trivial:

# ExecutionPolicy umgehen - Standardrepertoire jedes Pentests
powershell.exe -ExecutionPolicy Bypass -File .\evil.ps1

# Oder einfach den Inhalt per Pipe einspeisen, Policy greift gar nicht erst
Get-Content .\evil.ps1 | powershell.exe -Command -

# Oder Base64-kodiert direkt ausfuehren
powershell.exe -EncodedCommand <Base64String>

Keine dieser Techniken erfordert Admin-Rechte. Ein normaler Benutzer kann ExecutionPolicy fuer seinen eigenen Prozess-Scope jederzeit selbst setzen. Das heisst nicht, dass ExecutionPolicy nutzlos ist - AllSigned in Kombination mit einer echten Signierpipeline hat durchaus Wert als Regressions-Schutz. Aber gegen einen Angreifer, der bereits Code auf dem System ausfuehren will, ist es ein Papier-Zaun.

Die echten Kontrollen heissen AppLocker, Windows Defender Application Control (WDAC) und - als Konsequenz aus beiden - der PowerShell Constrained Language Mode. Diese Seite baut auf PowerShell im IT-Alltag und PowerShell-Scripting vertieft auf und zeigt, wie du Skriptausfuehrung im Schweizer KMU tatsaechlich kontrollierst - inklusive der Bypasses, die du kennen musst, um sie zu schliessen.

AppLocker: Regelbasierte Ausfuehrungskontrolle

AppLocker existiert seit Windows 7 / Server 2008 R2 und ist in den Enterprise- und Education-Editionen von Windows sowie in allen Server-SKUs enthalten (nicht in Windows Pro). Es arbeitet mit vier Regel-Kategorien, die jeweils eigene Whitelists sind:

  • Executable Rules (.exe, .com)
  • Script Rules (.ps1, .vbs, .js, .cmd, .bat)
  • Windows Installer Rules (.msi, .msp)
  • Packaged App Rules (MSIX/APPX)
  • DLL Rules (optional, deaktiviert standardmaessig wegen Performance-Impact)

Jede Regel basiert auf einem von drei Bedingungstypen:

BedingungstypBeschreibungSicherheitWartungsaufwand
Pfad (Path)z.B. %PROGRAMFILES%\*niedrig - Angreifer kann Datei einfach dorthin kopierengering
Herausgeber (Publisher)Digitale Signatur + Product/File-Name, optional mit Versionsbereichhoch - ueberlebt Updates, bindet an Zertifikatmittel
Hash (File Hash)SHA-256-Hash der konkreten Dateisehr hoch fuer diese eine Datei, bricht bei jedem Updatehoch

In der Praxis baust du Publisher-Regeln fuer signierte Software (Microsoft, deine ERP-Software, dein RMM-Tool) und Hash-Regeln fuer interne, unsignierte Skripte, die sich selten aendern.

AppLocker per GPO einrichten

# Lokale Testrichtlinie exportieren, um eine Ausgangsbasis zu haben
Get-AppLockerPolicy -Local -Xml | Out-File C:\Temp\AppLocker-Baseline.xml

# Automatisch Regeln aus vorhandenen, signierten EXEs im Programme-Ordner generieren
New-AppLockerPolicy -RuleType Publisher -User Everyone `
    -DirectoryPath "C:\Program Files" -Optimize | Out-File C:\Temp\AppLocker-AutoRules.xml

Danach importierst du die XML in eine GPO unter Computerkonfiguration > Richtlinien > Windows-Einstellungen > Sicherheitseinstellungen > Anwendungssteuerungsrichtlinien > AppLocker. Wichtig: Der Windows-Dienst Application Identity (AppIDSvc) muss laufen, sonst greifen die Regeln nicht - ein klassischer Stolperstein, den GPOs standardmaessig nicht selbst starten.

# Dienst per GPO-Preference oder direkt setzen (Testumgebung)
Set-Service -Name AppIDSvc -StartupType Automatic
Start-Service -Name AppIDSvc

Die Grenzen von AppLocker

AppLocker hat drei strukturelle Schwaechen, die du kennen musst, bevor du dich darauf verlaesst:

  1. Kein Kernel-Modus-Schutz. AppLocker laeuft im User-Mode. Ein Prozess mit lokalen Administratorrechten kann den AppIDSvc-Dienst stoppen oder die Regeln per Registry manipulieren.
  2. DLL-Regeln sind standardmaessig aus. Ohne DLL-Regeln kann Code weiterhin ueber DLL-Sideloading oder Reflection nachgeladen werden.
  3. Microsoft investiert nicht mehr aktiv in AppLocker. Laut Microsoft-Doku erhaelt AppLocker nur noch Sicherheitsupdates, keine neuen Features. Fuer Neuprojekte empfiehlt Microsoft explizit WDAC (App Control for Business).

Fuer ein KMU mit gemischter Umgebung (manche Clients Pro-Edition, manche Enterprise) bleibt AppLocker trotzdem oft die pragmatischere Wahl, weil WDAC deutlich mehr Vorarbeit braucht. Die Entscheidung ist also nicht “immer WDAC”, sondern situativ.

WDAC: Kernel-Modus-Kontrolle mit Code Integrity

Windows Defender Application Control (mittlerweile offiziell “App Control for Business” genannt) ist der Nachfolger von AppLocker und arbeitet fundamental anders: Es nutzt die Code-Integrity-Engine im Kernel (CI.dll), nicht einen User-Mode-Dienst. Das macht es robuster gegen lokale Manipulation - selbst ein Administrator kann eine aktive, signierte WDAC-Policy nicht einfach per Dienst-Stopp aushebeln.

WDAC-Policies sind XML-Dateien, die zu einer Binaerdatei (.cip) kompiliert und im Boot-Pfad des Systems verankert werden. Ab Windows 10 1903 werden Multiple Policy Format Policies unterstuetzt - du kannst mehrere Policies parallel fahren (z.B. Basis-Policy fuer alle Clients + Zusatz-Policy pro Abteilung).

Eine WDAC-Policy erstellen

# Referenz-Policy aus einem "goldenen" Referenzsystem scannen
New-CIPolicy -Level Publisher -FilePath C:\WDAC\InitialScan.xml `
    -ScanPath "C:\" -UserPEs -Fallback Hash -MultiplePolicyFormat

# Microsoft-Basis-Policies als Startpunkt nutzen (mitgeliefert unter C:\Windows\schemas\CodeIntegrity\ExamplePolicies)
Copy-Item "C:\Windows\schemas\CodeIntegrity\ExamplePolicies\DefaultWindows_Enforced.xml" `
    -Destination C:\WDAC\Base.xml

# Policy zunaechst im Audit-Modus (Regel-Option 3) belassen
Set-RuleOption -FilePath C:\WDAC\Base.xml -Option 3

# XML in binaeres Format kompilieren
ConvertFrom-CIPolicy -XmlFilePath C:\WDAC\Base.xml -BinaryFilePath C:\WDAC\Base.cip

# Policy lokal bereitstellen (Windows 10 1903+, Multiple Policy Format)
Copy-Item C:\WDAC\Base.cip "C:\Windows\System32\CodeIntegrity\CiPolicies\Active\"

Zur Verteilung im Unternehmen nutzt du in der Praxis Intune (Endpoint Security > App Control fuer Windows) statt manueller Kopie - das ist fuer die meisten Schweizer KMU mit M365-Anbindung der realistischere Weg als reine GPO-Verteilung. Siehe dazu auch Intune-Grundlagen und SCCM/Intune-Softwareverteilung.

AppLocker vs. WDAC im Vergleich

KriteriumAppLockerWDAC / App Control for Business
DurchsetzungsebeneUser-Mode-Dienst (AppIDSvc)Kernel-Mode (Code Integrity Engine)
Verfuegbare EditionenWindows Enterprise/Education, ServerWindows 10/11 alle Editionen (eingeschraenkt in Home), Server
Umgehbar durch lokalen AdminJa, Dienst stoppbarNein, sofern Policy signiert und verankert
VerwaltungstoolGPO-Editor (GUI)Nur PowerShell/XML, Intune-Policy fuer Verteilung
AuditierbarkeitGut (Event-ID 8003/8004)Sehr gut (Code Integrity Events 3076/3077/3089)
Microsoft-InvestitionNur SicherheitsfixesAktive Weiterentwicklung
EinstiegshuerdeNiedrigHoch (XML-Policy-Design, Testing)
Empfehlung fuer SkriptkontrolleSolide Basis, schnell umsetzbarZiel-Zustand fuer hohe Sicherheitsanforderungen

Fuer die meisten KMU ist ein pragmatischer Pfad: AppLocker als Sofortmassnahme fuer Skriptregeln ausrollen, WDAC parallel fuer neue oder besonders exponierte Systeme (Terminalserver, Kiosk-PCs, Server mit Internetzugriff) pilotieren. Siehe Terminalserver/RDS-Support fuer den typischen Einsatzort, an dem Skriptkontrolle am wichtigsten ist.

PowerShell Constrained Language Mode

Der entscheidende Effekt von AppLocker und WDAC fuer PowerShell ist nicht primaer “Skript X darf nicht laufen” - sondern dass PowerShell selbst automatisch in einen eingeschraenkten Sprachmodus wechselt, sobald eine Application-Control-Policy aktiv ist. Das ist der eigentliche Hebel gegen Angreifer, die PowerShell fuer Post-Exploitation nutzen (Mimikatz-Loader, In-Memory-Payloads, Reflection-basierte AMSI-Bypasses).

PowerShell kennt vier Sprachmodi:

ModusVerhalten
FullLanguageKein Limit - Standard fuer normale Nutzer ohne Policy
ConstrainedLanguageNur zugelassene .NET-Typen, kein Add-Type, kein COM, kein direkter Win32-API-Zugriff
RestrictedLanguageNur Basisbefehle, keine Variablenzuweisung mit Ausdruecken, kein Pipelining komplexer Objekte
NoLanguageKeine Skriptsprache erlaubt, nur einzelne Cmdlet-Aufrufe

Im ConstrainedLanguage Mode funktionieren weiterhin alle Cmdlets - aber .NET-Klassen ausserhalb einer Zulassungsliste (im Wesentlichen primitive Typen wie String, Int, Array) werden blockiert. Konkret bedeutet das:

# Funktioniert im ConstrainedLanguage Mode weiterhin
Get-Process | Where-Object CPU -gt 100
Get-ADUser -Filter * | Export-Csv report.csv

# Schlaegt im ConstrainedLanguage Mode fehl
Add-Type -TypeDefinition '...'                    # kein beliebiger C#-Code
[System.Runtime.InteropServices.Marshal]::Copy(...) # kein Win32-API via Reflection
New-Object -ComObject "WScript.Shell"              # kein COM

# Aktuellen Modus pruefen
$ExecutionContext.SessionState.LanguageMode

Der Modus wird automatisch gesetzt: Sobald AppLocker im Enforce-Modus laeuft oder eine WDAC-Policy mit Script-Enforcement aktiv ist, laufen alle Skripte, die nicht explizit von der Policy zugelassen sind, automatisch in ConstrainedLanguage. Skripte, die die Policy erlaubt (z.B. weil sie signiert und in der Publisher-Regel gelistet sind), laufen weiterhin in FullLanguage.

Manuelles Erzwingen ohne AppLocker/WDAC

Fuer Testzwecke oder als Uebergangsloesung laesst sich der Modus auch direkt per Umgebungsvariable oder Registry setzen:

# Nur fuer die aktuelle Sitzung (Testzwecke)
$env:__PSLockdownPolicy = 4  # 4 = ConstrainedLanguage

# Systemweit per Registry (nicht signaturbasiert, daher schwaecher als AppLocker/WDAC)
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" `
    -Name "__PSLockdownPolicy" -PropertyType String -Value "4" -Force

Script Block Logging und Transcription fuer Audit

Kontrolle ist die eine Haelfte, Nachvollziehbarkeit die andere. Selbst mit AppLocker/WDAC solltest du protokollieren, was tatsaechlich ausgefuehrt wird - insbesondere, weil auch erlaubte Skripte boesartig sein koennen (kompromittiertes, aber signiertes Tool) und weil Audit-Modus-Policies gerade keine Skripte blockieren, sondern nur loggen.

Script Block Logging (Event 4104)

; GPO-Pfad:
; Computerkonfiguration > Richtlinien > Administrative Vorlagen >
; Windows-Komponenten > Windows PowerShell >
; "Protokollierung von PowerShell-Skriptblöcken aktivieren" = Aktiviert

Alternativ per Registry (z.B. fuer Systeme ohne Domain-GPO):

New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Force
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" `
    -Name "EnableScriptBlockLogging" -Value 1

Damit landet jeder ausgefuehrte Skriptblock - inklusive de-obfuskiertem Code, PowerShell loest z.B. -EncodedCommand automatisch auf - als Event-ID 4104 im Log Microsoft-Windows-PowerShell/Operational. Das ist der wichtigste einzelne Logging-Hebel gegen verschleierte Angriffsskripte.

// Beispiel: KQL-Query fuer Microsoft Sentinel / Log Analytics
// Sucht nach verdaechtigen Schluesselwoertern in geloggten Skriptbloecken
Event
| where Source == "Microsoft-Windows-PowerShell"
| where EventID == 4104
| where EventData has_any ("DownloadString", "IEX", "Invoke-Expression", "FromBase64String", "-nop", "-w hidden")
| project TimeGenerated, Computer, EventData
| order by TimeGenerated desc

Transcription: Vollstaendiger Sitzungsmitschnitt

; GPO-Pfad:
; Windows-Komponenten > Windows PowerShell >
; "Transkription aktivieren" = Aktiviert
; Ausgabeverzeichnis: \\fileserver\PSLogs$\%COMPUTERNAME%

Transcription schreibt jede Ein- und Ausgabe einer PowerShell-Sitzung als Textdatei mit. Anders als Script Block Logging erfasst es auch interaktiv eingetippte Befehle in ihrer Rohform, inklusive Timestamps pro Sitzung. Der Nachteil: hohes Datenvolumen, daher in der Praxis meist nur auf priviligierten Jump-Hosts oder Servern mit direktem Internetzugang aktiviert, nicht flaechendeckend auf allen Clients.

Modul-Logging als dritte Komponente

Ergaenzend gibt es Module Logging (Event 4103), das pro Cmdlet-Aufruf Pipeline-Ausfuehrungsdetails protokolliert - nuetzlich, wenn Script Block Logging durch tief verschachtelte Obfuskation umgangen wird. Aktivierung ebenfalls per GPO unter “Module-Protokollierung aktivieren” mit Modulnamen * fuer alle Module.

AMSI: Die vierte Verteidigungslinie

Neben AppLocker/WDAC und den Logging-Mechanismen spielt das Antimalware Scan Interface (AMSI) eine zentrale Rolle. AMSI erlaubt es PowerShell (und anderen Skript-Hosts wie VBA, JScript), Skriptinhalte vor der Ausfuehrung an den installierten Virenscanner (z.B. Microsoft Defender) zur Analyse zu uebergeben - auch nach Deobfuskation zur Laufzeit. Das ist der Grund, warum simple String-Verschleierung (“I”+“EX”) heute meist nicht mehr reicht, um Erkennung zu umgehen.

AMSI ist kein Ersatz fuer AppLocker/WDAC, sondern eine zusaetzliche Schicht: WDAC entscheidet, ob ein Skript ueberhaupt in FullLanguage laufen darf, AMSI scannt den tatsaechlichen Inhalt auf bekannte Schadmuster. Beide zusammen mit Constrained Language Mode ergeben ein mehrschichtiges Modell (Defense in Depth), bei dem der Ausfall einer Schicht nicht gleich das ganze System kompromittiert.

Bypass-Techniken - kennen, um sich abzusichern

Diese Techniken dienen ausschliesslich dazu, deine eigene Absicherung zu haerten und Findings in einem Penetrationstest richtig einzuordnen. Wer sie nur zum Umgehen von Kontrollen in fremden oder nicht autorisierten Systemen nutzt, macht sich strafbar.

1. Downgrade auf PowerShell 2.0

# PS 2.0 kennt kein Script Block Logging, kein AMSI, kein Constrained Language Mode
powershell.exe -Version 2 -Command "..."

Gegenmassnahme: Das optionale Feature “Windows PowerShell 2.0” muss deinstalliert werden - es ist nicht mehr Bestandteil aktueller Windows-11-Installationen, aber auf aelteren Servern oft noch vorhanden.

Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2
Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root

2. Ausweichen auf andere Interpreter

Wenn nur .ps1-Dateien per AppLocker-Skriptregel kontrolliert werden, aber keine allgemeine Prozessregel fuer cscript.exe, mshta.exe, wscript.exe oder rundll32.exe existiert, kann ein Angreifer auf diese Interpreter ausweichen (“Living off the Land Binaries”, LOLBins).

Gegenmassnahme: Executable-Regeln muessen alle relevanten Interpreter abdecken, nicht nur powershell.exe. Eine reine Skript-Regel-Sammlung ohne begleitende Executable-Regeln ist Stueckwerk.

3. In-Memory-Ausfuehrung ueber .NET direkt

# Umgeht ps1-Dateiregeln komplett, da kein Skript auf Platte liegt
[System.Reflection.Assembly]::Load($byteArray)

Gegenmassnahme: Genau das ist der Grund, warum WDAC mit Constrained Language Mode wichtiger ist als reine Dateiregeln - Assembly.Load auf beliebige .NET-Typen wird im ConstrainedLanguage Mode selbst blockiert, unabhaengig davon, ob eine Datei auf der Platte liegt.

4. Signierte, aber verwundbare Skripte missbrauchen (Bring Your Own Vulnerable Script)

Ein legitim signiertes PowerShell-Skript, das selbst Invoke-Expression auf externe Eingaben anwendet, laesst sich als “vertrauenswuerdiger Traeger” fuer eigentlich blockierten Code missbrauchen.

Gegenmassnahme: WDAC-Regelsaetze regelmaessig gegen bekannte “LOLBAS”-Listen pruefen (lolbas-project.github.io) und Skripte, die dynamischen Code aus externen Quellen laden, explizit von Publisher-Whitelists ausschliessen.

Entscheidungsablauf fuer dein KMU

  1. Bestandsaufnahme: Welche Editionen laufen im Feld (Pro vs. Enterprise)? AppLocker braucht Enterprise/Education, WDAC ist editionsunabhaengiger.
  2. Logging zuerst. Aktiviere Script Block Logging und Modul-Logging flaechendeckend per GPO, bevor du irgendeine Enforce-Policy einfuehrst. Ohne Sichtbarkeit fliegst du blind.
  3. Audit-Modus vor Enforce. Sowohl AppLocker als auch WDAC bieten reine Beobachtungsmodi. Mindestens zwei bis vier Wochen Praxisdaten sammeln, dann auswerten.
  4. Pilotgruppe. Erzwinge zuerst auf einer kleinen, gut ueberwachten Gruppe (z.B. IT-Abteilung selbst), nie direkt unternehmensweit.
  5. Ausrollen nach Risiko priorisiert. Terminalserver, exponierte Server mit Internetzugriff und Kiosk-Systeme zuerst, normale Fachabteilungs-Clients zuletzt.
  6. Laufender Regel-Unterhalt. Jedes Softwareupdate kann Hash-Regeln brechen - Publisher-Regeln bevorzugen und einen Prozess etablieren, wie neue Business-Software schnell freigegeben wird, ohne die Policy komplett zu oeffnen.

Weiterlernen

Kommentare

Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.

  • Lade Kommentare …
Kommentar schreiben