Working on creating a custom variant of a common cryptoblocker script. I combined several versions of it to gain SMTP email configuration/notification & whitelist functionality but am running into an issue when trying to set up exclusions for folders (file name exclusions work fine). The problem I’m running into (aside from not being very knowledgeable with Powershell) is trying to get the script to pull from a list of whitelisted folders and also pull a list of the File Groups that it generates when it performs the New-CBArraySplit function, then running a command for each whitelisted folder that includes a parameter for only the file groups created with the New-CBArraySplit function.
For example, I made this section of code as a band-aid to get the project deployable at the moment since there are only 3 groups being made right now:
$excludedPaths | % { &filescrn.exe Exception Delete /Path:"$_" /Quiet &filescrn.exe Exception Add /Path:"$_" "/Add-Filegroup:CryptoBlockerGroup1" "/Add-Filegroup:CryptoBlockerGroup2" "/Add-Filegroup:CryptoBlockerGroup3" }
This is able to add an exception for each path listed in $excludedPaths and adds each of the aforementioned Groups (1 through 3) to the path exception. However, I’d like the script to be able to add in a /Add-Filegroup: for each group that it creates in the beginning. I tried a few things but they are obviously wrong and I could use some help. I may need to completely redo the list formatting for it to work, but I’m not sure what I should be doing instead.
The whole script (sanitized) is below:
################################ Functions ################################ write-debug continue function ConvertFrom-Json20([Object] $obj) { Add-Type -AssemblyName System.Web.Extensions $serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer return ,$serializer.DeserializeObject($obj) } Function New-CBArraySplit { param( $extArr, $depth = 1 ) $extArr = $extArr | Sort-Object -Unique # Concatenate the input array $conStr = $extArr -join ',' $outArr = @() # If the input string breaks the 4Kb limit If ($conStr.Length -gt 4096) { # Pull the first 4096 characters and split on comma $conArr = $conStr.SubString(0,4096).Split(',') # Find index of the last guaranteed complete item of the split array in the input array $endIndex = [array]::IndexOf($extArr,$conArr[-2]) # Build shorter array up to that indexNumber and add to output array $shortArr = $extArr[0..$endIndex] $outArr += [psobject] @{ index = $depth array = $shortArr } # Then call this function again to split further $newArr = $extArr[($endindex + 1)..($extArr.Count -1)] $outArr += New-CBArraySplit $newArr -depth ($depth + 1) return $outArr } # If the concat string is less than 4096 characters already, just return the input array Else { return [psobject] @{ index = $depth array = $extArr } } } ################################ Functions ################################ Function PurgeNonAdminDirectoryPermissions([string] $directory) { $acl = Get-Acl $directory if ($acl.AreAccessRulesProtected) { $acl.Access | % { $acl.PurgeAccessRules($_.IdentityReference) } } else { $acl.SetAccessRuleProtection($true, $true) } $ar = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM","FullControl","Allow") $acl.AddAccessRule($ar) $ar = $ar = New-Object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators","FullControl","Allow") $acl.AddAccessRule($ar) Set-Acl -AclObject $acl -Path $directory } ########################################################################### $SMTPServer = "255.255.255.255" #Change to your SMTP Server $AdminEmails = "DestinationEmailAddressGoesHere" #Comma Seperated $ServerFrom = "FromEmailAddressGoesHere" Function AddSMTP { filescrn.exe admin options /smtp:$SMTPServer /from:$ServerFrom /adminemails:$AdminEmails } # Create notification file. $EmailTo = "Email To Goes Here" $EmailFrom = "Email From Goes Here" $Subject = "Custom Subject Goes Here" $Message = "Custom Message Goes Here" $CryptoConf = "Notification=m`nTo=$EmailTo`nFrom=$EmailFrom`nSubject=$Subject`nMessage=$Message" New-Item C:\Apps\Blocker\conf.ini -type file -Value $CryptoConf -Force ########################################################################### # Add to all drives $drivesContainingShares = Get-WmiObject Win32_Share | Select Name,Path,Type | Where-Object { $_.Type -eq 0 } | Select -ExpandProperty Path | % { "$((Get-Item -ErrorAction SilentlyContinue $_).Root)" } | Select -Unique if ($drivesContainingShares -eq $null -or $drivesContainingShares.Length -eq 0) { Write-Host "No drives containing shares were found. Exiting.." exit } Write-Host "The following shares need to be protected: $($drivesContainingShares -Join ",")" $majorVer = [System.Environment]::OSVersion.Version.Major $minorVer = [System.Environment]::OSVersion.Version.Minor Write-Host "Checking for File Server Resource Manager.." Import-Module ServerManager if ($majorVer -ge 6) { $checkFSRM = Get-WindowsFeature -Name FS-Resource-Manager if ($minorVer -ge 2 -and $checkFSRM.Installed -ne "True") { # Server 2012 Write-Host "FSRM not found.. Installing (2012).." Install-WindowsFeature -Name FS-Resource-Manager -IncludeManagementTools } elseif ($minorVer -ge 1 -and $checkFSRM.Installed -ne "True") { # Server 2008 R2 Write-Host "FSRM not found.. Installing (2008 R2).." Add-WindowsFeature FS-FileServer, FS-Resource-Manager } elseif ($checkFSRM.Installed -ne "True") { # Server 2008 Write-Host "FSRM not found.. Installing (2008).." &servermanagercmd -Install FS-FileServer FS-Resource-Manager } } else { # Assume Server 2003 Write-Host "This version of Windows is not supported. Quitting." return } $fileGroupName = "CryptoBlockerGroup" $fileTemplateName = "CryptoBlockerTemplate" $fileScreenName = "CryptoBlockerScreen" $webClient = New-Object System.Net.WebClient $jsonStr = $webClient.DownloadString("https://fsrm.experiant.ca/api/v1/get") $monitoredExtensions = @(ConvertFrom-Json20($jsonStr) | % { $_.filters }) $scriptFilename = "C:\FSRMScripts\KillUserSession.ps1" $batchFilename = "C:\FSRMScripts\KillUserSession.bat" $eventConfFilename = "$env:Temp\blocker-eventnotify.txt" $cmdConfFilename = "$env:Temp\blocker-cmdnotify.txt" $exclusions = @(` $MyInvocation.MyCommand.Name, $($MyInvocation.MyCommand.Name + ".*"), "cryptoblocker-eventnotify.txt",` "cryptoblocker-cmdnotify.txt",` "*upload.zzz",` "*debug.log.*.upload.zzz"` ) $excludedPaths = @(` "C:\Windows",` "C:\Test2",` "C:\Test3",` "C:\ProgramData\Kaspersky Lab"` ) $scriptConf = @' param([string] $DomainUser) Function DenySharePermission ([string] $ShareName, [string] $DomainUser) { $domainUserSplit = $DomainUser.Split("\") $trusteeClass = [wmiclass] "ROOT\CIMV2:Win32_Trustee" $trustee = $trusteeClass.CreateInstance() $trustee.Domain = $domainUserSplit[0] $trustee.Name = $domainUserSplit[1] $aceClass = [wmiclass] "ROOT\CIMV2:Win32_ACE" $ace = $aceClass.CreateInstance() $ace.AccessMask = 2032127 $ace.AceType = 1 $ace.Trustee = $trustee $shss = Get-WmiObject -Class Win32_LogicalShareSecuritySetting -Filter "Name='$ShareName'" $sd = Invoke-WmiMethod -InputObject $shss -Name GetSecurityDescriptor | Select -ExpandProperty Descriptor $sclass = [wmiclass] "ROOT\CIMV2:Win32_SecurityDescriptor" $newsd = $sclass.CreateInstance() $newsd.ControlFlags = $sd.ControlFlags foreach ($oace in $sd.DACL) { $newsd.DACL += [System.Management.ManagementBaseObject] $oace } $newsd.DACL += [System.Management.ManagementBaseObject] $ace $share = Get-WmiObject -Class Win32_LogicalShareSecuritySetting -Filter "Name='$ShareName'" $setResult = $share.SetSecurityDescriptor($newsd) return $setResult.ReturnValue } # Let's try altering share permissions.. $Username = $DomainUser.Split("\")[1] $affectedShares = Get-WmiObject -Class Win32_Share | Select Name, Path, Type | Where { $_.Type -eq 0 } $affectedShares | % { Write-Host "Denying [$DomainUser] access to share [$($_.Name)].." DenySharePermission -ShareName $_.Name -DomainUser $DomainUser } Write-Host $affectedShares '@ $batchConf = @" @echo off powershell.exe -ExecutionPolicy Bypass -File "$scriptFilename" -DomainUser %1 "@ $scriptDirectory = Split-Path -Parent $scriptFilename $batchDirectory = Split-Path -Parent $batchFilename if (-not (Test-Path $scriptDirectory)) { Write-Host "Script directory [$scriptDirectory] not found. Creating.." New-Item -Path $scriptDirectory -ItemType Directory } if (-not (Test-Path $batchDirectory)) { Write-Host "Batch directory [$batchDirectory] not found. Creating.." New-Item -Path $batchDirectory -ItemType Directory } # Split the $monitoredExtensions array into fileGroups of less than 4kb to allow processing by filescrn.exe $fileGroups = New-CBArraySplit $monitoredExtensions ForEach ($group in $fileGroups) { $group | Add-Member -MemberType NoteProperty -Name fileGroupName -Value "$FileGroupName$($group.index)" } # Perform these steps for each of the 4KB limit split fileGroups ForEach ($group in $fileGroups) { Write-Host "Adding/replacing File Group [$($group.fileGroupName)] with monitored file [$($group.array -Join ",")].." &filescrn.exe filegroup Delete "/Filegroup:$($group.fileGroupName)" /Quiet &filescrn.exe Filegroup Add "/Filegroup:$($group.fileGroupName)" "/Members:$($group.array -Join '|')" &filescrn.exe Filegroup Modify "/Filegroup:$($group.fileGroupName)" "/Nonmembers:$($exclusions -Join "|")" } # FSRM stipulates that the command directories/files can only be accessible by SYSTEM or Administrators # As a result, we lock down permissions for SYSTEM and local admin only Write-Host "Purging Non-Admin NTFS permissions on script directory [$scriptDirectory].." PurgeNonAdminDirectoryPermissions($scriptDirectory) Write-Host "Purging Non-Admin NTFS permissions on batch directory [$batchDirectory].." PurgeNonAdminDirectoryPermissions($batchDirectory) Write-Host "Writing defensive PowerShell script to location [$scriptFilename].." $scriptConf | Out-File -Encoding ASCII $scriptFilename Write-Host "Writing batch script launcher to location [$batchFilename].." $batchConf | Out-File -Encoding ASCII $batchFilename $eventConf = @" Notification=E RunLimitInterval=0 EventType=Warning Message=User [Source Io Owner] attempted to save [Source File Path] to [File Screen Path] on the [Server] server. This file is in the [Violated File Group] file group, which is not permitted on the server. An attempt has been made at blocking this user. "@ $cmdConf = @" Notification=C RunLimitInterval=0 Command=$batchFilename Arguments=[Source Io Owner] MonitorCommand=Enable Account=LocalSystem "@ Write-Host "Writing temporary FSRM Event Viewer configuration to location [$eventConfFilename].." $eventConf | Out-File $eventConfFilename Write-Host "Writing temporary FSRM Command configuration to location [$cmdConfFilename].." $cmdConf | Out-File $cmdConfFilename Write-Host "Adding/replacing File Screen Template [$fileTemplateName] with Event Notification [$eventConfFilename] and Command Notification [$cmdConfFilename].." &filescrn.exe Template Delete /Template:$fileTemplateName /Quiet # Build the argument list with all required fileGroups $screenArgs = 'Template','Add',"/Template:$fileTemplateName","/Type:Passive","/Add-Notification:E,$eventConfFilename","/Add-Notification:C,$cmdConfFilename" ForEach ($group in $fileGroups) { $screenArgs += "/Add-Filegroup:$($group.fileGroupName)" } &filescrn.exe $screenArgs Write-Host "Adding/replacing File Screens.." $drivesContainingShares | % { Write-Host "`tAdding/replacing File Screen for [$_] with Source Template [$fileTemplateName].." &filescrn.exe Screen Delete "/Path:$_" /Quiet &filescrn.exe Screen Add "/Path:$_" "/SourceTemplate:$fileTemplateName" "/Add-Notification:m,C:\Apps\Blocker\conf.ini" } #####WORKING##### Write-Host "Adding/replacing File Screen Exceptions..." $excludedPaths | % { &filescrn.exe Exception Delete /Path:"$_" /Quiet &filescrn.exe Exception Add /Path:"$_" "/Add-Filegroup:CryptoBlockerGroup1" "/Add-Filegroup:CryptoBlockerGroup2" "/Add-Filegroup:CryptoBlockerGroup3" } #####WORKING##### Write-Host "Removing temporary FSRM Event Viewer configuration file [$eventConfFilename].." Write-Host "Removing temporary FSRM Event Viewer configuration file [$cmdConfFilename].." Remove-Item $eventConfFilename Remove-Item $cmdConfFilename AddSMTP