GETPATHS.CMD und AppLocker am WTS

GETPATHS.CMD wird mit aktiviertem AppLocker am Terminalserver geblockt.
Microsoft-Windows-AppLocker/MSI and Script: %OSDRIVE%\USERS\ADM-DOMAIN\APPDATA\LOCAL\TEMP\2\GETPATHS.CMD was prevented from running.

Das „GETPATHS.CMD“ Script wird bei jeder Anmeldung am Terminalserver neu im %TEMP% Verzeichnis generiert und mit aktiviertem AppLocker direkt an der Ausführung gehindert.

Wo kommt das Script „GETPATHS.CMD“ her und was macht es? Während des Anmeldevorgangs am WTS wird die Batchdatei „USERLOGON.CMD“ aus „%WinDir%\System32“ aufgerufen („HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion \Winlogon\Appsetup“ (Set up logon script only for Terminal Server users – Windows Server | Microsoft Learn)). Die „USERLOGON.CMD“ startet dann unter anderem das Script „SETPATHS.CMD“ aus dem Ordner „Application Compatibility Scripts“. In diesem Script wird die „ACRegL.exe“ mit verschiedenen Parametern aufgerufen, welche dann letztlich die „GETPATHS.CMD“ im %TEMP% des Benutzers erstellt, anschließend aufruft und danach wieder löscht. Startet man die „ACRegL.exe“ samt der Parameter, kann man sich das Script ansehen:

Aufruf ACRegL.exe:

"%systemroot%\Application Compatibility Scripts\ACRegL.exe" "%TEMP%\getpaths.cmd" COMMON_PATHS "HKLM\Software" "" GETPATHS

%TEMP%\GETPATHS.CMD:

SET COMMON_START_MENU=C:\ProgramData\Microsoft\Windows\Start Menu
SET COMMON_STARTUP=C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
SET COMMON_PROGRAMS=C:\ProgramData\Microsoft\Windows\Start Menu\Programs
SET USER_START_MENU=C:\Users\<Benutzer>\AppData\Roaming\Microsoft\Windows\Start Menu
SET USER_STARTUP=C:\Users\<Benutzer>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
SET USER_PROGRAMS=C:\Users\<Benutzer>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
SET MY_DOCUMENTS=Documents
SET TEMPLATES=Templates
SET APP_DATA=Roaming

Application Compatibility Scripts?! Die Application Compatibility Scripts stammen ungefähr aus der Zeit, als Gummistiefel noch aus Holz waren. 😉 Gebraucht wurden die Scripte „damals“, um Anwendungen Multi-User – also terminalserverfähig – zu machen.

Welches Problem gibt es jetzt mit AppLocker? Mit den Standard Regeln wird das Ausführen von Scripts im %TEMP% der User nicht erlaubt. Das hat auch durchaus Sinn! Da wo User Schreibrechte haben und somit Dateien erstellen können, sollten die User definitiv keine Scripte / Anwendungen ausführen dürfen.

Aber in der Fehlermeldung aus der Ereignisanzeige („%OSDRIVE%\USERS\ADM-DOMAIN\APPDATA\LOCAL\TEMP\2\GETPATHS.CMD“) steht doch schon die Lösung? Nein! Die AppLocker Regel für Scripts müsste dann mindestens folgendermaßen aussehen: „%OSDRIVE%\USERS\*\APPDATA\LOCAL\TEMP\*\GETPATHS.CMD“. Damit wäre es leider jederzeit möglich eine Datei „GETPATHS.CMD“ in %TEMP% zu platzieren und auszuführen. Das ist eher unschön.

Und jetzt? Einfach blocken. Zumindest gab es in meinen ersten Tests keine Probleme. Allerdings gibt es dann bei jeder Anmeldung eines Benutzers einen entsprechenden Error in der Ereignisanzeige, was ebenfalls sehr unschön ist.

Log Name: Microsoft-Windows-AppLocker/MSI and Script
Source: Microsoft-Windows-AppLocker
Date: 21.12.2022 15:08:45
Event ID: 8007
Task Category: None
Level: Error
Keywords:
User: AD\adm-domain
Computer: JansClient01.ad.adsvc.org
Description:
%OSDRIVE%\USERS\ADM-DOMAIN\APPDATA\LOCAL\TEMP\2\GETPATHS.CMD was prevented from running.

Windows Ereignisanzeige „Microsoft-Windows-AppLocker/MSI and Script“ mit der Event ID 8007

