Cryptovirus Prevention Script

This topic contains 1 reply, has 2 voices, and was last updated by Profile photo of Don Jones Don Jones 3 months, 2 weeks ago.

  • Author
    Posts
  • #63168
    Profile photo of Lee
    Lee
    Participant

    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
    
  • #63493
    Profile photo of Don Jones
    Don Jones
    Keymaster

    That's a butt-tonne of code. Can you help narrow down where the problem is, what you're doing that isn't working, and what you'd like it to do instead?

You must be logged in to reply to this topic.