mirror of
https://github.com/ironhulk-0xff/WindowsSentinel
synced 2026-08-09 12:41:21 +00:00
2349 lines
119 KiB
Batchfile
2349 lines
119 KiB
Batchfile
@echo off
|
|
setlocal EnableExtensions EnableDelayedExpansion
|
|
|
|
:: ============================================================
|
|
:: Deploy-WDAC.bat - WindowsSentinel WDAC Deployment Tool
|
|
::
|
|
:: Usage:
|
|
:: Deploy-WDAC.bat /setup - Full setup wizard (Audit Mode)
|
|
:: Deploy-WDAC.bat /enforce - Switch deployed policy to Enforce Mode
|
|
:: Deploy-WDAC.bat /report - Generate audit report only
|
|
:: Deploy-WDAC.bat /remove - Remove the deployed policy
|
|
:: Deploy-WDAC.bat /harden - Enforce policy + apply insider threat hardening
|
|
:: Deploy-WDAC.bat /help - Show full help and step descriptions
|
|
::
|
|
:: Run as Administrator.
|
|
:: ============================================================
|
|
|
|
net session >nul 2>&1
|
|
if %errorLevel% neq 0 (
|
|
echo ERROR: Please run this script as Administrator.
|
|
pause
|
|
exit /b 1
|
|
)
|
|
|
|
:: Set console width for full-screen display
|
|
mode con: cols=120 lines=50
|
|
|
|
:: ============================================================
|
|
:: GLOBAL VARIABLES
|
|
:: ============================================================
|
|
set "WDAC_FOLDER=C:\WDAC"
|
|
set "POLICY_NAME=WindowsSentinelPolicy"
|
|
set "BASE_TEMPLATE=C:\Windows\schemas\CodeIntegrity\ExamplePolicies\DefaultWindows_Enforced.xml"
|
|
set "XML_PATH=C:\WDAC\WSSentinel.xml"
|
|
|
|
set SETUP_MODE=0
|
|
set ENFORCE_MODE=0
|
|
set ENFORCE_DLL=0
|
|
set ENFORCE_SYS=0
|
|
set ENFORCE_PS1=0
|
|
set ENFORCE_SCRIPTS=0
|
|
set ENFORCE_HTA=0
|
|
set ENFORCE_WSF=0
|
|
set ENFORCE_PKG=0
|
|
set ALLOW_COPYPASTE=0
|
|
set "EXT_LIST="
|
|
set REPORT_ONLY=0
|
|
set REMOVE_MODE=0
|
|
set HARDEN_MODE=0
|
|
set FAST_DEPLOY=0
|
|
set HELP_MODE=0
|
|
|
|
if /i "%1"=="/setup" set SETUP_MODE=1
|
|
if /i "%1"=="/enforce" set ENFORCE_MODE=1
|
|
if /i "%1"=="/report" set REPORT_ONLY=1
|
|
if /i "%1"=="/remove" set REMOVE_MODE=1
|
|
if /i "%1"=="/help" set HELP_MODE=1
|
|
if /i "%1"=="/harden" set HARDEN_MODE=1
|
|
|
|
:: /help - show full help then exit
|
|
if "!HELP_MODE!"=="1" goto SHOW_HELP
|
|
|
|
:: No flag supplied - print short usage and exit
|
|
if "!SETUP_MODE!!ENFORCE_MODE!!REPORT_ONLY!!REMOVE_MODE!!HARDEN_MODE!"=="00000" goto SHOW_USAGE
|
|
|
|
:: Create WDAC folder immediately so /report and /remove modes work
|
|
if not exist "%WDAC_FOLDER%" mkdir "%WDAC_FOLDER%"
|
|
|
|
cls
|
|
echo ============================================================
|
|
echo WDAC Policy Deployment - WindowsSentinel v1
|
|
echo ============================================================
|
|
echo.
|
|
echo Author : Ironhulk
|
|
echo Telegram : @ironhulk_0xff
|
|
echo X (Twitter) : @ironhulk_0xff
|
|
echo.
|
|
echo ============================================================
|
|
echo.
|
|
echo WindowsSentinel deploys a Windows Defender Application Control
|
|
echo policy that restricts which programs are allowed to run on
|
|
echo this machine. Only Microsoft-signed binaries and apps you
|
|
echo explicitly whitelist will be permitted to execute.
|
|
echo.
|
|
echo The policy runs in two stages:
|
|
echo Audit Mode - Monitors and logs what would be blocked.
|
|
echo Nothing is blocked yet. Safe to explore.
|
|
echo Enforce Mode - Actively blocks unauthorized executables.
|
|
echo Only whitelisted apps will run.
|
|
echo.
|
|
echo All policy files are stored in C:\WDAC\
|
|
echo Recovery script : C:\WDAC\Remove-WDAC.ps1
|
|
echo Full help : Deploy-WDAC.bat /help
|
|
echo.
|
|
echo ============================================================
|
|
echo IMPORTANT SECURITY NOTICE
|
|
echo ============================================================
|
|
echo.
|
|
echo Some Antivirus (AV) and Endpoint Detection and Response (EDR)
|
|
echo products may block, quarantine, or interfere with WDAC policy
|
|
echo generation and deployment.
|
|
echo.
|
|
echo If you encounter errors during execution:
|
|
echo - Temporarily disable tamper protection if permitted.
|
|
echo - Add this script and C:\WDAC\ to your AV/EDR exclusions.
|
|
echo - Restore any files quarantined by your security software.
|
|
echo.
|
|
echo Supported AV/EDR products can be detected automatically later
|
|
echo in the deployment process.
|
|
echo.
|
|
echo ============================================================
|
|
echo.
|
|
if "!REMOVE_MODE!"=="1" goto DO_REMOVE
|
|
if "!HARDEN_MODE!"=="1" goto DO_HARDEN
|
|
if "!REPORT_ONLY!"=="1" goto GENERATE_REPORT
|
|
if "!ENFORCE_MODE!"=="1" goto DO_ENFORCE_ENTRY
|
|
|
|
:: ============================================================
|
|
:: STEP 0 - WDAC PRE-FLIGHT CHECK
|
|
:: ============================================================
|
|
echo [STEP 0] Checking existing WDAC policies on this machine...
|
|
echo.
|
|
echo Press enter to start or ctrl+c to exit...
|
|
|
|
:: Call citool directly from batch - avoids stdin/stdout issues when
|
|
:: calling from inside PowerShell. Output is written to a temp file.
|
|
set "CITOOL_OUT=%WDAC_FOLDER%\citool_out.txt"
|
|
set "CITOOL_AVAILABLE=0"
|
|
where citool.exe >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set CITOOL_AVAILABLE=1
|
|
powershell -Command "citool.exe --list-policies | Out-File -FilePath 'C:\WDAC\citool_out.txt' -Encoding UTF8 -Force"
|
|
)
|
|
|
|
set "PF=%WDAC_FOLDER%\preflight_check.ps1"
|
|
if exist "%PF%" del "%PF%"
|
|
|
|
>> "%PF%" echo $citoolAvailable = [int]%CITOOL_AVAILABLE%
|
|
>> "%PF%" echo $outFile = "C:\WDAC\citool_out.txt"
|
|
>> "%PF%" echo if ($citoolAvailable -eq 0 -or -not (Test-Path $outFile)) {
|
|
>> "%PF%" echo Write-Host " [SKIP] citool.exe not found (requires Windows 11)."
|
|
>> "%PF%" echo Write-Host " Skipping pre-flight check - proceeding manually."
|
|
>> "%PF%" echo exit 0
|
|
>> "%PF%" echo }
|
|
>> "%PF%" echo $raw = Get-Content $outFile -ErrorAction SilentlyContinue
|
|
>> "%PF%" echo Remove-Item $outFile -Force -ErrorAction SilentlyContinue
|
|
>> "%PF%" echo $policies = [System.Collections.Generic.List[hashtable]]::new()
|
|
>> "%PF%" echo $current = $null
|
|
>> "%PF%" echo foreach ($line in $raw) {
|
|
>> "%PF%" echo $l = $line.Trim()
|
|
>> "%PF%" echo if ($l -eq "Policy:") {
|
|
>> "%PF%" echo if ($current) { $policies.Add($current) }
|
|
>> "%PF%" echo $current = @{ ID=""; BasePolicyID=""; Name=""; Platform=$false; Enforced=$false; Authorized=$false; OnDisk=$false }
|
|
>> "%PF%" echo continue
|
|
>> "%PF%" echo }
|
|
>> "%PF%" echo if (-not $current) { continue }
|
|
>> "%PF%" echo if ($l -match "^Policy ID:\s+(.+)") { $current.ID = $Matches[1].Trim() }
|
|
>> "%PF%" echo if ($l -match "^Base Policy ID:\s+(.+)") { $current.BasePolicyID = $Matches[1].Trim() }
|
|
>> "%PF%" echo if ($l -match "^Friendly Name:\s+(.+)") { $current.Name = $Matches[1].Trim() }
|
|
>> "%PF%" echo if ($l -match "^Platform Policy:\s+(.+)") { $current.Platform = ($Matches[1].Trim() -eq "true") }
|
|
>> "%PF%" echo if ($l -match "^Is Currently Enforced:\s+(.+)") { $current.Enforced = ($Matches[1].Trim() -eq "true") }
|
|
>> "%PF%" echo if ($l -match "^Is Authorized:\s+(.+)") { $current.Authorized = ($Matches[1].Trim() -eq "true") }
|
|
>> "%PF%" echo if ($l -match "^Has File on Disk:\s+(.+)") { $current.OnDisk = ($Matches[1].Trim() -eq "true") }
|
|
>> "%PF%" echo }
|
|
>> "%PF%" echo if ($current) { $policies.Add($current) }
|
|
>> "%PF%" echo $enforced = @($policies ^| Where-Object { $_.Enforced })
|
|
>> "%PF%" echo $platform = @($policies ^| Where-Object { $_.Enforced -and $_.Platform })
|
|
>> "%PF%" echo $userDeploy = @($policies ^| Where-Object { $_.Enforced -and -not $_.Platform })
|
|
>> "%PF%" echo $sacPolicy = @($policies ^| Where-Object { $_.Name -match "VerifiedAndReputable[^E]" -and $_.Enforced })
|
|
>> "%PF%" echo $sacOn = ($sacPolicy.Count -gt 0)
|
|
>> "%PF%" echo $conflicts = $false
|
|
>> "%PF%" echo Write-Host " Policies detected : $($policies.Count)"
|
|
>> "%PF%" echo Write-Host " Currently enforced : $($enforced.Count)"
|
|
>> "%PF%" echo Write-Host " Microsoft platform : $($platform.Count)"
|
|
>> "%PF%" echo Write-Host " User/enterprise : $($userDeploy.Count)"
|
|
>> "%PF%" echo Write-Host ""
|
|
>> "%PF%" echo if ($sacOn) {
|
|
>> "%PF%" echo Write-Host " [WARN] Smart App Control is ON"
|
|
>> "%PF%" echo Write-Host " SAC uses its own WDAC base policy which may conflict"
|
|
>> "%PF%" echo Write-Host " with WindowsSentinel. Recommended: disable SAC first."
|
|
>> "%PF%" echo Write-Host " Settings > Privacy and Security > Windows Security > App and Browser Control"
|
|
>> "%PF%" echo Write-Host ""
|
|
>> "%PF%" echo $conflicts = $true
|
|
>> "%PF%" echo } else {
|
|
>> "%PF%" echo Write-Host " [OK] Smart App Control : OFF"
|
|
>> "%PF%" echo }
|
|
>> "%PF%" echo if ($platform.Count -gt 0) {
|
|
>> "%PF%" echo Write-Host " [OK] Microsoft platform policies (managed by Windows - safe):"
|
|
>> "%PF%" echo foreach ($p in $platform) {
|
|
>> "%PF%" echo $status = if ($p.Enforced) { "ENFORCED" } else { "inactive" }
|
|
>> "%PF%" echo $n = $p.Name
|
|
>> "%PF%" echo if ($n.Length -gt 55) { $n = $n.Substring(0,52) + "..." }
|
|
>> "%PF%" echo Write-Host (" {0,-56} [{1}]" -f $n, $status)
|
|
>> "%PF%" echo }
|
|
>> "%PF%" echo Write-Host ""
|
|
>> "%PF%" echo }
|
|
>> "%PF%" echo if ($userDeploy.Count -gt 0) {
|
|
>> "%PF%" echo Write-Host " [WARN] Non-platform enforced policies found - possible conflicts:"
|
|
>> "%PF%" echo foreach ($p in $userDeploy) {
|
|
>> "%PF%" echo Write-Host " Name : $($p.Name)"
|
|
>> "%PF%" echo Write-Host " ID : $($p.ID)"
|
|
>> "%PF%" echo Write-Host " This policy may conflict with WindowsSentinel rules."
|
|
>> "%PF%" echo Write-Host ""
|
|
>> "%PF%" echo }
|
|
>> "%PF%" echo $conflicts = $true
|
|
>> "%PF%" echo } else {
|
|
>> "%PF%" echo Write-Host " [OK] No conflicting enterprise or third-party WDAC policies"
|
|
>> "%PF%" echo }
|
|
>> "%PF%" echo Write-Host ""
|
|
>> "%PF%" echo if ($conflicts) {
|
|
>> "%PF%" echo Write-Host " Result: WARNINGS DETECTED - review before continuing."
|
|
>> "%PF%" echo exit 2
|
|
>> "%PF%" echo } else {
|
|
>> "%PF%" echo Write-Host " Result: PRE-FLIGHT PASSED - safe to proceed."
|
|
>> "%PF%" echo exit 0
|
|
>> "%PF%" echo }
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%PF%"
|
|
set PREFLIGHT_RESULT=%errorLevel%
|
|
del "%PF%" >nul 2>&1
|
|
echo.
|
|
|
|
if "!PREFLIGHT_RESULT!"=="2" (
|
|
echo --------------------------------------------------------
|
|
echo One or more warnings were detected above.
|
|
echo Deploying WindowsSentinel on top of conflicting policies
|
|
echo may block legitimate software or behave unexpectedly.
|
|
echo.
|
|
set "PREFLIGHT_CHOICE="
|
|
set /p PREFLIGHT_CHOICE=" Continue anyway? [Y/N]: "
|
|
if /i "!PREFLIGHT_CHOICE!" neq "Y" (
|
|
echo Setup cancelled.
|
|
goto END_NOCLEAN
|
|
)
|
|
echo.
|
|
)
|
|
|
|
:: ============================================================
|
|
:: STEP 1 - PREREQUISITES
|
|
:: ============================================================
|
|
echo [STEP 1] Checking prerequisites...
|
|
echo.
|
|
|
|
if not exist "%BASE_TEMPLATE%" (
|
|
echo ERROR: Base template not found:
|
|
echo %BASE_TEMPLATE%
|
|
echo This script requires Windows 10/11 Enterprise or Server 2016+.
|
|
pause & exit /b 1
|
|
)
|
|
|
|
powershell -Command "Get-Command ConvertFrom-CIPolicy -ErrorAction SilentlyContinue" >nul 2>&1
|
|
if %errorLevel% neq 0 (
|
|
echo ERROR: ConfigCI PowerShell module not found.
|
|
echo This script requires Windows 10/11 Enterprise or Server 2016+.
|
|
pause & exit /b 1
|
|
)
|
|
|
|
echo [+] Prerequisites passed.
|
|
echo.
|
|
|
|
:: ============================================================
|
|
:: STEP 2 - FILE EXTENSION SELECTION
|
|
:: ============================================================
|
|
echo [STEP 2] File extension enforcement...
|
|
echo.
|
|
echo Select which file types to enforce:
|
|
echo.
|
|
echo +-----+---------------+--------------------------------------------------+
|
|
echo ^| No. ^| Extension ^| Description ^|
|
|
echo +-----+---------------+--------------------------------------------------+
|
|
echo ^| 1 ^| .exe ^| Executables (apps, tools, programs) ^|
|
|
echo ^| 2 ^| .dll ^| Libraries (loaded into running processes) ^|
|
|
echo ^| 3 ^| .sys ^| Kernel drivers ^|
|
|
echo ^| 4 ^| .ps1 ^| PowerShell scripts ^|
|
|
echo ^| 5 ^| .bat / .cmd ^| Batch scripts ^|
|
|
echo ^| 6 ^| .vbs / .js ^| VBScript / JScript ^|
|
|
echo ^| 7 ^| .hta ^| HTML Applications (common attack vector) ^|
|
|
echo ^| 8 ^| .wsf / .wsh ^| Windows Script Host files ^|
|
|
echo ^| 9 ^| .appx / .msix ^| Package installers (Store / sideloaded apps) ^|
|
|
echo ^| A ^| ALL ^| All of the above (recommended) ^|
|
|
echo +-----+---------------+--------------------------------------------------+
|
|
echo.
|
|
echo You can combine options separated by commas.
|
|
echo Examples: 1 = EXE only
|
|
echo 1,2,3 = EXE, DLL and SYS
|
|
echo 1,2,7,8 = EXE, DLL and both script attack vectors
|
|
echo A = All extensions
|
|
echo.
|
|
echo Note: Options 4,5,6,7,8 all use script enforcement (Policy Option 16).
|
|
echo Selecting any one of them enables it for all script types.
|
|
echo.
|
|
|
|
:ASK_EXT
|
|
set "EXT_CHOICE="
|
|
set /p EXT_CHOICE=" Enter your selection: "
|
|
|
|
if /i "!EXT_CHOICE!"=="A" (
|
|
set ENFORCE_DLL=1
|
|
set ENFORCE_SYS=1
|
|
set ENFORCE_PS1=1
|
|
set ENFORCE_SCRIPTS=1
|
|
set ENFORCE_HTA=1
|
|
set ENFORCE_WSF=1
|
|
set ENFORCE_PKG=1
|
|
set "EXT_LIST=.exe .dll .sys .ps1 .bat .cmd .vbs .js .hta .wsf .wsh .appx .msix"
|
|
goto EXT_DONE
|
|
)
|
|
|
|
:: Validate - only digits 1-9 and commas allowed
|
|
powershell -Command "$p='!EXT_CHOICE!' -split ',' | ForEach-Object {$_.Trim()}; if(($p | Where-Object {$_ -notmatch '^[1-9]$'}).Count -gt 0){exit 1}else{exit 0}" >nul 2>&1
|
|
if %errorLevel% neq 0 (
|
|
echo INVALID: Use numbers 1-9 separated by commas, or A for all.
|
|
goto ASK_EXT
|
|
)
|
|
|
|
:: Pad with commas to prevent partial number matches
|
|
set "PADDED=,!EXT_CHOICE!,"
|
|
|
|
echo !PADDED! | findstr /c:",1," >nul 2>&1
|
|
if not errorlevel 1 set "EXT_LIST=!EXT_LIST! .exe"
|
|
|
|
echo !PADDED! | findstr /c:",2," >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set ENFORCE_DLL=1
|
|
set "EXT_LIST=!EXT_LIST! .dll"
|
|
)
|
|
|
|
echo !PADDED! | findstr /c:",3," >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set ENFORCE_SYS=1
|
|
set "EXT_LIST=!EXT_LIST! .sys"
|
|
)
|
|
|
|
echo !PADDED! | findstr /c:",4," >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set ENFORCE_PS1=1
|
|
set ENFORCE_SCRIPTS=1
|
|
set "EXT_LIST=!EXT_LIST! .ps1"
|
|
)
|
|
|
|
echo !PADDED! | findstr /c:",5," >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set ENFORCE_SCRIPTS=1
|
|
set "EXT_LIST=!EXT_LIST! .bat .cmd"
|
|
)
|
|
|
|
echo !PADDED! | findstr /c:",6," >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set ENFORCE_SCRIPTS=1
|
|
set "EXT_LIST=!EXT_LIST! .vbs .js"
|
|
)
|
|
|
|
echo !PADDED! | findstr /c:",7," >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set ENFORCE_HTA=1
|
|
set ENFORCE_SCRIPTS=1
|
|
set "EXT_LIST=!EXT_LIST! .hta"
|
|
)
|
|
|
|
echo !PADDED! | findstr /c:",8," >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set ENFORCE_WSF=1
|
|
set ENFORCE_SCRIPTS=1
|
|
set "EXT_LIST=!EXT_LIST! .wsf .wsh"
|
|
)
|
|
|
|
echo !PADDED! | findstr /c:",9," >nul 2>&1
|
|
if not errorlevel 1 (
|
|
set ENFORCE_PKG=1
|
|
set "EXT_LIST=!EXT_LIST! .appx .msix"
|
|
)
|
|
|
|
:EXT_DONE
|
|
echo.
|
|
echo Extensions selected: !EXT_LIST!
|
|
echo.
|
|
|
|
if "!ENFORCE_DLL!"=="0" (
|
|
echo NOTE: DLL enforcement is OFF.
|
|
echo Malicious DLLs injected into trusted processes will not be blocked.
|
|
echo.
|
|
)
|
|
if "!ENFORCE_SYS!"=="0" (
|
|
echo NOTE: Kernel driver enforcement is OFF.
|
|
echo Unsigned kernel drivers will be allowed to load.
|
|
echo.
|
|
)
|
|
if "!ENFORCE_SCRIPTS!"=="1" (
|
|
echo WARNING: Script enforcement is ON.
|
|
echo This covers: .ps1 .bat .cmd .vbs .js .hta .wsf .wsh
|
|
echo This script ^(Deploy-WDAC.bat^) WILL BE BLOCKED after Enforce Mode activates.
|
|
echo Keep the rollback script ^(Remove-WDAC.ps1^) accessible in case you need recovery.
|
|
echo.
|
|
)
|
|
if "!ENFORCE_PKG!"=="1" (
|
|
echo NOTE: Package enforcement is ON.
|
|
echo Only Microsoft-signed .appx/.msix packages will be allowed to install.
|
|
echo.
|
|
)
|
|
|
|
:: ============================================================
|
|
:: STEP 3 - VMWARE COPY/PASTE
|
|
:: ============================================================
|
|
echo [STEP 3] VMware Tools configuration...
|
|
echo.
|
|
echo If this machine is a VMware VM, VMware Tools provides:
|
|
echo - Copy/paste between host and VM
|
|
echo - Drag and drop, display scaling
|
|
echo.
|
|
|
|
:ASK_COPYPASTE
|
|
set "CP_CHOICE="
|
|
set /p CP_CHOICE=" Whitelist VMware Tools? [Y/N]: "
|
|
if /i "!CP_CHOICE!"=="Y" (
|
|
set ALLOW_COPYPASTE=1
|
|
echo [+] VMware Tools will be whitelisted.
|
|
goto CP_DONE
|
|
)
|
|
if /i "!CP_CHOICE!"=="N" (
|
|
echo VMware Tools will be blocked.
|
|
goto CP_DONE
|
|
)
|
|
echo Please enter Y or N.
|
|
goto ASK_COPYPASTE
|
|
|
|
:CP_DONE
|
|
echo.
|
|
|
|
:: ============================================================
|
|
:: STEP 4 - AV/EDR AUTO-DETECT
|
|
:: ============================================================
|
|
echo [STEP 4] Scanning for AV/EDR products...
|
|
echo.
|
|
echo ============================================================
|
|
echo Supported AV / EDR Detection Targets
|
|
echo ============================================================
|
|
echo This script automatically detects installed security products
|
|
echo and can generate WDAC allow rules for the following vendors:
|
|
echo - Cybereason
|
|
echo - CrowdStrike Falcon
|
|
echo - SentinelOne
|
|
echo - VMware Carbon Black (Bit9)
|
|
echo - Trend Micro
|
|
echo - McAfee
|
|
echo - Symantec / Broadcom Symantec
|
|
echo - Sophos
|
|
echo - ESET
|
|
echo - Kaspersky
|
|
echo - Bitdefender
|
|
echo - Cylance
|
|
echo - Palo Alto Networks (Cortex XDR)
|
|
echo - Elastic Security
|
|
echo - Malwarebytes
|
|
echo Detection is performed by checking common installation paths
|
|
echo under Program Files. Additional products can be added by
|
|
echo extending the $products array in detect_av.ps1.
|
|
echo ============================================================
|
|
|
|
set "DS=%WDAC_FOLDER%\detect_av.ps1"
|
|
if exist "%DS%" del "%DS%"
|
|
|
|
>> "%DS%" echo $products = @(
|
|
>> "%DS%" echo @{Name="Cybereason"; Path="C:\Program Files\Cybereason*"},
|
|
>> "%DS%" echo @{Name="CrowdStrike"; Path="C:\Program Files\CrowdStrike*"},
|
|
>> "%DS%" echo @{Name="SentinelOne"; Path="C:\Program Files\SentinelOne*"},
|
|
>> "%DS%" echo @{Name="Carbon Black"; Path="C:\Program Files\Bit9*"},
|
|
>> "%DS%" echo @{Name="Carbon Black"; Path="C:\Program Files\VMware\VMware Carbon Black*"},
|
|
>> "%DS%" echo @{Name="Trend Micro"; Path="C:\Program Files\Trend Micro*"},
|
|
>> "%DS%" echo @{Name="McAfee"; Path="C:\Program Files\McAfee*"},
|
|
>> "%DS%" echo @{Name="Symantec"; Path="C:\Program Files\Symantec*"},
|
|
>> "%DS%" echo @{Name="Symantec"; Path="C:\Program Files\Broadcom\Symantec*"},
|
|
>> "%DS%" echo @{Name="Sophos"; Path="C:\Program Files\Sophos*"},
|
|
>> "%DS%" echo @{Name="ESET"; Path="C:\Program Files\ESET*"},
|
|
>> "%DS%" echo @{Name="Kaspersky"; Path="C:\Program Files\Kaspersky*"},
|
|
>> "%DS%" echo @{Name="Bitdefender"; Path="C:\Program Files\Bitdefender*"},
|
|
>> "%DS%" echo @{Name="Cylance"; Path="C:\Program Files\Cylance*"},
|
|
>> "%DS%" echo @{Name="Palo Alto"; Path="C:\Program Files\Palo Alto Networks*"},
|
|
>> "%DS%" echo @{Name="Elastic"; Path="C:\Program Files\Elastic*"},
|
|
>> "%DS%" echo @{Name="Malwarebytes"; Path="C:\Program Files\Malwarebytes*"}
|
|
>> "%DS%" echo )
|
|
>> "%DS%" echo $detected = @()
|
|
>> "%DS%" echo foreach ($p in $products) {
|
|
>> "%DS%" echo $found = Get-Item -Path $p.Path -ErrorAction SilentlyContinue
|
|
>> "%DS%" echo if ($found) {
|
|
>> "%DS%" echo $fp = $found.FullName + "\*"
|
|
>> "%DS%" echo if (-not ($detected ^| Where-Object { $_.Path -eq $fp })) {
|
|
>> "%DS%" echo $detected += @{Name=$p.Name; Path=$fp}
|
|
>> "%DS%" echo Write-Host " [+] Found: $($p.Name) at $($found.FullName)"
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo try {
|
|
>> "%DS%" echo $sc = Get-CimInstance -Namespace root\SecurityCenter2 -ClassName AntiVirusProduct -EA SilentlyContinue
|
|
>> "%DS%" echo foreach ($s in $sc) {
|
|
>> "%DS%" echo if ($s.pathToSignedProductExe -and (Test-Path $s.pathToSignedProductExe)) {
|
|
>> "%DS%" echo $dir = Split-Path $s.pathToSignedProductExe -Parent
|
|
>> "%DS%" echo $fp = $dir + "\*"
|
|
>> "%DS%" echo if (-not ($detected ^| Where-Object { $_.Path -eq $fp })) {
|
|
>> "%DS%" echo $detected += @{Name=$s.displayName; Path=$fp}
|
|
>> "%DS%" echo Write-Host " [+] Found via SecurityCenter: $($s.displayName) at $dir"
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo } catch {}
|
|
>> "%DS%" echo $kw = @("crowdstrike","falcon","sentinel","cylance","carbonblack","cybereason","elastic","edr","sophos","eset","kaspersky","bitdefender","mcafee","symantec","malwarebytes")
|
|
>> "%DS%" echo $svcs = Get-WmiObject Win32_Service -EA SilentlyContinue ^| Where-Object { $_.PathName -and $_.State -eq "Running" }
|
|
>> "%DS%" echo foreach ($svc in $svcs) {
|
|
>> "%DS%" echo $nl = $svc.Name.ToLower()
|
|
>> "%DS%" echo $pl = $svc.PathName.ToLower()
|
|
>> "%DS%" echo $m = $kw ^| Where-Object { $nl -match $_ -or $pl -match $_ }
|
|
>> "%DS%" echo if ($m) {
|
|
>> "%DS%" echo $exe = $svc.PathName -replace '"','' -replace ' -.*',''
|
|
>> "%DS%" echo if (Test-Path $exe) {
|
|
>> "%DS%" echo $dir = Split-Path $exe -Parent
|
|
>> "%DS%" echo $fp = $dir + "\*"
|
|
>> "%DS%" echo if (-not ($detected ^| Where-Object { $_.Path -eq $fp })) {
|
|
>> "%DS%" echo $detected += @{Name=$svc.DisplayName; Path=$fp}
|
|
>> "%DS%" echo Write-Host " [+] Found via service: $($svc.DisplayName) at $dir"
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo }
|
|
>> "%DS%" echo if ($detected.Count -eq 0) { Write-Host " No third-party AV/EDR products detected." }
|
|
>> "%DS%" echo $detected ^| ForEach-Object { $_.Path } ^| Out-File "C:\WDAC\detected_av_paths.txt" -Encoding ASCII
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%DS%"
|
|
echo.
|
|
|
|
:: ============================================================
|
|
:: STEP 5 - INSTALLED APP SCANNER (NEW)
|
|
:: ============================================================
|
|
echo [STEP 5] Scanning installed applications...
|
|
echo.
|
|
echo Scanning Program Files for installed software.
|
|
echo This may take a moment...
|
|
echo.
|
|
|
|
set "AS=%WDAC_FOLDER%\scan_apps.ps1"
|
|
if exist "%AS%" del "%AS%"
|
|
|
|
>> "%AS%" echo $scanPaths = @("C:\Program Files", "C:\Program Files (x86)")
|
|
>> "%AS%" echo $apps = [System.Collections.Generic.List[PSObject]]::new()
|
|
>> "%AS%" echo $idx = 0
|
|
>> "%AS%" echo foreach ($sp in $scanPaths) {
|
|
>> "%AS%" echo if (-not (Test-Path $sp)) { continue }
|
|
>> "%AS%" echo $folders = Get-ChildItem $sp -Directory -ErrorAction SilentlyContinue
|
|
>> "%AS%" echo foreach ($folder in $folders) {
|
|
>> "%AS%" echo $exe = Get-ChildItem $folder.FullName -Filter "*.exe" -Recurse -Depth 2 -ErrorAction SilentlyContinue ^| Select-Object -First 1
|
|
>> "%AS%" echo if (-not $exe) { continue }
|
|
>> "%AS%" echo # Skip if a folder with the same name was already found in the other scan path
|
|
>> "%AS%" echo if ($apps ^| Where-Object { $_.Name -eq $folder.Name }) { continue }
|
|
>> "%AS%" echo $idx++
|
|
>> "%AS%" echo $isSigned = $false
|
|
>> "%AS%" echo $pubName = "UNSIGNED"
|
|
>> "%AS%" echo # Stage 1: embedded cert check - fast, no network, no CRL calls
|
|
>> "%AS%" echo # Catches most commercial apps (Firefox, Chrome, WinRAR, etc.)
|
|
>> "%AS%" echo try {
|
|
>> "%AS%" echo $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::CreateFromSignedFile($exe.FullName)
|
|
>> "%AS%" echo if ($cert -and $cert.Subject) {
|
|
>> "%AS%" echo $isSigned = $true
|
|
>> "%AS%" echo $subj = $cert.Subject
|
|
>> "%AS%" echo $pubName = if ($subj -match 'CN=([^,]+)') { $Matches[1] } else { $subj }
|
|
>> "%AS%" echo }
|
|
>> "%AS%" echo } catch {}
|
|
>> "%AS%" echo # Stage 2: catalog cert check - only runs if Stage 1 found nothing
|
|
>> "%AS%" echo # Catches Windows-bundled apps signed via catalog (IE, WMP, Windows Mail, etc.)
|
|
>> "%AS%" echo # Slightly slower but only fires for a small number of apps
|
|
>> "%AS%" echo if (-not $isSigned) {
|
|
>> "%AS%" echo try {
|
|
>> "%AS%" echo $sig = Get-AuthenticodeSignature $exe.FullName -ErrorAction SilentlyContinue
|
|
>> "%AS%" echo if ($sig -and $sig.Status -eq "Valid" -and $sig.SignerCertificate) {
|
|
>> "%AS%" echo $isSigned = $true
|
|
>> "%AS%" echo $subj = $sig.SignerCertificate.Subject
|
|
>> "%AS%" echo $pubName = if ($subj -match 'CN=([^,]+)') { $Matches[1] } else { $subj }
|
|
>> "%AS%" echo }
|
|
>> "%AS%" echo } catch {}
|
|
>> "%AS%" echo }
|
|
>> "%AS%" echo $apps.Add([PSCustomObject]@{
|
|
>> "%AS%" echo Index = $idx
|
|
>> "%AS%" echo Name = $folder.Name
|
|
>> "%AS%" echo Path = $folder.FullName
|
|
>> "%AS%" echo MainExe = $exe.FullName
|
|
>> "%AS%" echo Publisher= $pubName
|
|
>> "%AS%" echo RuleType = if ($isSigned) { "Publisher" } else { "Path" }
|
|
>> "%AS%" echo Signed = $isSigned
|
|
>> "%AS%" echo })
|
|
>> "%AS%" echo }
|
|
>> "%AS%" echo }
|
|
>> "%AS%" echo $apps ^| ConvertTo-Json -Depth 3 ^| Out-File "C:\WDAC\detected_apps.json" -Encoding UTF8
|
|
>> "%AS%" echo Write-Host (" {0,4} {1,-38} {2,-12} {3}" -f "No.", "Application", "Rule Type", "Publisher")
|
|
>> "%AS%" echo Write-Host (" {0,4} {1,-38} {2,-12} {3}" -f "----", "----------------------------------", "----------", "--------------------------")
|
|
>> "%AS%" echo foreach ($app in $apps) {
|
|
>> "%AS%" echo $n = $app.Name
|
|
>> "%AS%" echo if ($n.Length -gt 38) { $n = $n.Substring(0,35) + "..." }
|
|
>> "%AS%" echo $pub = $app.Publisher
|
|
>> "%AS%" echo if ($pub.Length -gt 30) { $pub = $pub.Substring(0,28) + ".." }
|
|
>> "%AS%" echo Write-Host (" {0,4} {1,-38} {2,-12} {3}" -f $app.Index, $n, $app.RuleType, $pub)
|
|
>> "%AS%" echo }
|
|
>> "%AS%" echo Write-Host ""
|
|
>> "%AS%" echo Write-Host " Total: $($apps.Count) applications found."
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%AS%"
|
|
|
|
echo.
|
|
echo Rule type explanation:
|
|
echo Publisher = App is signed (embedded or catalog cert found).
|
|
echo Rule is tied to the signing certificate.
|
|
echo Only files from that publisher are trusted - more secure.
|
|
echo Path = App has no detectable signature.
|
|
echo Rule is tied to the install folder location.
|
|
echo Anything placed in that folder will run - weaker.
|
|
echo.
|
|
echo All of the above apps will be WHITELISTED (allowed to run).
|
|
echo Enter numbers to EXCLUDE from the whitelist (separated by commas).
|
|
echo Excluded apps will be BLOCKED in Enforce Mode.
|
|
echo Press ENTER with nothing typed to allow ALL apps listed above.
|
|
echo.
|
|
|
|
set "EXCLUDE_LIST="
|
|
set /p EXCLUDE_LIST=" Exclude numbers (or press ENTER for all): "
|
|
echo.
|
|
|
|
if "!EXCLUDE_LIST!"=="" (
|
|
echo [+] All detected applications will be whitelisted.
|
|
) else (
|
|
echo [+] Excluding apps: !EXCLUDE_LIST!
|
|
)
|
|
|
|
:: Write exclusions file - used by build and report scripts
|
|
echo !EXCLUDE_LIST!> "%WDAC_FOLDER%\app_exclusions.txt"
|
|
echo.
|
|
|
|
:: ============================================================
|
|
:: STEP 6 - LOLBAS DENY LIST
|
|
:: ============================================================
|
|
echo [STEP 6] LOLBAS - Living Off The Land Binaries deny list...
|
|
echo.
|
|
echo The following Microsoft-signed binaries are commonly abused
|
|
echo by attackers to execute code without dropping new files.
|
|
echo Select which ones to DENY on this machine.
|
|
echo.
|
|
echo +------+----------------------------------+-------------------------------+---------+
|
|
echo ^| No. ^| Binary ^| Abuse Technique ^| Impact ^|
|
|
echo +------+----------------------------------+-------------------------------+---------+
|
|
echo ^| 1 ^| msbuild.exe ^| Inline C# via .csproj ^| Low ^|
|
|
echo ^| 2 ^| regsvr32.exe ^| COM scriptlet execution ^| Medium ^|
|
|
echo ^| 3 ^| rundll32.exe ^| DLL/script via exports ^| HIGH ^|
|
|
echo ^| 4 ^| certutil.exe ^| File download / base64 decode ^| Low ^|
|
|
echo ^| 5 ^| installutil.exe ^| .NET WDAC bypass ^| Low ^|
|
|
echo ^| 6 ^| regasm.exe ^| .NET COM execution ^| Low ^|
|
|
echo ^| 7 ^| regsvcs.exe ^| .NET COM+ execution ^| Low ^|
|
|
echo ^| 8 ^| cmstp.exe ^| UAC bypass / INF execution ^| Low ^|
|
|
echo ^| 9 ^| odbcconf.exe ^| DLL via ODBC response file ^| Low ^|
|
|
echo ^| 10 ^| cscript.exe ^| JScript/VBScript execution ^| HIGH ^|
|
|
echo ^| 11 ^| wscript.exe ^| JScript/VBScript execution ^| HIGH ^|
|
|
echo ^| 12 ^| mshta.exe ^| HTA/JScript/VBScript ^| Medium ^|
|
|
echo ^| 13 ^| powershell.exe ^| PowerShell execution ^| CRIT ^|
|
|
echo ^| 14 ^| pwsh.exe ^| PowerShell 7 execution ^| HIGH ^|
|
|
echo ^| 15 ^| presentationhost.exe ^| XAML execution ^| Low ^|
|
|
echo ^| 16 ^| ieexec.exe ^| .NET remote execution ^| Low ^|
|
|
echo ^| 17 ^| microsoft.workflow.compiler.exe ^| Workflow compile-and-execute ^| Low ^|
|
|
echo ^| 18 ^| desktopimgdownldr.exe ^| Payload retrieval via reg key ^| Low ^|
|
|
echo ^| 19 ^| syncappvpublishingserver.exe ^| Script execution via App-V ^| Low ^|
|
|
echo ^| 20 ^| bash.exe ^| WSL abuse ^| Medium ^|
|
|
echo ^| 21 ^| wsl.exe ^| WSL abuse ^| Medium ^|
|
|
echo ^| 22 ^| ftp.exe ^| File transfer / exfil ^| Low ^|
|
|
echo ^| 23 ^| bitsadmin.exe ^| Payload download (legacy) ^| Low ^|
|
|
echo ^| 24 ^| forfiles.exe ^| Command execution via files ^| Low ^|
|
|
echo ^| 25 ^| pcalua.exe ^| App Compat Layer execution ^| Low ^|
|
|
echo ^| 26 ^| verclsid.exe ^| COM object execution ^| Low ^|
|
|
echo ^| 27 ^| mofcomp.exe ^| WMI MOF compile/execute ^| Medium ^|
|
|
echo ^| 28 ^| msiexec.exe ^| MSI-based code execution ^| CRIT ^|
|
|
echo ^| 29 ^| dxcap.exe ^| DLL loading abuse ^| Low ^|
|
|
echo ^| 30 ^| cmd.exe ^| Shell / batch execution ^| HIGH ^|
|
|
echo ^| 31 ^| wt.exe ^| Windows Terminal launcher ^| Medium ^|
|
|
echo +------+----------------------------------+-------------------------------+---------+
|
|
echo.
|
|
echo Impact: Low/Medium = Safe to deny on production machines
|
|
echo HIGH = May break admin tools or legacy software
|
|
echo CRIT = Requires extra confirmation (see warnings below)
|
|
echo.
|
|
echo Note: options 10,11,12 deny the binary itself.
|
|
echo Stronger than extension enforcement which only blocks script files.
|
|
echo.
|
|
echo Examples: 1,4,5,18 = Deny msbuild, certutil, installutil, desktopimgdownldr
|
|
echo A = Deny all 31 (CRIT items will prompt for confirmation)
|
|
echo S = Skip - no deny rules added
|
|
echo.
|
|
|
|
:ASK_LOLBAS
|
|
set "LOLBAS_CHOICE="
|
|
set /p LOLBAS_CHOICE=" Enter selection (or S to skip): "
|
|
|
|
if /i "!LOLBAS_CHOICE!"=="S" (
|
|
echo [+] No LOLBAS deny rules will be added.
|
|
echo.> "%WDAC_FOLDER%\lolbas_deny.txt"
|
|
goto LOLBAS_DONE
|
|
)
|
|
|
|
if /i "!LOLBAS_CHOICE!"=="A" set "LOLBAS_CHOICE=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31"
|
|
|
|
powershell -Command "$p='!LOLBAS_CHOICE!' -split ',' | ForEach-Object {$_.Trim()}; if(($p | Where-Object {$_ -notmatch '^([1-9]|[12][0-9]|3[01])$'}).Count -gt 0){exit 1}else{exit 0}" >nul 2>&1
|
|
if !errorLevel! neq 0 (
|
|
echo INVALID: Use numbers 1-31 separated by commas, A for all, or S to skip.
|
|
goto ASK_LOLBAS
|
|
)
|
|
|
|
set "LOLBAS_PADDED=,!LOLBAS_CHOICE!,"
|
|
|
|
:: Check CRITICAL and HIGH items - each has its own confirmation flow
|
|
echo !LOLBAS_PADDED! | findstr /c:",3," >nul 2>&1
|
|
if not errorlevel 1 goto WARN_RUNDLL32
|
|
goto CHECK_POWERSHELL
|
|
|
|
:WARN_RUNDLL32
|
|
echo.
|
|
echo WARNING: rundll32.exe (option 3)
|
|
echo ---------------------------------------------------------
|
|
echo Denying rundll32.exe will block:
|
|
echo - Classic Control Panel applets (.cpl files)
|
|
echo e.g. Display, Date/Time, Programs and Features
|
|
echo - Legacy third-party installers that call rundll32 directly
|
|
echo - Screensaver configuration dialogs
|
|
echo.
|
|
echo NOT affected:
|
|
echo - Modern Windows Settings app (ms-settings://)
|
|
echo - All standard Windows 10/11 functionality using Settings
|
|
echo - GPO-managed machines where Control Panel is already restricted
|
|
echo.
|
|
echo If this machine uses the Settings app and modern software,
|
|
echo denying rundll32 is generally safe.
|
|
echo When in doubt, run in Audit Mode first and check Event ID 3077.
|
|
echo ---------------------------------------------------------
|
|
echo.
|
|
set "RUNDLL_CONFIRM="
|
|
set /p RUNDLL_CONFIRM=" Confirm deny rundll32.exe? [Y/N]: "
|
|
if /i "!RUNDLL_CONFIRM!"=="Y" goto CHECK_POWERSHELL
|
|
echo Removing rundll32.exe from selection.
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:,3,=,!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:3,=!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:,3=!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:3=!"
|
|
set "LOLBAS_PADDED=,!LOLBAS_CHOICE!,"
|
|
echo.
|
|
|
|
:CHECK_POWERSHELL
|
|
echo !LOLBAS_PADDED! | findstr /c:",13," >nul 2>&1
|
|
if not errorlevel 1 goto WARN_POWERSHELL
|
|
goto CHECK_MSIEXEC
|
|
|
|
:WARN_POWERSHELL
|
|
echo.
|
|
echo CRITICAL: powershell.exe (option 13)
|
|
echo ---------------------------------------------------------
|
|
echo Denying powershell.exe will block:
|
|
echo - ALL PowerShell usage on this machine
|
|
echo - This deployment script itself (uses PowerShell internally)
|
|
echo - Windows Remote Management (WinRM / PSRemoting)
|
|
echo - Many Windows admin and management tools
|
|
echo - Some Windows Update and maintenance components
|
|
echo.
|
|
echo This is an extreme lockdown measure. Only select this if:
|
|
echo - PowerShell has already been replaced by another remote
|
|
echo management solution on this machine
|
|
echo - You have an alternative way to manage the machine
|
|
echo - You understand the rollback script also uses PowerShell
|
|
echo.
|
|
echo RECOMMENDATION: Do not deny powershell.exe. Use script
|
|
echo enforcement (Step 2 option 4) to block unsigned .ps1 files
|
|
echo instead - this is the right balance for most environments.
|
|
echo ---------------------------------------------------------
|
|
echo.
|
|
set "PS_CONFIRM="
|
|
set /p PS_CONFIRM=" Confirm deny powershell.exe? [Y/N]: "
|
|
if /i "!PS_CONFIRM!"=="Y" goto CHECK_MSIEXEC
|
|
echo Removing powershell.exe from selection.
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:,13,=,!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:13,=!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:,13=!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:13=!"
|
|
set "LOLBAS_PADDED=,!LOLBAS_CHOICE!,"
|
|
echo.
|
|
|
|
:CHECK_MSIEXEC
|
|
echo !LOLBAS_PADDED! | findstr /c:",28," >nul 2>&1
|
|
if not errorlevel 1 goto WARN_MSIEXEC
|
|
goto LOLBAS_SAVE
|
|
|
|
:WARN_MSIEXEC
|
|
echo.
|
|
echo CRITICAL: msiexec.exe (option 28)
|
|
echo ---------------------------------------------------------
|
|
echo Denying msiexec.exe will block:
|
|
echo - ALL MSI-based software installation
|
|
echo - Some Windows Update components that deliver MSI packages
|
|
echo - Software removal and repair via Programs and Features
|
|
echo - Group Policy software deployment if it uses MSI
|
|
echo.
|
|
echo This is appropriate only on fully locked-down machines
|
|
echo where software is managed through a different mechanism
|
|
echo (e.g. MSIX packages, SCCM without MSI, or image-based).
|
|
echo ---------------------------------------------------------
|
|
echo.
|
|
set "MSI_CONFIRM="
|
|
set /p MSI_CONFIRM=" Confirm deny msiexec.exe? [Y/N]: "
|
|
if /i "!MSI_CONFIRM!"=="Y" goto LOLBAS_SAVE
|
|
echo Removing msiexec.exe from selection.
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:,28,=,!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:28,=!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:,28=!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:28=!"
|
|
echo.
|
|
|
|
:CHECK_CMD
|
|
echo !LOLBAS_PADDED! | findstr /c:",30," >nul 2>&1
|
|
if not errorlevel 1 goto WARN_CMD
|
|
goto CHECK_WT
|
|
|
|
:WARN_CMD
|
|
echo.
|
|
echo WARNING: cmd.exe (option 30)
|
|
echo ---------------------------------------------------------
|
|
echo Denying cmd.exe will block:
|
|
echo - This script (Deploy-WDAC.bat) after Enforce Mode activates
|
|
echo - All batch (.bat/.cmd) file execution including signed ones
|
|
echo - Windows internal maintenance and installer operations
|
|
echo - Any tool or script that shells out to cmd.exe
|
|
echo.
|
|
echo RECOMMENDATION: Use script enforcement (Step 2 option 5) to
|
|
echo block unsigned .bat/.cmd files instead. That stops attacker
|
|
echo scripts without breaking Windows internals or this tool.
|
|
echo ---------------------------------------------------------
|
|
echo.
|
|
set "CMD_CONFIRM="
|
|
set /p CMD_CONFIRM=" Confirm deny cmd.exe? [Y/N]: "
|
|
if /i "!CMD_CONFIRM!"=="Y" goto CHECK_WT
|
|
echo Removing cmd.exe from selection.
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:,30,=,!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:30,=!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:,30=!"
|
|
set "LOLBAS_CHOICE=!LOLBAS_CHOICE:30=!"
|
|
set "LOLBAS_PADDED=,!LOLBAS_CHOICE!,"
|
|
echo.
|
|
|
|
:CHECK_WT
|
|
|
|
:LOLBAS_SAVE
|
|
echo [+] LOLBAS deny list: !LOLBAS_CHOICE!
|
|
echo !LOLBAS_CHOICE!> "%WDAC_FOLDER%\lolbas_deny.txt"
|
|
echo.
|
|
|
|
:LOLBAS_DONE
|
|
|
|
:: ============================================================
|
|
:: STEP 7 - BUILD POLICY
|
|
:: ============================================================
|
|
echo [STEP 7] Building WDAC policy...
|
|
echo.
|
|
|
|
set "BS=%WDAC_FOLDER%\build_policy.ps1"
|
|
if exist "%BS%" del "%BS%"
|
|
|
|
>> "%BS%" echo $xmlPath = "C:\WDAC\WSSentinel.xml"
|
|
>> "%BS%" echo $base = "C:\Windows\schemas\CodeIntegrity\ExamplePolicies\DefaultWindows_Enforced.xml"
|
|
>> "%BS%" echo $enforceDLL = [int]%ENFORCE_DLL%
|
|
>> "%BS%" echo $enforceScr = ([int]%ENFORCE_SCRIPTS%) -bor ([int]%ENFORCE_PS1%)
|
|
>> "%BS%" echo $enforcePkg = [int]%ENFORCE_PKG%
|
|
>> "%BS%" echo $copyPaste = [int]%ALLOW_COPYPASTE%
|
|
>> "%BS%" echo $exRaw = (Get-Content "C:\WDAC\app_exclusions.txt" -ErrorAction SilentlyContinue) -join ""
|
|
>> "%BS%" echo $exNums = $exRaw -split ',' ^| ForEach-Object { $_.Trim() } ^| Where-Object { [int32]::TryParse($_, [ref]$null) } ^| ForEach-Object { [int]$_ }
|
|
>> "%BS%" echo Write-Host " Copying base template..."
|
|
>> "%BS%" echo Copy-Item $base $xmlPath -Force
|
|
>> "%BS%" echo $g = Set-CIPolicyIdInfo -FilePath $xmlPath -PolicyName "WindowsSentinelPolicy" -ResetPolicyID
|
|
>> "%BS%" echo $guidOnly = [regex]::Match($g, '\{[0-9a-fA-F-]+\}').Value
|
|
>> "%BS%" echo Write-Host " GUID: $guidOnly"
|
|
>> "%BS%" echo $guidOnly ^| Out-File "C:\WDAC\policy_guid.txt" -Encoding ASCII -NoNewline
|
|
>> "%BS%" echo if ($enforceDLL -eq 0) {
|
|
>> "%BS%" echo Set-RuleOption -FilePath $xmlPath -Option 19
|
|
>> "%BS%" echo Write-Host " [Option 19] DLL enforcement: OFF"
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo Set-RuleOption -FilePath $xmlPath -Option 19 -Delete -ErrorAction SilentlyContinue
|
|
>> "%BS%" echo Write-Host " [Option 19] DLL enforcement: ON"
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($enforceScr -eq 0) {
|
|
>> "%BS%" echo Set-RuleOption -FilePath $xmlPath -Option 16
|
|
>> "%BS%" echo Write-Host " [Option 16] Script enforcement: OFF"
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo Set-RuleOption -FilePath $xmlPath -Option 16 -Delete -ErrorAction SilentlyContinue
|
|
>> "%BS%" echo Write-Host " [Option 16] Script enforcement: ON"
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($enforcePkg -eq 1) {
|
|
>> "%BS%" echo Set-RuleOption -FilePath $xmlPath -Option 20 -Delete -ErrorAction SilentlyContinue
|
|
>> "%BS%" echo Write-Host " [Option 20] Package enforcement: ON"
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo Set-RuleOption -FilePath $xmlPath -Option 20
|
|
>> "%BS%" echo Write-Host " [Option 20] Package enforcement: OFF"
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo Set-RuleOption -FilePath $xmlPath -Option 3
|
|
>> "%BS%" echo Write-Host " [Option 3] Audit Mode: ON"
|
|
>> "%BS%" echo $rules = @()
|
|
>> "%BS%" echo $ruleErrors = [System.Collections.Generic.List[string]]::new()
|
|
>> "%BS%" echo # AV/EDR rules - publisher first, path fallback (AV/EDR must never be blocked)
|
|
>> "%BS%" echo if (Test-Path "C:\WDAC\detected_av_paths.txt") {
|
|
>> "%BS%" echo Get-Content "C:\WDAC\detected_av_paths.txt" ^| ForEach-Object {
|
|
>> "%BS%" echo $p = $_.Trim()
|
|
>> "%BS%" echo if ($p -eq "") { return }
|
|
>> "%BS%" echo $dir = $p -replace "\\\*$", ""
|
|
>> "%BS%" echo # Try publisher rule - find a signed exe in the AV/EDR folder
|
|
>> "%BS%" echo $signedExe = $null
|
|
>> "%BS%" echo $candidates = @(Get-ChildItem $dir -Filter "*.exe" -Recurse -Depth 2 -ErrorAction SilentlyContinue)
|
|
>> "%BS%" echo foreach ($candidate in $candidates) {
|
|
>> "%BS%" echo $sig = Get-AuthenticodeSignature $candidate.FullName -ErrorAction SilentlyContinue
|
|
>> "%BS%" echo if ($sig -and $sig.Status -eq "Valid" -and $sig.SignerCertificate) {
|
|
>> "%BS%" echo $signedExe = $candidate.FullName
|
|
>> "%BS%" echo break
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($signedExe) {
|
|
>> "%BS%" echo $exeDir = Split-Path $signedExe -Parent
|
|
>> "%BS%" echo $driverFiles = Get-SystemDriver -ScanPath $exeDir -UserPEs -ErrorAction Stop -WarningAction SilentlyContinue 2^>$null ^| Where-Object { $_ -isnot [string] }
|
|
>> "%BS%" echo if ($driverFiles) {
|
|
>> "%BS%" echo try {
|
|
>> "%BS%" echo $r = New-CIPolicyRule -DriverFiles $driverFiles -Level Publisher -ErrorAction Stop
|
|
>> "%BS%" echo if ($r -and $r.Count -gt 0) {
|
|
>> "%BS%" echo $pub = (Get-AuthenticodeSignature $signedExe -EA SilentlyContinue).SignerCertificate.Subject
|
|
>> "%BS%" echo Write-Host " [Publisher] AV/EDR: $dir - $pub"
|
|
>> "%BS%" echo foreach ($rl in $r) { $rules += $rl }
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo Write-Host " [Path] AV/EDR (fallback - no publisher rules): $p"
|
|
>> "%BS%" echo $rules += (New-CIPolicyRule -FilePathRule $p)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo } catch {
|
|
>> "%BS%" echo Write-Host " [Path] AV/EDR (fallback - publisher error): $p"
|
|
>> "%BS%" echo $rules += (New-CIPolicyRule -FilePathRule $p)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo Write-Host " [Path] AV/EDR (fallback - no signed files): $p"
|
|
>> "%BS%" echo $rules += (New-CIPolicyRule -FilePathRule $p)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo Write-Host " [Path] AV/EDR (fallback - no signed exe found): $p"
|
|
>> "%BS%" echo $rules += (New-CIPolicyRule -FilePathRule $p)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo # VMware Tools path rules
|
|
>> "%BS%" echo if ($copyPaste -eq 1) {
|
|
>> "%BS%" echo @("C:\Program Files\VMware\*", "C:\Program Files\Common Files\VMware\*") ^| ForEach-Object {
|
|
>> "%BS%" echo $chk = $_ -replace "\\\*", ""
|
|
>> "%BS%" echo if (Test-Path $chk) {
|
|
>> "%BS%" echo Write-Host " [Path] VMware Tools: $_"
|
|
>> "%BS%" echo $rules += (New-CIPolicyRule -FilePathRule $_)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo # Installed apps - publisher rules via Get-SystemDriver
|
|
>> "%BS%" echo # -ErrorAction Stop is required - SilentlyContinue causes empty results
|
|
>> "%BS%" echo if (Test-Path "C:\WDAC\detected_apps.json") {
|
|
>> "%BS%" echo $apps = Get-Content "C:\WDAC\detected_apps.json" ^| ConvertFrom-Json
|
|
>> "%BS%" echo foreach ($app in $apps) {
|
|
>> "%BS%" echo if ($exNums -contains $app.Index) {
|
|
>> "%BS%" echo Write-Host " [SKIP] Excluded: $($app.Name)"
|
|
>> "%BS%" echo continue
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($app.Signed) {
|
|
>> "%BS%" echo try {
|
|
>> "%BS%" echo $scanDir = Split-Path $app.MainExe -Parent
|
|
>> "%BS%" echo $driverFiles = Get-SystemDriver -ScanPath $scanDir -UserPEs -ErrorAction Stop -WarningAction SilentlyContinue 2^>$null ^| Where-Object { $_ -isnot [string] }
|
|
>> "%BS%" echo if ($driverFiles) {
|
|
>> "%BS%" echo $r = New-CIPolicyRule -DriverFiles $driverFiles -Level Publisher -ErrorAction Stop
|
|
>> "%BS%" echo Write-Host " [Publisher] $($app.Name) - $($app.Publisher)"
|
|
>> "%BS%" echo foreach ($rl in $r) { $rules += $rl }
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo throw "No driver files returned"
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo } catch {
|
|
>> "%BS%" echo Write-Host " [Skip] $($app.Name) - no publisher rule available"
|
|
>> "%BS%" echo $ruleErrors.Add("$($app.Name)")
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo Write-Host " [Skip] $($app.Name) - unsigned, not whitelisted"
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($rules.Count -gt 0) {
|
|
>> "%BS%" echo Write-Host ""
|
|
>> "%BS%" echo Write-Host " Merging $($rules.Count) rules into policy..."
|
|
>> "%BS%" echo Merge-CIPolicy -PolicyPaths $xmlPath -Rules $rules -OutputFilePath $xmlPath ^| Out-Null
|
|
>> "%BS%" echo Write-Host " [+] Rules merged."
|
|
>> "%BS%" echo } else {
|
|
>> "%BS%" echo Write-Host " No additional rules to add."
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo # LOLBAS deny rules
|
|
>> "%BS%" echo $lolbasFile = "C:\WDAC\lolbas_deny.txt"
|
|
>> "%BS%" echo if (Test-Path $lolbasFile) {
|
|
>> "%BS%" echo $lolbasRaw = (Get-Content $lolbasFile -Raw -ErrorAction SilentlyContinue) -join ""
|
|
>> "%BS%" echo $lolbasNums = $lolbasRaw -split ',' ^| ForEach-Object { $_.Trim() } ^| Where-Object { [int32]::TryParse($_, [ref]$null) } ^| ForEach-Object { [int]$_ }
|
|
>> "%BS%" echo $denyRules = @()
|
|
>> "%BS%" echo if ($lolbasNums -contains 1) {
|
|
>> "%BS%" echo Write-Host " [DENY] msbuild.exe"
|
|
>> "%BS%" echo @("C:\Windows\Microsoft.NET\Framework*\MSBuild.exe","C:\Windows\Microsoft.NET\Framework64*\MSBuild.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 2) {
|
|
>> "%BS%" echo Write-Host " [DENY] regsvr32.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\regsvr32.exe","C:\Windows\SysWOW64\regsvr32.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 3) {
|
|
>> "%BS%" echo Write-Host " [DENY] rundll32.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\rundll32.exe","C:\Windows\SysWOW64\rundll32.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 4) {
|
|
>> "%BS%" echo Write-Host " [DENY] certutil.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\certutil.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 5) {
|
|
>> "%BS%" echo Write-Host " [DENY] installutil.exe"
|
|
>> "%BS%" echo @("C:\Windows\Microsoft.NET\Framework*\InstallUtil.exe","C:\Windows\Microsoft.NET\Framework64*\InstallUtil.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 6) {
|
|
>> "%BS%" echo Write-Host " [DENY] regasm.exe"
|
|
>> "%BS%" echo @("C:\Windows\Microsoft.NET\Framework*\RegAsm.exe","C:\Windows\Microsoft.NET\Framework64*\RegAsm.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 7) {
|
|
>> "%BS%" echo Write-Host " [DENY] regsvcs.exe"
|
|
>> "%BS%" echo @("C:\Windows\Microsoft.NET\Framework*\RegSvcs.exe","C:\Windows\Microsoft.NET\Framework64*\RegSvcs.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 8) {
|
|
>> "%BS%" echo Write-Host " [DENY] cmstp.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\cmstp.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 9) {
|
|
>> "%BS%" echo Write-Host " [DENY] odbcconf.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\odbcconf.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 10) {
|
|
>> "%BS%" echo Write-Host " [DENY] cscript.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\cscript.exe","C:\Windows\SysWOW64\cscript.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 11) {
|
|
>> "%BS%" echo Write-Host " [DENY] wscript.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\wscript.exe","C:\Windows\SysWOW64\wscript.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 12) {
|
|
>> "%BS%" echo Write-Host " [DENY] mshta.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\mshta.exe","C:\Windows\SysWOW64\mshta.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 13) {
|
|
>> "%BS%" echo Write-Host " [DENY] powershell.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe","C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 14) {
|
|
>> "%BS%" echo Write-Host " [DENY] pwsh.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Program Files\PowerShell\*\pwsh.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 15) {
|
|
>> "%BS%" echo Write-Host " [DENY] presentationhost.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\presentationhost.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 16) {
|
|
>> "%BS%" echo Write-Host " [DENY] ieexec.exe"
|
|
>> "%BS%" echo @("C:\Windows\Microsoft.NET\Framework*\ieexec.exe","C:\Windows\Microsoft.NET\Framework64*\ieexec.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 17) {
|
|
>> "%BS%" echo Write-Host " [DENY] microsoft.workflow.compiler.exe"
|
|
>> "%BS%" echo @("C:\Windows\Microsoft.NET\Framework*\microsoft.workflow.compiler.exe","C:\Windows\Microsoft.NET\Framework64*\microsoft.workflow.compiler.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 18) {
|
|
>> "%BS%" echo Write-Host " [DENY] desktopimgdownldr.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\desktopimgdownldr.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 19) {
|
|
>> "%BS%" echo Write-Host " [DENY] syncappvpublishingserver.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\syncappvpublishingserver.exe","C:\Windows\SysWOW64\syncappvpublishingserver.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 20) {
|
|
>> "%BS%" echo Write-Host " [DENY] bash.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\bash.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 21) {
|
|
>> "%BS%" echo Write-Host " [DENY] wsl.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\wsl.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 22) {
|
|
>> "%BS%" echo Write-Host " [DENY] ftp.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\ftp.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 23) {
|
|
>> "%BS%" echo Write-Host " [DENY] bitsadmin.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\bitsadmin.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 24) {
|
|
>> "%BS%" echo Write-Host " [DENY] forfiles.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\forfiles.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 25) {
|
|
>> "%BS%" echo Write-Host " [DENY] pcalua.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\pcalua.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 26) {
|
|
>> "%BS%" echo Write-Host " [DENY] verclsid.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\verclsid.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 27) {
|
|
>> "%BS%" echo Write-Host " [DENY] mofcomp.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\wbem\mofcomp.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 28) {
|
|
>> "%BS%" echo Write-Host " [DENY] msiexec.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\msiexec.exe","C:\Windows\SysWOW64\msiexec.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 29) {
|
|
>> "%BS%" echo Write-Host " [DENY] dxcap.exe"
|
|
>> "%BS%" echo $denyRules += (New-CIPolicyRule -FilePathRule "C:\Windows\System32\dxcap.exe" -Deny)
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 30) {
|
|
>> "%BS%" echo Write-Host " [DENY] cmd.exe"
|
|
>> "%BS%" echo @("C:\Windows\System32\cmd.exe","C:\Windows\SysWOW64\cmd.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($lolbasNums -contains 31) {
|
|
>> "%BS%" echo Write-Host " [DENY] wt.exe"
|
|
>> "%BS%" echo @("C:\Program Files\WindowsApps\Microsoft.WindowsTerminal*\wt.exe","C:\Program Files\WindowsApps\Microsoft.WindowsTerminalPreview*\wt.exe") ^| ForEach-Object { $denyRules += (New-CIPolicyRule -FilePathRule $_ -Deny) }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($denyRules.Count -gt 0) {
|
|
>> "%BS%" echo Write-Host ""
|
|
>> "%BS%" echo Write-Host " Merging $($denyRules.Count) LOLBAS deny rules into policy..."
|
|
>> "%BS%" echo Merge-CIPolicy -PolicyPaths $xmlPath -Rules $denyRules -OutputFilePath $xmlPath ^| Out-Null
|
|
>> "%BS%" echo Write-Host " [+] LOLBAS deny rules merged."
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo if ($ruleErrors.Count -gt 0) {
|
|
>> "%BS%" echo Write-Host ""
|
|
>> "%BS%" echo Write-Host " Note: these apps had no extractable publisher rule and were skipped:"
|
|
>> "%BS%" echo $ruleErrors ^| ForEach-Object { Write-Host " - $_" }
|
|
>> "%BS%" echo }
|
|
>> "%BS%" echo Write-Host ""
|
|
>> "%BS%" echo Write-Host "[+] Policy build complete."
|
|
powershell -ExecutionPolicy Bypass -File "%BS%"
|
|
echo.
|
|
|
|
:: ============================================================
|
|
:: STEP 8 - GENERATE ROLLBACK SCRIPT
|
|
:: ============================================================
|
|
echo [STEP 8] Generating rollback script...
|
|
|
|
set "RB=%WDAC_FOLDER%\Remove-WDAC.ps1"
|
|
if exist "%RB%" del "%RB%"
|
|
|
|
>> "%RB%" echo # Remove-WDAC.ps1
|
|
>> "%RB%" echo # Removes the WindowsSentinel WDAC policy from this machine.
|
|
>> "%RB%" echo # Run as Administrator, then reboot to complete removal.
|
|
>> "%RB%" echo $guidFile = "C:\WDAC\policy_guid.txt"
|
|
>> "%RB%" echo $activeDir = "$env:SystemRoot\System32\CodeIntegrity\CIPolicies\Active"
|
|
>> "%RB%" echo if (-not (Test-Path $guidFile)) {
|
|
>> "%RB%" echo Write-Host "ERROR: policy_guid.txt not found. Cannot determine which policy to remove."
|
|
>> "%RB%" echo Write-Host "Manually delete .cip files from: $activeDir"
|
|
>> "%RB%" echo exit 1
|
|
>> "%RB%" echo }
|
|
>> "%RB%" echo $guid = (Get-Content $guidFile -Raw).Trim()
|
|
>> "%RB%" echo $cipPath = "$activeDir\$guid.cip"
|
|
>> "%RB%" echo Write-Host "Removing policy: $guid"
|
|
>> "%RB%" echo if (Test-Path $cipPath) {
|
|
>> "%RB%" echo Remove-Item $cipPath -Force
|
|
>> "%RB%" echo Write-Host "[+] Removed: $cipPath"
|
|
>> "%RB%" echo } else {
|
|
>> "%RB%" echo Write-Host "WARNING: .cip file not found at expected location: $cipPath"
|
|
>> "%RB%" echo Write-Host "Files currently in Active directory:"
|
|
>> "%RB%" echo Get-ChildItem $activeDir -Filter "*.cip" -ErrorAction SilentlyContinue ^| ForEach-Object {
|
|
>> "%RB%" echo Write-Host " $($_.FullName)"
|
|
>> "%RB%" echo }
|
|
>> "%RB%" echo }
|
|
>> "%RB%" echo try {
|
|
>> "%RB%" echo Invoke-CimMethod -Namespace "root\Microsoft\Windows\CI" -ClassName "PS_UpdateAndCompareCIPolicy" -MethodName "Update" -Arguments @{FilePath=$cipPath} ^| Out-Null
|
|
>> "%RB%" echo Write-Host "[+] Policy refresh triggered."
|
|
>> "%RB%" echo } catch {
|
|
>> "%RB%" echo Write-Host "Note: CIM refresh skipped - a reboot is required to fully remove the policy."
|
|
>> "%RB%" echo }
|
|
>> "%RB%" echo Write-Host ""
|
|
>> "%RB%" echo Write-Host "Reboot the machine to complete policy removal."
|
|
|
|
echo [+] Rollback script created: %WDAC_FOLDER%\Remove-WDAC.ps1
|
|
echo Keep this file safe. Run it as Administrator then reboot to remove the policy.
|
|
echo.
|
|
|
|
:: ============================================================
|
|
:: STEP 9 - DEPLOY IN AUDIT MODE
|
|
:: ============================================================
|
|
echo [STEP 9] Deploying policy in Audit Mode...
|
|
echo.
|
|
|
|
set "DP=%WDAC_FOLDER%\deploy_policy.ps1"
|
|
if exist "%DP%" del "%DP%"
|
|
|
|
>> "%DP%" echo $xmlPath = "C:\WDAC\WSSentinel.xml"
|
|
>> "%DP%" echo $activeDir = "$env:SystemRoot\System32\CodeIntegrity\CIPolicies\Active"
|
|
>> "%DP%" echo New-Item -ItemType Directory -Force -Path $activeDir ^| Out-Null
|
|
>> "%DP%" echo $guid = (Get-Content "C:\WDAC\policy_guid.txt" -Raw).Trim()
|
|
>> "%DP%" echo $cip = "C:\WDAC\$guid.cip"
|
|
>> "%DP%" echo $dest = "$activeDir\$guid.cip"
|
|
>> "%DP%" echo ConvertFrom-CIPolicy -XmlFilePath $xmlPath -BinaryFilePath $cip ^| Out-Null
|
|
>> "%DP%" echo Write-Host " Compiled: $cip"
|
|
>> "%DP%" echo Copy-Item $cip $dest -Force
|
|
>> "%DP%" echo Write-Host " Copied to Active: $dest"
|
|
>> "%DP%" echo $r = Invoke-CimMethod -Namespace "root\Microsoft\Windows\CI" -ClassName "PS_UpdateAndCompareCIPolicy" -MethodName "Update" -Arguments @{FilePath=$dest}
|
|
>> "%DP%" echo if ($r.ReturnValue -eq 0) { Write-Host "[+] Policy loaded successfully (Audit Mode)." }
|
|
>> "%DP%" echo else { Write-Host "Warning: CIM ReturnValue = $($r.ReturnValue)" }
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%DP%"
|
|
echo.
|
|
|
|
if "!ENFORCE_MODE!"=="1" goto DO_ENFORCE_ENTRY
|
|
|
|
:: ============================================================
|
|
:: FAST DEPLOY PROMPT - shown after /setup step 9
|
|
:: ============================================================
|
|
echo.
|
|
echo ============================================================
|
|
echo OPTIONAL: ENFORCE + HARDEN NOW IN ONE GO
|
|
echo ============================================================
|
|
echo.
|
|
echo Your policy is deployed in Audit Mode. Nothing is blocked yet.
|
|
echo.
|
|
echo If your LOLBAS selection includes cmd.exe, PowerShell, or
|
|
echo script enforcement is ON, you will NOT be able to run this
|
|
echo script again once Enforce Mode activates. Choosing YES here
|
|
echo does Enforce + Harden in one shot before the reboot.
|
|
echo.
|
|
echo YES = Remove Audit Mode, enforce policy, apply NTFS ACLs,
|
|
echo GPO settings and WDAC path deny rules, then reboot.
|
|
echo.
|
|
echo NO = Reboot into Audit Mode. Review /report first, then
|
|
echo run /enforce and /harden separately while you still can.
|
|
echo.
|
|
set "FAST_CONF="
|
|
set /p FAST_CONF=" Enforce + Harden now? [YES/NO]: "
|
|
if /i "!FAST_CONF!"=="YES" (
|
|
set FAST_DEPLOY=1
|
|
goto DO_ENFORCE
|
|
)
|
|
goto SHOW_AUDIT_SUMMARY
|
|
|
|
:: ============================================================
|
|
:: ENFORCE MODE
|
|
:: Entry point when called directly with /enforce flag
|
|
:: ============================================================
|
|
:DO_ENFORCE_ENTRY
|
|
echo ============================================================
|
|
echo SWITCHING TO ENFORCE MODE
|
|
echo ============================================================
|
|
echo.
|
|
echo WARNING: After reboot ONLY whitelisted apps will run.
|
|
echo Everything else will be BLOCKED.
|
|
echo.
|
|
echo Extensions : !EXT_LIST!
|
|
echo.
|
|
if "!ENFORCE_SCRIPTS!"=="1" (
|
|
echo CRITICAL: Script enforcement is ON.
|
|
echo This .bat file will be BLOCKED after the reboot.
|
|
echo Use %WDAC_FOLDER%\Remove-WDAC.ps1 to recover if needed.
|
|
echo.
|
|
)
|
|
|
|
:ASK_ENFORCE
|
|
set "CONFIRM="
|
|
set /p CONFIRM=" Type YES to enforce or NO to stay in Audit Mode: "
|
|
if /i "!CONFIRM!"=="NO" goto CANCEL_ENFORCE
|
|
if /i "!CONFIRM!"=="YES" goto DO_ENFORCE
|
|
echo Please type YES or NO.
|
|
goto ASK_ENFORCE
|
|
|
|
:CANCEL_ENFORCE
|
|
echo Cancelled. Staying in Audit Mode.
|
|
goto SHOW_AUDIT_SUMMARY
|
|
|
|
:DO_ENFORCE
|
|
set "ES=%WDAC_FOLDER%\enforce_policy.ps1"
|
|
if exist "%ES%" del "%ES%"
|
|
|
|
>> "%ES%" echo $xmlPath = "C:\WDAC\WSSentinel.xml"
|
|
>> "%ES%" echo $activeDir = "$env:SystemRoot\System32\CodeIntegrity\CIPolicies\Active"
|
|
>> "%ES%" echo $guid = (Get-Content "C:\WDAC\policy_guid.txt" -Raw).Trim()
|
|
>> "%ES%" echo $cip = "C:\WDAC\$guid.cip"
|
|
>> "%ES%" echo $dest = "$activeDir\$guid.cip"
|
|
>> "%ES%" echo # Remove Audit Mode option from XML
|
|
>> "%ES%" echo Set-RuleOption -FilePath $xmlPath -Option 3 -Delete
|
|
>> "%ES%" echo $stillAudit = Select-String -Path $xmlPath -Pattern "Audit" -Quiet
|
|
>> "%ES%" echo if ($stillAudit) {
|
|
>> "%ES%" echo Write-Host "ERROR: Audit Mode option still present in XML. Aborting to prevent policy corruption."
|
|
>> "%ES%" echo exit 1
|
|
>> "%ES%" echo }
|
|
>> "%ES%" echo Write-Host "[+] Audit Mode removed from policy."
|
|
>> "%ES%" echo ConvertFrom-CIPolicy -XmlFilePath $xmlPath -BinaryFilePath $cip ^| Out-Null
|
|
>> "%ES%" echo Write-Host "[+] Recompiled in Enforce Mode."
|
|
>> "%ES%" echo Copy-Item $cip $dest -Force
|
|
>> "%ES%" echo $r = Invoke-CimMethod -Namespace "root\Microsoft\Windows\CI" -ClassName "PS_UpdateAndCompareCIPolicy" -MethodName "Update" -Arguments @{FilePath=$dest}
|
|
>> "%ES%" echo if ($r.ReturnValue -eq 0) { Write-Host "[+] Enforce Mode deployed." }
|
|
>> "%ES%" echo else { Write-Host "Warning: CIM ReturnValue = $($r.ReturnValue)" }
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%ES%"
|
|
echo.
|
|
|
|
if "!FAST_DEPLOY!"=="1" goto RUN_FAST_HARDEN
|
|
goto GENERATE_REPORT_THEN_REBOOT
|
|
|
|
:: ============================================================
|
|
:: RUN_FAST_HARDEN - called from fast deploy path after enforce
|
|
:: Generates and runs harden.ps1 inline then reboots via report
|
|
:: ============================================================
|
|
:RUN_FAST_HARDEN
|
|
echo.
|
|
echo ============================================================
|
|
echo APPLYING INSIDER THREAT HARDENING
|
|
echo ============================================================
|
|
echo.
|
|
echo [*] Step 0 - Switching to Enforce Mode...
|
|
echo.
|
|
|
|
set "ES=%WDAC_FOLDER%\enforce_policy.ps1"
|
|
if exist "%ES%" del "%ES%"
|
|
|
|
>> "%ES%" echo $xmlPath = "C:\WDAC\WSSentinel.xml"
|
|
>> "%ES%" echo $activeDir = "$env:SystemRoot\System32\CodeIntegrity\CIPolicies\Active"
|
|
>> "%ES%" echo $guid = (Get-Content "C:\WDAC\policy_guid.txt" -Raw).Trim()
|
|
>> "%ES%" echo $cip = "C:\WDAC\$guid.cip"
|
|
>> "%ES%" echo $dest = "$activeDir\$guid.cip"
|
|
>> "%ES%" echo Set-RuleOption -FilePath $xmlPath -Option 3 -Delete
|
|
>> "%ES%" echo $stillAudit = Select-String -Path $xmlPath -Pattern "Audit" -Quiet
|
|
>> "%ES%" echo if ($stillAudit) {
|
|
>> "%ES%" echo Write-Host "ERROR: Audit Mode still present. Aborting."
|
|
>> "%ES%" echo exit 1
|
|
>> "%ES%" echo }
|
|
>> "%ES%" echo Write-Host "[+] Audit Mode removed from policy."
|
|
>> "%ES%" echo ConvertFrom-CIPolicy -XmlFilePath $xmlPath -BinaryFilePath $cip ^| Out-Null
|
|
>> "%ES%" echo Write-Host "[+] Recompiled in Enforce Mode."
|
|
>> "%ES%" echo Copy-Item $cip $dest -Force
|
|
>> "%ES%" echo $r = Invoke-CimMethod -Namespace "root\Microsoft\Windows\CI" -ClassName "PS_UpdateAndCompareCIPolicy" -MethodName "Update" -Arguments @{FilePath=$dest}
|
|
>> "%ES%" echo if ($r.ReturnValue -eq 0) { Write-Host "[+] Enforce Mode deployed." }
|
|
>> "%ES%" echo else { Write-Host "Warning: CIM ReturnValue = $($r.ReturnValue)" }
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%ES%"
|
|
echo.
|
|
|
|
echo [*] Step 1-3 - Applying insider threat hardening...
|
|
echo.
|
|
|
|
set "HS=%WDAC_FOLDER%\harden.ps1"
|
|
if exist "%HS%" del "%HS%"
|
|
|
|
>> "%HS%" echo $xmlPath = "C:\WDAC\WSSentinel.xml"
|
|
>> "%HS%" echo $lolbasFile = "C:\WDAC\lolbas_deny.txt"
|
|
>> "%HS%" echo $lolbasRaw = (Get-Content $lolbasFile -Raw -ErrorAction SilentlyContinue) -join ""
|
|
>> "%HS%" echo $lolbasNums = $lolbasRaw -split ',' ^| ForEach-Object { $_.Trim() } ^| Where-Object { [int32]::TryParse($_, [ref]$null) } ^| ForEach-Object { [int]$_ }
|
|
>> "%HS%" echo $pathMap = @{}
|
|
>> "%HS%" echo $pathMap[1] = @("C:\Windows\Microsoft.NET\Framework*\MSBuild.exe","C:\Windows\Microsoft.NET\Framework64*\MSBuild.exe")
|
|
>> "%HS%" echo $pathMap[2] = @("C:\Windows\System32\regsvr32.exe","C:\Windows\SysWOW64\regsvr32.exe")
|
|
>> "%HS%" echo $pathMap[3] = @("C:\Windows\System32\rundll32.exe","C:\Windows\SysWOW64\rundll32.exe")
|
|
>> "%HS%" echo $pathMap[4] = @("C:\Windows\System32\certutil.exe")
|
|
>> "%HS%" echo $pathMap[5] = @("C:\Windows\Microsoft.NET\Framework*\InstallUtil.exe","C:\Windows\Microsoft.NET\Framework64*\InstallUtil.exe")
|
|
>> "%HS%" echo $pathMap[6] = @("C:\Windows\Microsoft.NET\Framework*\RegAsm.exe","C:\Windows\Microsoft.NET\Framework64*\RegAsm.exe")
|
|
>> "%HS%" echo $pathMap[7] = @("C:\Windows\Microsoft.NET\Framework*\RegSvcs.exe","C:\Windows\Microsoft.NET\Framework64*\RegSvcs.exe")
|
|
>> "%HS%" echo $pathMap[8] = @("C:\Windows\System32\cmstp.exe")
|
|
>> "%HS%" echo $pathMap[9] = @("C:\Windows\System32\odbcconf.exe")
|
|
>> "%HS%" echo $pathMap[10] = @("C:\Windows\System32\cscript.exe","C:\Windows\SysWOW64\cscript.exe")
|
|
>> "%HS%" echo $pathMap[11] = @("C:\Windows\System32\wscript.exe","C:\Windows\SysWOW64\wscript.exe")
|
|
>> "%HS%" echo $pathMap[12] = @("C:\Windows\System32\mshta.exe","C:\Windows\SysWOW64\mshta.exe")
|
|
>> "%HS%" echo $pathMap[13] = @("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe","C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe")
|
|
>> "%HS%" echo $pathMap[14] = @("C:\Program Files\PowerShell\*\pwsh.exe")
|
|
>> "%HS%" echo $pathMap[15] = @("C:\Windows\System32\presentationhost.exe")
|
|
>> "%HS%" echo $pathMap[16] = @("C:\Windows\Microsoft.NET\Framework*\ieexec.exe","C:\Windows\Microsoft.NET\Framework64*\ieexec.exe")
|
|
>> "%HS%" echo $pathMap[17] = @("C:\Windows\Microsoft.NET\Framework*\microsoft.workflow.compiler.exe","C:\Windows\Microsoft.NET\Framework64*\microsoft.workflow.compiler.exe")
|
|
>> "%HS%" echo $pathMap[18] = @("C:\Windows\System32\desktopimgdownldr.exe")
|
|
>> "%HS%" echo $pathMap[19] = @("C:\Windows\System32\syncappvpublishingserver.exe","C:\Windows\SysWOW64\syncappvpublishingserver.exe")
|
|
>> "%HS%" echo $pathMap[20] = @("C:\Windows\System32\bash.exe")
|
|
>> "%HS%" echo $pathMap[21] = @("C:\Windows\System32\wsl.exe")
|
|
>> "%HS%" echo $pathMap[22] = @("C:\Windows\System32\ftp.exe")
|
|
>> "%HS%" echo $pathMap[23] = @("C:\Windows\System32\bitsadmin.exe")
|
|
>> "%HS%" echo $pathMap[24] = @("C:\Windows\System32\forfiles.exe")
|
|
>> "%HS%" echo $pathMap[25] = @("C:\Windows\System32\pcalua.exe")
|
|
>> "%HS%" echo $pathMap[26] = @("C:\Windows\System32\verclsid.exe")
|
|
>> "%HS%" echo $pathMap[27] = @("C:\Windows\System32\wbem\mofcomp.exe")
|
|
>> "%HS%" echo $pathMap[28] = @("C:\Windows\System32\msiexec.exe","C:\Windows\SysWOW64\msiexec.exe")
|
|
>> "%HS%" echo $pathMap[29] = @("C:\Windows\System32\dxcap.exe")
|
|
>> "%HS%" echo $pathMap[30] = @("C:\Windows\System32\cmd.exe","C:\Windows\SysWOW64\cmd.exe")
|
|
>> "%HS%" echo $pathMap[31] = @("C:\Program Files\WindowsApps\Microsoft.WindowsTerminal*\wt.exe","C:\Program Files\WindowsApps\Microsoft.WindowsTerminalPreview*\wt.exe")
|
|
>> "%HS%" echo Write-Host "[Section 1] Applying NTFS ACLs to denied LOLBAS binaries..."
|
|
>> "%HS%" echo $usersSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-545")
|
|
>> "%HS%" echo $aclCount = 0
|
|
>> "%HS%" echo foreach ($num in $lolbasNums) {
|
|
>> "%HS%" echo if (-not $pathMap.ContainsKey($num)) { continue }
|
|
>> "%HS%" echo foreach ($pattern in $pathMap[$num]) {
|
|
>> "%HS%" echo $resolved = @(Get-Item -Path $pattern -ErrorAction SilentlyContinue)
|
|
>> "%HS%" echo foreach ($file in $resolved) {
|
|
>> "%HS%" echo try {
|
|
>> "%HS%" echo $acl = Get-Acl $file.FullName -ErrorAction Stop
|
|
>> "%HS%" echo $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($usersSid,"ReadAndExecute","Deny")
|
|
>> "%HS%" echo $acl.AddAccessRule($rule)
|
|
>> "%HS%" echo Set-Acl $file.FullName $acl -ErrorAction Stop
|
|
>> "%HS%" echo Write-Host " [ACL] $($file.FullName)"
|
|
>> "%HS%" echo $aclCount++
|
|
>> "%HS%" echo } catch { Write-Host " [SKIP] $($file.FullName) - $($_.Exception.Message)" }
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo Write-Host " [+] ACLs applied to $aclCount binaries."
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host "[Section 2] Applying GPO registry settings..."
|
|
>> "%HS%" echo $sysPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System"
|
|
>> "%HS%" echo if (-not (Test-Path $sysPath)) { New-Item -Path $sysPath -Force ^| Out-Null }
|
|
>> "%HS%" echo Set-ItemProperty $sysPath "DisableCMD" 1
|
|
>> "%HS%" echo Write-Host " [GPO] cmd.exe disabled for standard users"
|
|
>> "%HS%" echo $expPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer"
|
|
>> "%HS%" echo if (-not (Test-Path $expPath)) { New-Item -Path $expPath -Force ^| Out-Null }
|
|
>> "%HS%" echo Set-ItemProperty $expPath "NoDrives" 4
|
|
>> "%HS%" echo Write-Host " [GPO] C:\ hidden in Explorer"
|
|
>> "%HS%" echo Set-ItemProperty $expPath "NoViewOnDrive" 4
|
|
>> "%HS%" echo Write-Host " [GPO] C:\ access blocked in Explorer"
|
|
>> "%HS%" echo $polPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
|
|
>> "%HS%" echo if (-not (Test-Path $polPath)) { New-Item -Path $polPath -Force ^| Out-Null }
|
|
>> "%HS%" echo Set-ItemProperty $polPath "DisableRegistryTools" 1
|
|
>> "%HS%" echo Write-Host " [GPO] Registry Editor disabled for standard users"
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host "[Section 3] Adding WDAC deny rules for user-writable paths..."
|
|
>> "%HS%" echo $denyPaths = @("C:\Users\*\Desktop\*","C:\Users\*\Downloads\*","C:\Users\*\AppData\Local\Temp\*","C:\Windows\Temp\*","C:\Temp\*")
|
|
>> "%HS%" echo $pathDenyRules = @()
|
|
>> "%HS%" echo foreach ($dp in $denyPaths) {
|
|
>> "%HS%" echo $pathDenyRules += (New-CIPolicyRule -FilePathRule $dp -Deny)
|
|
>> "%HS%" echo Write-Host " [DENY PATH] $dp"
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo if ($pathDenyRules.Count -gt 0) {
|
|
>> "%HS%" echo Merge-CIPolicy -PolicyPaths $xmlPath -Rules $pathDenyRules -OutputFilePath $xmlPath ^| Out-Null
|
|
>> "%HS%" echo $guid = (Get-Content "C:\WDAC\policy_guid.txt" -Raw).Trim()
|
|
>> "%HS%" echo $cip = "C:\WDAC\$guid.cip"
|
|
>> "%HS%" echo $dest = "$env:SystemRoot\System32\CodeIntegrity\CIPolicies\Active\$guid.cip"
|
|
>> "%HS%" echo ConvertFrom-CIPolicy -XmlFilePath $xmlPath -BinaryFilePath $cip ^| Out-Null
|
|
>> "%HS%" echo Copy-Item $cip $dest -Force
|
|
>> "%HS%" echo Invoke-CimMethod -Namespace "root\Microsoft\Windows\CI" -ClassName "PS_UpdateAndCompareCIPolicy" -MethodName "Update" -Arguments @{FilePath=$dest} ^| Out-Null
|
|
>> "%HS%" echo Write-Host " [+] WDAC path deny rules applied."
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host "[+] Hardening complete."
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%HS%"
|
|
echo.
|
|
goto GENERATE_REPORT_THEN_REBOOT
|
|
|
|
:: ============================================================
|
|
:: AUDIT MODE SUMMARY
|
|
:: ============================================================
|
|
:SHOW_AUDIT_SUMMARY
|
|
echo ============================================================
|
|
echo AUDIT MODE ACTIVE - Nothing is blocked yet
|
|
echo ============================================================
|
|
echo.
|
|
echo Mode : AUDIT (monitor only)
|
|
echo Extensions : !EXT_LIST!
|
|
if "!ALLOW_COPYPASTE!"=="1" echo Copy/Paste : VMware Tools whitelisted
|
|
if "!ALLOW_COPYPASTE!"=="0" echo Copy/Paste : VMware Tools blocked
|
|
echo.
|
|
echo Next steps:
|
|
echo 1. Reboot to activate Audit Mode
|
|
echo 2. Use the machine normally for 1-7 days
|
|
echo 3. Generate a report to see what WOULD be blocked:
|
|
echo Deploy-WDAC.bat /report
|
|
echo Or check Event Viewer:
|
|
echo Apps and Services / Microsoft / Windows / CodeIntegrity / Operational
|
|
echo Look for Event ID 3076
|
|
echo 4. When satisfied with the whitelist: Deploy-WDAC.bat /enforce
|
|
echo.
|
|
echo To remove the policy at any time:
|
|
echo powershell -ExecutionPolicy Bypass -File %WDAC_FOLDER%\Remove-WDAC.ps1
|
|
echo Then reboot.
|
|
echo.
|
|
echo Rebooting in 10 seconds to activate Audit Mode...
|
|
echo Press CTRL+C to cancel.
|
|
echo.
|
|
timeout /t 10
|
|
shutdown /r /t 0
|
|
goto END
|
|
|
|
:: ============================================================
|
|
:: GENERATE REPORT
|
|
:: ============================================================
|
|
:GENERATE_REPORT_THEN_REBOOT
|
|
:GENERATE_REPORT
|
|
echo [*] Generating WDAC report...
|
|
echo.
|
|
|
|
set "RS=%WDAC_FOLDER%\generate_report.ps1"
|
|
if exist "%RS%" del "%RS%"
|
|
|
|
>> "%RS%" echo $reportPath = "C:\WDAC\WDAC_Report.txt"
|
|
>> "%RS%" echo $sep = "=" * 70
|
|
>> "%RS%" echo $now = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
>> "%RS%" echo $out = [System.Collections.Generic.List[string]]::new()
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add(" WDAC POLICY REPORT")
|
|
>> "%RS%" echo $out.Add(" Generated : $now")
|
|
>> "%RS%" echo $out.Add(" Machine : $env:COMPUTERNAME")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $xmlBase = "C:\WDAC\WSSentinel.xml"
|
|
>> "%RS%" echo if (Test-Path $xmlBase) {
|
|
>> "%RS%" echo $isAudit = [bool](Select-String -Path $xmlBase -Pattern "Audit" -Quiet)
|
|
>> "%RS%" echo $mode = if ($isAudit) { "AUDIT (monitor only - nothing is blocked)" } else { "ENFORCE (active blocking)" }
|
|
>> "%RS%" echo $gLine = Select-String -Path $xmlBase -Pattern "<PolicyID>\{(.+?)\}</PolicyID>"
|
|
>> "%RS%" echo $guid = if ($gLine) { $gLine.Matches[0].Groups[1].Value } else { "Unknown" }
|
|
>> "%RS%" echo $out.Add(" POLICY INFORMATION")
|
|
>> "%RS%" echo $out.Add(" Policy Name : WindowsSentinelPolicy")
|
|
>> "%RS%" echo $out.Add(" Policy GUID : {$guid}")
|
|
>> "%RS%" echo $out.Add(" Policy Mode : $mode")
|
|
>> "%RS%" echo $out.Add(" Policy File : $xmlBase")
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add(" SECTION 1 - WHITELISTED ITEMS")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $out.Add(" [ALWAYS ALLOWED]")
|
|
>> "%RS%" echo $out.Add(" All files signed by Microsoft Corporation or Microsoft Windows.")
|
|
>> "%RS%" echo $out.Add(" Examples: notepad.exe, powershell.exe, cmd.exe, explorer.exe, calc.exe")
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo if (Test-Path "C:\WDAC\detected_av_paths.txt") {
|
|
>> "%RS%" echo $avPaths = Get-Content "C:\WDAC\detected_av_paths.txt" ^| Where-Object { $_.Trim() -ne "" }
|
|
>> "%RS%" echo if ($avPaths) {
|
|
>> "%RS%" echo $out.Add(" [WHITELISTED] AV/EDR Products (path rules - anything in these folders runs)")
|
|
>> "%RS%" echo foreach ($p in $avPaths) {
|
|
>> "%RS%" echo $out.Add(" Folder: $p")
|
|
>> "%RS%" echo $dir = $p -replace "\\\*", ""
|
|
>> "%RS%" echo $exe = Get-ChildItem $dir -Filter "*.exe" -ErrorAction SilentlyContinue ^| Select-Object -First 1
|
|
>> "%RS%" echo if ($exe) {
|
|
>> "%RS%" echo $sig = Get-AuthenticodeSignature $exe.FullName -ErrorAction SilentlyContinue
|
|
>> "%RS%" echo if ($sig.SignerCertificate) { $out.Add(" Signed By: $($sig.SignerCertificate.Subject)") }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo if (Test-Path "C:\WDAC\detected_apps.json") {
|
|
>> "%RS%" echo $apps = Get-Content "C:\WDAC\detected_apps.json" ^| ConvertFrom-Json
|
|
>> "%RS%" echo $exRaw = (Get-Content "C:\WDAC\app_exclusions.txt" -ErrorAction SilentlyContinue) -join ""
|
|
>> "%RS%" echo $exNums = $exRaw -split ',' ^| ForEach-Object { $_.Trim() } ^| Where-Object { [int32]::TryParse($_, [ref]$null) } ^| ForEach-Object { [int]$_ }
|
|
>> "%RS%" echo $allowed = @($apps ^| Where-Object { $exNums -notcontains $_.Index })
|
|
>> "%RS%" echo $denied = @($apps ^| Where-Object { $exNums -contains $_.Index })
|
|
>> "%RS%" echo if ($allowed.Count -gt 0) {
|
|
>> "%RS%" echo $out.Add(" [WHITELISTED] Installed Applications")
|
|
>> "%RS%" echo foreach ($app in $allowed) {
|
|
>> "%RS%" echo $out.Add(" [$($app.RuleType)] $($app.Name)")
|
|
>> "%RS%" echo $out.Add(" Path : $($app.Path)")
|
|
>> "%RS%" echo $out.Add(" Publisher : $($app.Publisher)")
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo if ($denied.Count -gt 0) {
|
|
>> "%RS%" echo $out.Add(" [BLOCKED] Manually excluded applications")
|
|
>> "%RS%" echo foreach ($app in $denied) {
|
|
>> "%RS%" echo $out.Add(" Blocked: $($app.Name) at $($app.Path)")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add(" SECTION 2 - EXTENSION ENFORCEMENT STATUS")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo if (Test-Path $xmlBase) {
|
|
>> "%RS%" echo $xc = Get-Content $xmlBase -Raw
|
|
>> "%RS%" echo $dllOff = $xc -match "Disabled:DLL Code Integrity"
|
|
>> "%RS%" echo $scrOff = $xc -match "Disabled:Script Enforcement"
|
|
>> "%RS%" echo $pkgOff = $xc -match "Disabled:UMCI"
|
|
>> "%RS%" echo $out.Add(" Extension Status Notes")
|
|
>> "%RS%" echo $out.Add(" ------------ ---------- ------------------------------------------------")
|
|
>> "%RS%" echo $out.Add(" .exe ENFORCED Always enforced by base template")
|
|
>> "%RS%" echo if ($dllOff) { $out.Add(" .dll ALLOWED Option 19 set - DLL enforcement off") }
|
|
>> "%RS%" echo else { $out.Add(" .dll ENFORCED Libraries must be signed or whitelisted") }
|
|
>> "%RS%" echo $out.Add(" .sys ENFORCED Kernel drivers always enforced")
|
|
>> "%RS%" echo if ($scrOff) { $out.Add(" .ps1 ALLOWED Option 16 set - script enforcement off") }
|
|
>> "%RS%" echo else { $out.Add(" .ps1 ENFORCED PowerShell scripts must be signed") }
|
|
>> "%RS%" echo if ($scrOff) { $out.Add(" .bat / .cmd ALLOWED Script enforcement off") }
|
|
>> "%RS%" echo else { $out.Add(" .bat / .cmd ENFORCED Batch scripts must be signed") }
|
|
>> "%RS%" echo if ($scrOff) { $out.Add(" .vbs / .js ALLOWED Script enforcement off") }
|
|
>> "%RS%" echo else { $out.Add(" .vbs / .js ENFORCED VBScript and JScript must be signed") }
|
|
>> "%RS%" echo if ($scrOff) { $out.Add(" .hta ALLOWED Script enforcement off") }
|
|
>> "%RS%" echo else { $out.Add(" .hta ENFORCED HTML Applications must be signed") }
|
|
>> "%RS%" echo if ($scrOff) { $out.Add(" .wsf / .wsh ALLOWED Script enforcement off") }
|
|
>> "%RS%" echo else { $out.Add(" .wsf / .wsh ENFORCED Windows Script Host files must be signed") }
|
|
>> "%RS%" echo if ($pkgOff) { $out.Add(" .appx / .msix ALLOWED Package enforcement off") }
|
|
>> "%RS%" echo else { $out.Add(" .appx / .msix ENFORCED Only Microsoft-signed packages allowed") }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add(" SECTION 3 - SETUP CONFIGURATION")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo # VMware Tools status - check for VMware path rules in XML
|
|
>> "%RS%" echo if (Test-Path $xmlBase) {
|
|
>> "%RS%" echo $xc = Get-Content $xmlBase -Raw
|
|
>> "%RS%" echo if ($xc -match "VMware") {
|
|
>> "%RS%" echo $out.Add(" VMware Tools : WHITELISTED (path rules applied)")
|
|
>> "%RS%" echo } else {
|
|
>> "%RS%" echo $out.Add(" VMware Tools : NOT whitelisted")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo # LOLBAS deny rules
|
|
>> "%RS%" echo $lolbasNames = @{}
|
|
>> "%RS%" echo $lolbasNames[1] = "msbuild.exe"
|
|
>> "%RS%" echo $lolbasNames[2] = "regsvr32.exe"
|
|
>> "%RS%" echo $lolbasNames[3] = "rundll32.exe"
|
|
>> "%RS%" echo $lolbasNames[4] = "certutil.exe"
|
|
>> "%RS%" echo $lolbasNames[5] = "installutil.exe"
|
|
>> "%RS%" echo $lolbasNames[6] = "regasm.exe"
|
|
>> "%RS%" echo $lolbasNames[7] = "regsvcs.exe"
|
|
>> "%RS%" echo $lolbasNames[8] = "cmstp.exe"
|
|
>> "%RS%" echo $lolbasNames[9] = "odbcconf.exe"
|
|
>> "%RS%" echo $lolbasNames[10] = "cscript.exe"
|
|
>> "%RS%" echo $lolbasNames[11] = "wscript.exe"
|
|
>> "%RS%" echo $lolbasNames[12] = "mshta.exe"
|
|
>> "%RS%" echo $lolbasNames[13] = "powershell.exe"
|
|
>> "%RS%" echo $lolbasNames[14] = "pwsh.exe"
|
|
>> "%RS%" echo $lolbasNames[15] = "presentationhost.exe"
|
|
>> "%RS%" echo $lolbasNames[16] = "ieexec.exe"
|
|
>> "%RS%" echo $lolbasNames[17] = "microsoft.workflow.compiler.exe"
|
|
>> "%RS%" echo $lolbasNames[18] = "desktopimgdownldr.exe"
|
|
>> "%RS%" echo $lolbasNames[19] = "syncappvpublishingserver.exe"
|
|
>> "%RS%" echo $lolbasNames[20] = "bash.exe"
|
|
>> "%RS%" echo $lolbasNames[21] = "wsl.exe"
|
|
>> "%RS%" echo $lolbasNames[22] = "ftp.exe"
|
|
>> "%RS%" echo $lolbasNames[23] = "bitsadmin.exe"
|
|
>> "%RS%" echo $lolbasNames[24] = "forfiles.exe"
|
|
>> "%RS%" echo $lolbasNames[25] = "pcalua.exe"
|
|
>> "%RS%" echo $lolbasNames[26] = "verclsid.exe"
|
|
>> "%RS%" echo $lolbasNames[27] = "mofcomp.exe"
|
|
>> "%RS%" echo $lolbasNames[28] = "msiexec.exe"
|
|
>> "%RS%" echo $lolbasNames[29] = "dxcap.exe"
|
|
>> "%RS%" echo $lolbasNames[30] = "cmd.exe"
|
|
>> "%RS%" echo $lolbasNames[31] = "wt.exe"
|
|
>> "%RS%" echo $lolbasFile = "C:\WDAC\lolbas_deny.txt"
|
|
>> "%RS%" echo if (Test-Path $lolbasFile) {
|
|
>> "%RS%" echo $lolbasRaw = (Get-Content $lolbasFile -Raw -ErrorAction SilentlyContinue) -join ""
|
|
>> "%RS%" echo $lolbasNums = $lolbasRaw -split ',' ^| ForEach-Object { $_.Trim() } ^| Where-Object { [int32]::TryParse($_, [ref]$null) } ^| ForEach-Object { [int]$_ }
|
|
>> "%RS%" echo if ($lolbasNums.Count -gt 0) {
|
|
>> "%RS%" echo $out.Add(" LOLBAS Deny Rules Applied:")
|
|
>> "%RS%" echo foreach ($num in ($lolbasNums ^| Sort-Object)) {
|
|
>> "%RS%" echo $name = if ($lolbasNames.ContainsKey($num)) { $lolbasNames[$num] } else { "Unknown ($num)" }
|
|
>> "%RS%" echo $out.Add(" [DENIED] $name")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $out.Add(" Note: deny rules block these binaries even if they are Microsoft-signed.")
|
|
>> "%RS%" echo $out.Add(" They take precedence over all whitelist rules.")
|
|
>> "%RS%" echo } else {
|
|
>> "%RS%" echo $out.Add(" LOLBAS Deny Rules : NONE (skipped during setup)")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo } else {
|
|
>> "%RS%" echo $out.Add(" LOLBAS Deny Rules : File not found (run /setup to configure)")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add(" SECTION 4 - AUDIT EVENTS (Event ID 3076 - Would Be Blocked)")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo try {
|
|
>> "%RS%" echo $evts = Get-WinEvent -LogName "Microsoft-Windows-CodeIntegrity/Operational" -EA SilentlyContinue ^|
|
|
>> "%RS%" echo Where-Object { $_.Id -eq 3076 } ^| Select-Object -First 100
|
|
>> "%RS%" echo if ($evts -and $evts.Count -gt 0) {
|
|
>> "%RS%" echo $out.Add(" Total: $($evts.Count) audit events (showing first 100)")
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $grouped = @{}
|
|
>> "%RS%" echo foreach ($ev in $evts) {
|
|
>> "%RS%" echo $m = [regex]::Match($ev.Message, 'File Name:\s+\\Device\\[^\\]+\\(.+)')
|
|
>> "%RS%" echo if (-not $m.Success) { $m = [regex]::Match($ev.Message, 'attempted to load ([^\s]+\.[A-Za-z0-9]+)') }
|
|
>> "%RS%" echo if ($m.Success) {
|
|
>> "%RS%" echo $fp = $m.Groups[1].Value
|
|
>> "%RS%" echo $ext = [System.IO.Path]::GetExtension($fp).ToLower()
|
|
>> "%RS%" echo if (-not $grouped.ContainsKey($ext)) { $grouped[$ext] = [System.Collections.Generic.List[string]]::new() }
|
|
>> "%RS%" echo if (-not $grouped[$ext].Contains($fp)) { $grouped[$ext].Add($fp) }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo foreach ($ext in ($grouped.Keys ^| Sort-Object)) {
|
|
>> "%RS%" echo $out.Add(" Extension: $ext ($($grouped[$ext].Count) unique files)")
|
|
>> "%RS%" echo foreach ($f in $grouped[$ext]) {
|
|
>> "%RS%" echo $out.Add(" WOULD BLOCK: $f")
|
|
>> "%RS%" echo $full = "C:\" + $f.TrimStart('\')
|
|
>> "%RS%" echo if (Test-Path $full) {
|
|
>> "%RS%" echo $sig = Get-AuthenticodeSignature $full -EA SilentlyContinue
|
|
>> "%RS%" echo $out.Add(" Signature : $($sig.StatusMessage)")
|
|
>> "%RS%" echo if ($sig.SignerCertificate) { $out.Add(" Signed By : $($sig.SignerCertificate.Subject)") }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo } else {
|
|
>> "%RS%" echo $out.Add(" No audit events found (Event ID 3076).")
|
|
>> "%RS%" echo $out.Add(" This is expected right after setup or if the machine has not been used yet.")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo } catch { $out.Add(" Error reading event log: $_") }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add(" SECTION 5 - BLOCKED EVENTS (Event ID 3077 - Actively Blocked)")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo try {
|
|
>> "%RS%" echo $bevts = Get-WinEvent -LogName "Microsoft-Windows-CodeIntegrity/Operational" -EA SilentlyContinue ^|
|
|
>> "%RS%" echo Where-Object { $_.Id -eq 3077 } ^| Select-Object -First 100
|
|
>> "%RS%" echo if ($bevts -and $bevts.Count -gt 0) {
|
|
>> "%RS%" echo $out.Add(" Total: $($bevts.Count) blocked events (showing first 100)")
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $bgrouped = @{}
|
|
>> "%RS%" echo foreach ($ev in $bevts) {
|
|
>> "%RS%" echo $m = [regex]::Match($ev.Message, 'File Name:\s+\\Device\\[^\\]+\\(.+)')
|
|
>> "%RS%" echo if (-not $m.Success) { $m = [regex]::Match($ev.Message, 'attempted to load ([^\s]+\.[A-Za-z0-9]+)') }
|
|
>> "%RS%" echo if ($m.Success) {
|
|
>> "%RS%" echo $fp = $m.Groups[1].Value
|
|
>> "%RS%" echo $ext = [System.IO.Path]::GetExtension($fp).ToLower()
|
|
>> "%RS%" echo if (-not $bgrouped.ContainsKey($ext)) { $bgrouped[$ext] = [System.Collections.Generic.List[string]]::new() }
|
|
>> "%RS%" echo if (-not $bgrouped[$ext].Contains($fp)) { $bgrouped[$ext].Add($fp) }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo foreach ($ext in ($bgrouped.Keys ^| Sort-Object)) {
|
|
>> "%RS%" echo $out.Add(" Extension: $ext ($($bgrouped[$ext].Count) unique files)")
|
|
>> "%RS%" echo foreach ($f in $bgrouped[$ext]) {
|
|
>> "%RS%" echo $out.Add(" BLOCKED : $f")
|
|
>> "%RS%" echo $full = "C:\" + $f.TrimStart('\')
|
|
>> "%RS%" echo if (Test-Path $full) {
|
|
>> "%RS%" echo $sig = Get-AuthenticodeSignature $full -EA SilentlyContinue
|
|
>> "%RS%" echo $out.Add(" Signature: $($sig.StatusMessage)")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo } else {
|
|
>> "%RS%" echo $out.Add(" No blocked events (Event ID 3077). Expected if still in Audit Mode.")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo } catch { $out.Add(" Error reading event log: $_") }
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add(" SECTION 6 - ACTIVE POLICIES ON THIS MACHINE")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo $polDir = "$env:SystemRoot\System32\CodeIntegrity\CIPolicies\Active"
|
|
>> "%RS%" echo $pols = Get-ChildItem $polDir -Filter "*.cip" -EA SilentlyContinue
|
|
>> "%RS%" echo if ($pols) {
|
|
>> "%RS%" echo foreach ($pol in $pols) {
|
|
>> "%RS%" echo $out.Add(" File : $($pol.Name)")
|
|
>> "%RS%" echo $out.Add(" Size : $($pol.Length) bytes")
|
|
>> "%RS%" echo $out.Add(" Date : $($pol.LastWriteTime)")
|
|
>> "%RS%" echo $out.Add("")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo } else {
|
|
>> "%RS%" echo $out.Add(" No active .cip policy files found.")
|
|
>> "%RS%" echo }
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out.Add(" END OF REPORT")
|
|
>> "%RS%" echo $out.Add($sep)
|
|
>> "%RS%" echo $out ^| Out-File -FilePath $reportPath -Encoding UTF8
|
|
>> "%RS%" echo Write-Host "[+] Report saved: $reportPath"
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%RS%"
|
|
echo.
|
|
echo [+] Report saved to: %WDAC_FOLDER%\WDAC_Report.txt
|
|
echo.
|
|
start notepad "%WDAC_FOLDER%\WDAC_Report.txt"
|
|
|
|
if "!REPORT_ONLY!"=="1" goto END
|
|
|
|
echo ============================================================
|
|
echo Rebooting in 10 seconds to activate Enforce Mode...
|
|
echo Press CTRL+C to cancel.
|
|
echo ============================================================
|
|
echo.
|
|
timeout /t 10
|
|
shutdown /r /t 0
|
|
goto END
|
|
|
|
:: ============================================================
|
|
:: HARDEN MODE - Insider Threat Hardening
|
|
:: ============================================================
|
|
:DO_HARDEN
|
|
echo ============================================================
|
|
echo ENFORCE + INSIDER THREAT HARDENING
|
|
echo ============================================================
|
|
echo.
|
|
echo This will ENFORCE the policy and apply insider threat hardening.
|
|
echo.
|
|
echo 0. Enforce - Switch policy from Audit to Enforce Mode.
|
|
echo After reboot all non-whitelisted apps are blocked.
|
|
echo.
|
|
echo 1. NTFS ACLs - Deny read access on denied LOLBAS binaries.
|
|
echo Standard users cannot read or copy the tools.
|
|
echo.
|
|
echo 2. GPO Policy - Disable cmd.exe for standard users.
|
|
echo Hide C:\ drive from Explorer.
|
|
echo Disable Registry Editor for standard users.
|
|
echo.
|
|
echo 3. WDAC Rules - Deny execution from user-writable paths.
|
|
echo Desktop, Downloads and Temp blocked.
|
|
echo.
|
|
echo Requires Deploy-WDAC.bat /setup to have been run first.
|
|
echo Admin and SYSTEM accounts are NOT affected by hardening.
|
|
echo A reboot is required to fully activate all changes.
|
|
echo.
|
|
|
|
if not exist "%WDAC_FOLDER%\lolbas_deny.txt" (
|
|
echo ERROR: lolbas_deny.txt not found. Run /setup first.
|
|
goto END_NOCLEAN
|
|
)
|
|
if not exist "%WDAC_FOLDER%\policy_guid.txt" (
|
|
echo ERROR: policy_guid.txt not found. Run /setup first.
|
|
goto END_NOCLEAN
|
|
)
|
|
if not exist "%XML_PATH%" (
|
|
echo ERROR: WSSentinel.xml not found. Run /setup first.
|
|
goto END_NOCLEAN
|
|
)
|
|
|
|
set "HARDEN_CONF="
|
|
set /p HARDEN_CONF=" Enforce + Apply insider threat hardening? [YES/NO]: "
|
|
if /i "!HARDEN_CONF!" neq "YES" (
|
|
echo Cancelled.
|
|
goto END_NOCLEAN
|
|
)
|
|
echo.
|
|
echo [*] Step 0 - Switching to Enforce Mode...
|
|
echo.
|
|
|
|
set "ES=%WDAC_FOLDER%\enforce_policy.ps1"
|
|
if exist "%ES%" del "%ES%"
|
|
|
|
>> "%ES%" echo $xmlPath = "C:\WDAC\WSSentinel.xml"
|
|
>> "%ES%" echo $activeDir = "$env:SystemRoot\System32\CodeIntegrity\CIPolicies\Active"
|
|
>> "%ES%" echo $guid = (Get-Content "C:\WDAC\policy_guid.txt" -Raw).Trim()
|
|
>> "%ES%" echo $cip = "C:\WDAC\$guid.cip"
|
|
>> "%ES%" echo $dest = "$activeDir\$guid.cip"
|
|
>> "%ES%" echo Set-RuleOption -FilePath $xmlPath -Option 3 -Delete
|
|
>> "%ES%" echo $stillAudit = Select-String -Path $xmlPath -Pattern "Audit" -Quiet
|
|
>> "%ES%" echo if ($stillAudit) {
|
|
>> "%ES%" echo Write-Host "ERROR: Audit Mode still present. Aborting."
|
|
>> "%ES%" echo exit 1
|
|
>> "%ES%" echo }
|
|
>> "%ES%" echo Write-Host "[+] Audit Mode removed from policy."
|
|
>> "%ES%" echo ConvertFrom-CIPolicy -XmlFilePath $xmlPath -BinaryFilePath $cip ^| Out-Null
|
|
>> "%ES%" echo Write-Host "[+] Recompiled in Enforce Mode."
|
|
>> "%ES%" echo Copy-Item $cip $dest -Force
|
|
>> "%ES%" echo $r = Invoke-CimMethod -Namespace "root\Microsoft\Windows\CI" -ClassName "PS_UpdateAndCompareCIPolicy" -MethodName "Update" -Arguments @{FilePath=$dest}
|
|
>> "%ES%" echo if ($r.ReturnValue -eq 0) { Write-Host "[+] Enforce Mode deployed." }
|
|
>> "%ES%" echo else { Write-Host "Warning: CIM ReturnValue = $($r.ReturnValue)" }
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%ES%"
|
|
echo.
|
|
|
|
echo [*] Step 1-3 - Applying insider threat hardening...
|
|
echo.
|
|
|
|
set "HS=%WDAC_FOLDER%\harden.ps1"
|
|
if exist "%HS%" del "%HS%"
|
|
|
|
>> "%HS%" echo $xmlPath = "C:\WDAC\WSSentinel.xml"
|
|
>> "%HS%" echo $lolbasFile = "C:\WDAC\lolbas_deny.txt"
|
|
>> "%HS%" echo $lolbasRaw = (Get-Content $lolbasFile -Raw -ErrorAction SilentlyContinue) -join ""
|
|
>> "%HS%" echo $lolbasNums = $lolbasRaw -split ',' ^| ForEach-Object { $_.Trim() } ^| Where-Object { [int32]::TryParse($_, [ref]$null) } ^| ForEach-Object { [int]$_ }
|
|
>> "%HS%" echo $pathMap = @{}
|
|
>> "%HS%" echo $pathMap[1] = @("C:\Windows\Microsoft.NET\Framework*\MSBuild.exe","C:\Windows\Microsoft.NET\Framework64*\MSBuild.exe")
|
|
>> "%HS%" echo $pathMap[2] = @("C:\Windows\System32\regsvr32.exe","C:\Windows\SysWOW64\regsvr32.exe")
|
|
>> "%HS%" echo $pathMap[3] = @("C:\Windows\System32\rundll32.exe","C:\Windows\SysWOW64\rundll32.exe")
|
|
>> "%HS%" echo $pathMap[4] = @("C:\Windows\System32\certutil.exe")
|
|
>> "%HS%" echo $pathMap[5] = @("C:\Windows\Microsoft.NET\Framework*\InstallUtil.exe","C:\Windows\Microsoft.NET\Framework64*\InstallUtil.exe")
|
|
>> "%HS%" echo $pathMap[6] = @("C:\Windows\Microsoft.NET\Framework*\RegAsm.exe","C:\Windows\Microsoft.NET\Framework64*\RegAsm.exe")
|
|
>> "%HS%" echo $pathMap[7] = @("C:\Windows\Microsoft.NET\Framework*\RegSvcs.exe","C:\Windows\Microsoft.NET\Framework64*\RegSvcs.exe")
|
|
>> "%HS%" echo $pathMap[8] = @("C:\Windows\System32\cmstp.exe")
|
|
>> "%HS%" echo $pathMap[9] = @("C:\Windows\System32\odbcconf.exe")
|
|
>> "%HS%" echo $pathMap[10] = @("C:\Windows\System32\cscript.exe","C:\Windows\SysWOW64\cscript.exe")
|
|
>> "%HS%" echo $pathMap[11] = @("C:\Windows\System32\wscript.exe","C:\Windows\SysWOW64\wscript.exe")
|
|
>> "%HS%" echo $pathMap[12] = @("C:\Windows\System32\mshta.exe","C:\Windows\SysWOW64\mshta.exe")
|
|
>> "%HS%" echo $pathMap[13] = @("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe","C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe")
|
|
>> "%HS%" echo $pathMap[14] = @("C:\Program Files\PowerShell\*\pwsh.exe")
|
|
>> "%HS%" echo $pathMap[15] = @("C:\Windows\System32\presentationhost.exe")
|
|
>> "%HS%" echo $pathMap[16] = @("C:\Windows\Microsoft.NET\Framework*\ieexec.exe","C:\Windows\Microsoft.NET\Framework64*\ieexec.exe")
|
|
>> "%HS%" echo $pathMap[17] = @("C:\Windows\Microsoft.NET\Framework*\microsoft.workflow.compiler.exe","C:\Windows\Microsoft.NET\Framework64*\microsoft.workflow.compiler.exe")
|
|
>> "%HS%" echo $pathMap[18] = @("C:\Windows\System32\desktopimgdownldr.exe")
|
|
>> "%HS%" echo $pathMap[19] = @("C:\Windows\System32\syncappvpublishingserver.exe","C:\Windows\SysWOW64\syncappvpublishingserver.exe")
|
|
>> "%HS%" echo $pathMap[20] = @("C:\Windows\System32\bash.exe")
|
|
>> "%HS%" echo $pathMap[21] = @("C:\Windows\System32\wsl.exe")
|
|
>> "%HS%" echo $pathMap[22] = @("C:\Windows\System32\ftp.exe")
|
|
>> "%HS%" echo $pathMap[23] = @("C:\Windows\System32\bitsadmin.exe")
|
|
>> "%HS%" echo $pathMap[24] = @("C:\Windows\System32\forfiles.exe")
|
|
>> "%HS%" echo $pathMap[25] = @("C:\Windows\System32\pcalua.exe")
|
|
>> "%HS%" echo $pathMap[26] = @("C:\Windows\System32\verclsid.exe")
|
|
>> "%HS%" echo $pathMap[27] = @("C:\Windows\System32\wbem\mofcomp.exe")
|
|
>> "%HS%" echo $pathMap[28] = @("C:\Windows\System32\msiexec.exe","C:\Windows\SysWOW64\msiexec.exe")
|
|
>> "%HS%" echo $pathMap[29] = @("C:\Windows\System32\dxcap.exe")
|
|
>> "%HS%" echo $pathMap[30] = @("C:\Windows\System32\cmd.exe","C:\Windows\SysWOW64\cmd.exe")
|
|
>> "%HS%" echo $pathMap[31] = @("C:\Program Files\WindowsApps\Microsoft.WindowsTerminal*\wt.exe","C:\Program Files\WindowsApps\Microsoft.WindowsTerminalPreview*\wt.exe")
|
|
>> "%HS%" echo # -------------------------------------------------------
|
|
>> "%HS%" echo # SECTION 1 - NTFS ACLs
|
|
>> "%HS%" echo # -------------------------------------------------------
|
|
>> "%HS%" echo Write-Host "[Section 1] Applying NTFS ACLs to denied LOLBAS binaries..."
|
|
>> "%HS%" echo Write-Host " Deny read+execute for BUILTIN\Users. SYSTEM and Admins unaffected."
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo $usersSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-545")
|
|
>> "%HS%" echo $aclCount = 0
|
|
>> "%HS%" echo foreach ($num in $lolbasNums) {
|
|
>> "%HS%" echo if (-not $pathMap.ContainsKey($num)) { continue }
|
|
>> "%HS%" echo foreach ($pattern in $pathMap[$num]) {
|
|
>> "%HS%" echo $resolved = @(Get-Item -Path $pattern -ErrorAction SilentlyContinue)
|
|
>> "%HS%" echo foreach ($file in $resolved) {
|
|
>> "%HS%" echo try {
|
|
>> "%HS%" echo $acl = Get-Acl $file.FullName -ErrorAction Stop
|
|
>> "%HS%" echo $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($usersSid,"ReadAndExecute","Deny")
|
|
>> "%HS%" echo $acl.AddAccessRule($rule)
|
|
>> "%HS%" echo Set-Acl $file.FullName $acl -ErrorAction Stop
|
|
>> "%HS%" echo Write-Host " [ACL] $($file.FullName)"
|
|
>> "%HS%" echo $aclCount++
|
|
>> "%HS%" echo } catch {
|
|
>> "%HS%" echo Write-Host " [SKIP] $($file.FullName) - $($_.Exception.Message)"
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host " [+] ACLs applied to $aclCount binaries."
|
|
>> "%HS%" echo # -------------------------------------------------------
|
|
>> "%HS%" echo # SECTION 2 - GPO Registry
|
|
>> "%HS%" echo # -------------------------------------------------------
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host "[Section 2] Applying GPO registry settings..."
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo $sysPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System"
|
|
>> "%HS%" echo if (-not (Test-Path $sysPath)) { New-Item -Path $sysPath -Force ^| Out-Null }
|
|
>> "%HS%" echo Set-ItemProperty $sysPath "DisableCMD" 1
|
|
>> "%HS%" echo Write-Host " [GPO] cmd.exe disabled for standard users"
|
|
>> "%HS%" echo $expPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer"
|
|
>> "%HS%" echo if (-not (Test-Path $expPath)) { New-Item -Path $expPath -Force ^| Out-Null }
|
|
>> "%HS%" echo Set-ItemProperty $expPath "NoDrives" 4
|
|
>> "%HS%" echo Write-Host " [GPO] C:\ hidden in Explorer (NoDrives=4)"
|
|
>> "%HS%" echo Set-ItemProperty $expPath "NoViewOnDrive" 4
|
|
>> "%HS%" echo Write-Host " [GPO] C:\ contents blocked in Explorer (NoViewOnDrive=4)"
|
|
>> "%HS%" echo $polPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
|
|
>> "%HS%" echo if (-not (Test-Path $polPath)) { New-Item -Path $polPath -Force ^| Out-Null }
|
|
>> "%HS%" echo Set-ItemProperty $polPath "DisableRegistryTools" 1
|
|
>> "%HS%" echo Write-Host " [GPO] Registry Editor disabled for standard users"
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host " [+] GPO settings applied. Takes effect at next logon."
|
|
>> "%HS%" echo # -------------------------------------------------------
|
|
>> "%HS%" echo # SECTION 3 - WDAC deny rules for user-writable paths
|
|
>> "%HS%" echo # -------------------------------------------------------
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host "[Section 3] Adding WDAC deny rules for user-writable paths..."
|
|
>> "%HS%" echo Write-Host " Blocks execution from Desktop, Downloads and Temp"
|
|
>> "%HS%" echo Write-Host " even for Microsoft-signed binaries copied there."
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo $denyPaths = @("C:\Users\*\Desktop\*","C:\Users\*\Downloads\*","C:\Users\*\AppData\Local\Temp\*","C:\Windows\Temp\*","C:\Temp\*")
|
|
>> "%HS%" echo $pathDenyRules = @()
|
|
>> "%HS%" echo foreach ($dp in $denyPaths) {
|
|
>> "%HS%" echo $pathDenyRules += (New-CIPolicyRule -FilePathRule $dp -Deny)
|
|
>> "%HS%" echo Write-Host " [DENY PATH] $dp"
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo if ($pathDenyRules.Count -gt 0) {
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host " Merging $($pathDenyRules.Count) path deny rules into policy..."
|
|
>> "%HS%" echo Merge-CIPolicy -PolicyPaths $xmlPath -Rules $pathDenyRules -OutputFilePath $xmlPath ^| Out-Null
|
|
>> "%HS%" echo $guid = (Get-Content "C:\WDAC\policy_guid.txt" -Raw).Trim()
|
|
>> "%HS%" echo $cip = "C:\WDAC\$guid.cip"
|
|
>> "%HS%" echo $dest = "$env:SystemRoot\System32\CodeIntegrity\CIPolicies\Active\$guid.cip"
|
|
>> "%HS%" echo ConvertFrom-CIPolicy -XmlFilePath $xmlPath -BinaryFilePath $cip ^| Out-Null
|
|
>> "%HS%" echo Copy-Item $cip $dest -Force
|
|
>> "%HS%" echo Invoke-CimMethod -Namespace "root\Microsoft\Windows\CI" -ClassName "PS_UpdateAndCompareCIPolicy" -MethodName "Update" -Arguments @{FilePath=$dest} ^| Out-Null
|
|
>> "%HS%" echo Write-Host " [+] Policy updated and redeployed."
|
|
>> "%HS%" echo }
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host "============================================================"
|
|
>> "%HS%" echo Write-Host " HARDENING COMPLETE"
|
|
>> "%HS%" echo Write-Host "============================================================"
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host " Applied:"
|
|
>> "%HS%" echo Write-Host " - LOLBAS binaries locked : read+execute denied for Users"
|
|
>> "%HS%" echo Write-Host " - cmd.exe : disabled via GPO for standard users"
|
|
>> "%HS%" echo Write-Host " - C:\ drive : hidden from Explorer"
|
|
>> "%HS%" echo Write-Host " - Registry Editor : disabled for standard users"
|
|
>> "%HS%" echo Write-Host " - Desktop/Downloads/Temp : execution blocked via WDAC"
|
|
>> "%HS%" echo Write-Host ""
|
|
>> "%HS%" echo Write-Host " Reboot recommended to apply changes to active user sessions."
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%HS%"
|
|
echo.
|
|
echo [+] Enforce + Hardening complete.
|
|
echo.
|
|
goto GENERATE_REPORT_THEN_REBOOT
|
|
|
|
:: ============================================================
|
|
:: REMOVE MODE
|
|
:: ============================================================
|
|
:DO_REMOVE
|
|
echo ============================================================
|
|
echo REMOVE WDAC POLICY
|
|
echo ============================================================
|
|
echo.
|
|
echo This will remove the WindowsSentinel WDAC policy.
|
|
echo After reboot, all application blocking will be disabled.
|
|
echo.
|
|
|
|
set "CONFIRM_RM="
|
|
set /p CONFIRM_RM=" Type YES to confirm removal: "
|
|
if /i "!CONFIRM_RM!" neq "YES" (
|
|
echo Cancelled.
|
|
goto END_NOCLEAN
|
|
)
|
|
echo.
|
|
|
|
if not exist "%WDAC_FOLDER%\Remove-WDAC.ps1" (
|
|
echo ERROR: Remove-WDAC.ps1 not found at %WDAC_FOLDER%
|
|
echo The rollback script is created the first time you run Deploy-WDAC.bat.
|
|
echo You can manually delete .cip files from:
|
|
echo %SystemRoot%\System32\CodeIntegrity\CIPolicies\Active\
|
|
goto END_NOCLEAN
|
|
)
|
|
|
|
powershell -ExecutionPolicy Bypass -File "%WDAC_FOLDER%\Remove-WDAC.ps1"
|
|
echo.
|
|
echo [+] Policy removal staged.
|
|
echo.
|
|
echo Rebooting in 10 seconds to complete removal...
|
|
echo Press CTRL+C to cancel.
|
|
echo.
|
|
timeout /t 10
|
|
shutdown /r /t 0
|
|
goto END_NOCLEAN
|
|
|
|
:: ============================================================
|
|
:: USAGE - Printed when no valid flag is supplied
|
|
:: ============================================================
|
|
:SHOW_USAGE
|
|
echo.
|
|
echo WindowsSentinel - WDAC Deployment Tool
|
|
echo.
|
|
echo Usage: Deploy-WDAC.bat [flag]
|
|
echo.
|
|
echo /setup Run the full setup wizard (first-time deployment)
|
|
echo /enforce Switch the deployed policy to Enforce Mode
|
|
echo /report Generate an audit report
|
|
echo /remove Remove the deployed policy and reboot
|
|
echo /harden Enforce policy + apply insider threat hardening
|
|
echo /help Show full help including step-by-step descriptions
|
|
echo.
|
|
echo Run Deploy-WDAC.bat /help for detailed information.
|
|
echo.
|
|
goto END_NOCLEAN
|
|
|
|
:: ============================================================
|
|
:: HELP - Full reference printed by /help flag
|
|
:: ============================================================
|
|
:SHOW_HELP
|
|
echo.
|
|
echo ============================================================
|
|
echo WindowsSentinel - WDAC Deployment Tool
|
|
echo Windows Defender Application Control for SOC and Sysadmins
|
|
echo ============================================================
|
|
echo.
|
|
echo WHAT THIS SCRIPT DOES
|
|
echo ---------------------
|
|
echo This script deploys a Windows Defender Application Control
|
|
echo (WDAC) policy that restricts which programs are allowed to
|
|
echo run on this machine. By default it trusts only Microsoft-
|
|
echo signed binaries. Everything else - Chrome, Firefox, Office,
|
|
echo third-party tools - is blocked unless you explicitly whitelist
|
|
echo it during setup.
|
|
echo.
|
|
echo There are two stages:
|
|
echo.
|
|
echo Audit Mode - The policy is active but nothing is blocked.
|
|
echo Windows logs what WOULD have been blocked so
|
|
echo you can review and adjust before committing.
|
|
echo (Event ID 3076 in CodeIntegrity event log)
|
|
echo.
|
|
echo Enforce Mode - The policy actively blocks unauthorized files.
|
|
echo Blocked attempts are logged as Event ID 3077.
|
|
echo Only whitelisted apps will run.
|
|
echo.
|
|
echo REQUIREMENTS
|
|
echo ------------
|
|
echo - Must be run as Administrator
|
|
echo - Windows 10/11 Enterprise or Server 2016+
|
|
echo - ConfigCI PowerShell module (ships with above editions)
|
|
echo - citool.exe for pre-flight check (Windows 11 only)
|
|
echo.
|
|
echo FLAGS
|
|
echo -----
|
|
echo /setup Runs the full first-time setup wizard.
|
|
echo Scans the machine, lets you choose which apps
|
|
echo to whitelist, builds the policy, and deploys
|
|
echo it in Audit Mode. Reboots at the end.
|
|
echo.
|
|
echo /enforce Switches the already-deployed policy from Audit
|
|
echo Mode into Enforce Mode. Run this after reviewing
|
|
echo the /report output and confirming nothing
|
|
echo legitimate will be blocked. Reboots at the end.
|
|
echo.
|
|
echo /report Generates a full report without changing anything.
|
|
echo Shows whitelisted items, extension enforcement
|
|
echo status, audit events (what would be blocked),
|
|
echo active block events, and policies on disk.
|
|
echo Saves to C:\WDAC\WDAC_Report.txt and opens it.
|
|
echo.
|
|
echo /remove Removes the WindowsSentinel policy from this
|
|
echo machine and reboots. All application blocking
|
|
echo is disabled after reboot. Uses the rollback
|
|
echo script at C:\WDAC\Remove-WDAC.ps1.
|
|
echo.
|
|
echo /harden Enforces the policy AND applies insider threat
|
|
echo hardening in a single operation:
|
|
echo Step 0 - Switches policy to Enforce Mode
|
|
echo Step 1 - NTFS ACLs: denies read+execute on all
|
|
echo denied LOLBAS binaries for standard
|
|
echo users so they cannot copy the tools
|
|
echo Step 2 - GPO: disables cmd.exe for standard
|
|
echo users, hides C:\ drive in Explorer,
|
|
echo disables Registry Editor
|
|
echo Step 3 - WDAC path deny rules: blocks execution
|
|
echo from Desktop, Downloads and Temp even
|
|
echo for Microsoft-signed binaries copied there
|
|
echo Generates a report and reboots at the end.
|
|
echo Use this instead of /enforce when you also want
|
|
echo the insider threat protections applied.
|
|
echo.
|
|
echo /help Shows this screen.
|
|
echo.
|
|
echo SETUP WIZARD - STEP BY STEP (/setup)
|
|
echo --------------------------------------
|
|
echo.
|
|
echo STEP 0 Pre-flight Check
|
|
echo Scans all existing WDAC policies already on the
|
|
echo machine using citool.exe. Reports:
|
|
echo - Smart App Control status (on or off)
|
|
echo - Microsoft platform policies (safe, listed)
|
|
echo - Enterprise or third-party policies (conflict warning)
|
|
echo If conflicts are found you are asked to confirm
|
|
echo before continuing. Skipped gracefully on Windows 10
|
|
echo where citool.exe is not available.
|
|
echo.
|
|
echo STEP 1 Prerequisites
|
|
echo Confirms the Microsoft base policy template exists
|
|
echo and the ConfigCI PowerShell module is loaded.
|
|
echo Exits early with a clear message if either is missing.
|
|
echo.
|
|
echo STEP 2 File Extension Selection
|
|
echo Choose which file types to enforce:
|
|
echo 1 = .exe Executables
|
|
echo 2 = .dll Libraries loaded into processes
|
|
echo 3 = .sys Kernel drivers
|
|
echo 4 = .ps1 PowerShell scripts
|
|
echo 5 = .bat/.cmd Batch scripts
|
|
echo 6 = .vbs/.js VBScript and JScript
|
|
echo 7 = .hta HTML Applications (common attack vector)
|
|
echo 8 = .wsf/.wsh Windows Script Host files (attack vector)
|
|
echo 9 = .appx/.msix Package installers
|
|
echo A = All of the above (recommended)
|
|
echo You can combine options, e.g. 1,2,3 or 1,2,7,8
|
|
echo Note: options 4,5,6,7,8 all use script enforcement (Option 16).
|
|
echo Selecting any one of them enables it for all script types.
|
|
echo If you select 4,5,6,7 or 8, this script itself will be
|
|
echo blocked after Enforce Mode activates.
|
|
echo.
|
|
echo STEP 3 VMware Tools
|
|
echo If this is a VMware virtual machine, VMware Tools
|
|
echo provides copy/paste and display scaling between
|
|
echo the host and VM. Choose Y to whitelist it.
|
|
echo.
|
|
echo STEP 4 AV/EDR Auto-Detection
|
|
echo Automatically scans for 21 known security products
|
|
echo (CrowdStrike, SentinelOne, Cybereason, Sophos, etc.)
|
|
echo using three methods:
|
|
echo - Known install folder patterns
|
|
echo - Windows Security Center registration
|
|
echo - Running service executable paths
|
|
echo Detected products are always whitelisted so they
|
|
echo are never blocked by the policy.
|
|
echo.
|
|
echo STEP 5 Installed Application Scanner
|
|
echo Scans Program Files and Program Files (x86) for
|
|
echo installed software. Displays a numbered table:
|
|
echo.
|
|
echo No. Application Rule Type Publisher
|
|
echo --- ------------------ ---------- -----------------
|
|
echo 1 7-Zip Path UNSIGNED
|
|
echo 2 Google Chrome Publisher Google LLC
|
|
echo 3 Mozilla Firefox Publisher Mozilla Corporation
|
|
echo.
|
|
echo Two rule types:
|
|
echo Publisher - Rule tied to the app signing certificate.
|
|
echo Only files signed by that company run.
|
|
echo More secure. Used for signed apps.
|
|
echo Path - Rule tied to the install folder location.
|
|
echo Anything placed in that folder can run.
|
|
echo Used as fallback for unsigned apps.
|
|
echo.
|
|
echo Press ENTER to whitelist ALL apps shown.
|
|
echo Type numbers to EXCLUDE (block) specific apps, e.g. 1,4,7
|
|
echo.
|
|
echo STEP 6 LOLBAS Deny List
|
|
echo Living Off The Land Binaries - Microsoft-signed tools
|
|
echo commonly abused by attackers to execute code without
|
|
echo dropping malicious files. Select which to deny:
|
|
echo 1 = msbuild.exe Inline C# via .csproj/.targets
|
|
echo 2 = regsvr32.exe Squiblydoo COM scriptlet execution
|
|
echo 3 = rundll32.exe DLL/script execution (HIGH)
|
|
echo 4 = certutil.exe File download and base64 decode
|
|
echo 5 = installutil.exe .NET assembly WDAC bypass
|
|
echo 6 = regasm.exe .NET COM registration + execution
|
|
echo 7 = regsvcs.exe .NET COM+ registration + execution
|
|
echo 8 = cmstp.exe UAC bypass via INF file
|
|
echo 9 = odbcconf.exe DLL execution via ODBC config
|
|
echo 10 = cscript.exe JScript/VBScript execution (HIGH)
|
|
echo 11 = wscript.exe JScript/VBScript execution (HIGH)
|
|
echo 12 = mshta.exe HTA/JScript/VBScript execution
|
|
echo 13 = powershell.exe PowerShell execution (CRITICAL)
|
|
echo 14 = pwsh.exe PowerShell 7 execution (HIGH)
|
|
echo 15 = presentationhost.exe XAML execution
|
|
echo 16 = ieexec.exe .NET remote execution
|
|
echo 17 = microsoft.workflow.compiler.exe Workflow compile-and-execute
|
|
echo 18 = desktopimgdownldr.exe Payload retrieval via reg key
|
|
echo 19 = syncappvpublishingserver.exe Script execution via App-V
|
|
echo 20 = bash.exe WSL abuse
|
|
echo 21 = wsl.exe WSL abuse
|
|
echo 22 = ftp.exe File transfer / exfil
|
|
echo 23 = bitsadmin.exe Payload download (legacy)
|
|
echo 24 = forfiles.exe Command execution via files
|
|
echo 25 = pcalua.exe App Compat Layer execution
|
|
echo 26 = verclsid.exe COM object execution
|
|
echo 27 = mofcomp.exe WMI MOF compile/execute
|
|
echo 28 = msiexec.exe MSI-based code execution (CRITICAL)
|
|
echo 29 = dxcap.exe DLL loading abuse
|
|
echo 30 = cmd.exe Shell / batch execution (HIGH)
|
|
echo 31 = wt.exe Windows Terminal launcher
|
|
echo A = Deny all 31 (CRIT/HIGH items prompt for confirmation)
|
|
echo S = Skip (no deny rules added)
|
|
echo Options 3, 13, 28, 30 each show a confirmation warning.
|
|
echo Options 13 (powershell.exe) and 28 (msiexec.exe) are
|
|
echo CRITICAL - denying them can break management tools and
|
|
echo software installation respectively.
|
|
echo Option 30 (cmd.exe) is HIGH - blocks this script after enforce.
|
|
echo.
|
|
echo STEP 7 Build Policy
|
|
echo Copies the Microsoft DefaultWindows_Enforced base
|
|
echo template and applies your selections:
|
|
echo - Sets DLL enforcement on or off (Option 19)
|
|
echo - Sets script enforcement on or off (Option 16)
|
|
echo - Sets package enforcement on or off (Option 20)
|
|
echo - Enables Audit Mode (Option 3)
|
|
echo - Creates publisher rules for signed apps
|
|
echo - Creates path rules for unsigned apps and AV/EDR
|
|
echo - Merges LOLBAS deny rules into the policy
|
|
echo - Merges all rules into a single policy XML
|
|
echo Output: C:\WDAC\WSSentinel.xml
|
|
echo.
|
|
echo STEP 8 Rollback Script
|
|
echo Generates C:\WDAC\Remove-WDAC.ps1
|
|
echo This is your recovery script. If Enforce Mode ever
|
|
echo blocks something critical, run this as Administrator
|
|
echo then reboot to fully remove the policy.
|
|
echo Keep this file accessible at all times.
|
|
echo.
|
|
echo STEP 9 Deploy in Audit Mode
|
|
echo Compiles WSSentinel.xml to a binary .cip file,
|
|
echo copies it to the Active policies folder, triggers
|
|
echo a live reload, then reboots into Audit Mode.
|
|
echo Nothing is blocked yet after this reboot.
|
|
echo.
|
|
echo TYPICAL WORKFLOW
|
|
echo ----------------
|
|
echo There are two paths depending on how much review time you want.
|
|
echo.
|
|
echo PATH A - Full audit review (recommended for production)
|
|
echo --------------------------------------------------------
|
|
echo 1. Deploy-WDAC.bat /setup
|
|
echo Run the wizard. Reboot into Audit Mode.
|
|
echo.
|
|
echo 2. Use the machine normally for several days.
|
|
echo Run your apps, do your work as usual.
|
|
echo.
|
|
echo 3. Deploy-WDAC.bat /report
|
|
echo Review WDAC_Report.txt. Section 4 lists everything
|
|
echo that WOULD have been blocked. If you see legitimate
|
|
echo apps there, run /setup again and add them to the
|
|
echo whitelist before enforcing.
|
|
echo.
|
|
echo 4. Deploy-WDAC.bat /harden
|
|
echo When satisfied nothing legitimate will be blocked,
|
|
echo run /harden. This enforces the policy AND applies
|
|
echo insider threat hardening (NTFS ACLs, GPO settings,
|
|
echo WDAC path deny rules) in one shot. Reboots at end.
|
|
echo Machine is fully locked down after reboot.
|
|
echo.
|
|
echo If you only want enforcement without hardening:
|
|
echo Deploy-WDAC.bat /enforce
|
|
echo.
|
|
echo 5. Deploy-WDAC.bat /report (ongoing)
|
|
echo Run periodically to monitor what is being blocked.
|
|
echo.
|
|
echo PATH B - Single session lockdown (known environments)
|
|
echo -------------------------------------------------------
|
|
echo 1. Deploy-WDAC.bat /setup
|
|
echo At the end of Step 9, answer YES to the prompt:
|
|
echo "Enforce + Harden now? [YES/NO]"
|
|
echo This enforces the policy, applies all hardening,
|
|
echo and reboots in one session - before cmd.exe or
|
|
echo PowerShell are locked down.
|
|
echo Use only when you know exactly what is installed
|
|
echo and are confident nothing legitimate will be blocked.
|
|
echo.
|
|
echo FILES WRITTEN TO C:\WDAC\
|
|
echo --------------------------
|
|
echo WSSentinel.xml Policy in human-readable XML
|
|
echo policy_guid.txt Policy GUID used by all modes
|
|
echo detected_av_paths.txt AV/EDR folders whitelisted in Step 4
|
|
echo detected_apps.json Full app scan results from Step 5
|
|
echo app_exclusions.txt App numbers the user chose to block
|
|
echo Remove-WDAC.ps1 Permanent rollback script (Step 7)
|
|
echo WDAC_Report.txt Last generated report
|
|
echo {guid}.cip Compiled binary policy
|
|
echo.
|
|
echo RECOVERY
|
|
echo --------
|
|
echo If Enforce Mode blocks something critical:
|
|
echo.
|
|
echo Option 1 (recommended):
|
|
echo powershell -ExecutionPolicy Bypass -File C:\WDAC\Remove-WDAC.ps1
|
|
echo Then reboot.
|
|
echo.
|
|
echo Option 2 (if script is blocked too):
|
|
echo Boot into Windows Recovery Environment (WinRE)
|
|
echo Open Command Prompt and run:
|
|
echo del "%SystemRoot%\System32\CodeIntegrity\CIPolicies\Active\*.cip"
|
|
echo Then reboot normally.
|
|
echo.
|
|
goto END_NOCLEAN
|
|
|
|
:: ============================================================
|
|
:: CLEANUP TEMP PS SCRIPTS
|
|
:: ============================================================
|
|
:END
|
|
del "%WDAC_FOLDER%\detect_av.ps1" >nul 2>&1
|
|
del "%WDAC_FOLDER%\scan_apps.ps1" >nul 2>&1
|
|
del "%WDAC_FOLDER%\build_policy.ps1" >nul 2>&1
|
|
del "%WDAC_FOLDER%\deploy_policy.ps1" >nul 2>&1
|
|
del "%WDAC_FOLDER%\enforce_policy.ps1" >nul 2>&1
|
|
del "%WDAC_FOLDER%\generate_report.ps1" >nul 2>&1
|
|
del "%WDAC_FOLDER%\harden.ps1" >nul 2>&1
|
|
:: Note: lolbas_deny.txt is kept - the /report mode reads it for Section 3
|
|
|
|
:END_NOCLEAN
|
|
endlocal
|