Und jetzt in schön(er)? Passen wir die „SETPATHS.CMD“ per PowerShell Script so an, dass die „GETPATHS.CMD“ nicht mehr ausgeführt wird und die Variablen dennoch gesetzt werden. 😎

$Path = -join(
    $env:windir,
    "\application compatibility scripts\SETPATHS.CMD"
)
$ACL = Get-ACL -Path $Path
$oldOwner = New-Object System.Security.Principal.NTAccount(
    "NT SERVICE",
    "TrustedInstaller"
)
$newOwner = New-Object System.Security.Principal.NTAccount(
    "NT AUTHORITY",
    "SYSTEM"
)
$tmpAR = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "NT AUTHORITY\SYSTEM",
    "Modify",
    "Allow"
)
$oldAR = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "NT AUTHORITY\SYSTEM",
    "ReadandExecute",
    "Allow"
)

# LastWriteTime.Year:
# 2018 -> Windows Server 2019
# 2021 -> Windows Server 2022
# Wird nur einmalig angewendet, falls MS die SETPATHS.CMD mal ändern sollte
$objSPCMD = Get-Item -Path $Path
if($objSPCMD.LastWriteTime.Year -eq "2018" -or $objSPCMD.LastWriteTime.Year -eq "2021"){
    $ACL.SetOwner($newOwner)
    $ACL.SetAccessRule($tmpAR)
    Set-Acl -Path $Path `
        -AclObject $ACL

    $SPContent = [System.IO.StreamReader]::new($Path)
    while($SPContent.EndOfStream -eq $false) {
        $line = $SPContent.ReadLine()
        if($line -eq "Call `"%TEMP%\getpaths.cmd`""){
            $line = -join("REM ", $line, "`n")
            $line += "for /f `"tokens=*`" %%i in ('type `"%TEMP%\getpaths.cmd`"') do %%i"
        }
        $newSPContent += -join($line, "`n")
    }
    $SPContent.Close()

    Set-Content -Path $Path `
        -Value $newSPContent

    $ACL.SetOwner($oldOwner)
    $ACL.RemoveAccessRule($tmpAR)
    $ACL.SetAccessRule($oldAR)
    Set-Acl -Path $Path `
        -AclObject $ACL
}

Was macht das Script und wie wird es gestartet?

  1. Der Pfad zur „SETPATHS.CMD“ wird erstellt, die derzeitige ACL des Files wird ausgelesen und die benötigten Rechte werden definiert
  2. Es wird geprüft, ob es sich noch um die original Datei von Windows Server 2019 oder 2022 handelt
  3. Die ACL wird angepasst und der Besitz vom TrustedInstaller wird auf SYSTEM geändert und SYSTEM bekommt ändern Rechte auf die Datei
  4. Die Datei wird zeilenweise eingelesen und der Aufruf der „GETPATHS.CMD“ wird auskommentiert
  5. Eine neue Zeile wird eingefügt, welche bewirkt, dass die „GETPATHS.CMD“ mit dem type-Befehl ausgegeben wird, wodurch die SET Befehle aus der „GETPAHTS.CMD“ (siehe oben) ausgeführt werden
  6. Die Datei „SETPAHTS.CMD“ wird geschlossen und der neue Inhalt geschrieben
  7. Die geänderten Berechtigungen werden rückgängig gemacht, damit der TrustedInstaller wieder Besitzer ist und SYSTEM die Datei nur noch Lesen und Ausführen darf

Das Script kann jetzt beispielsweise mit einem geplanten Task per Gruppenrichtlinien auf die Remote Desktop Session Hosts gebracht und dort mit dem Trigger „Bei Systemstart“ ausgeführt werden. Alternativ wäre auch ein Computer-StartUp-Script oder eine der vielen Lösungen zur Softwareverteilung denkbar. Möchte man das Script „nur“ im Golden Image / PVS Image ausführen, muss in der FileSystemAccessRule „$tmpAR“ „NT AUTHORITY“ durch die Domäne und „SYSTEM“ durch den User geändert werden. Oder man macht es kurz händisch und kommentiert Zeile 34 durch ein „REM “ am Anfang aus und fügt in die nächste Zeile folgendes „for /f „tokens=*“ %%i in (‚type „%TEMP%\getpaths.cmd“‚) do %%i“ ein. Dann sollte die „SETPAHTS.CMD“ so aussehen:

...
:Cont1
REM Call "%TEMP%\getpaths.cmd"
for /f "tokens=*" %%i in ('type "%TEMP%\getpaths.cmd"') do %%i
Del "%TEMP%\getpaths.cmd" >Nul: 2>&1
...

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.