forked from m-dwyer/CryptoBlocker
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathDeployCryptoBlocker.ps1
284 lines (232 loc) · 10.4 KB
/
DeployCryptoBlocker.ps1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# DeployCryptoBlocker.ps1
#
# This script performs the following actions:
# 1) Checks for network shares
# 2) Install File Server Resource Manager (FSRM) if missing
# 3) Creates Batch and PowerShell scripts used by FSRM
# 4) Creates a File Group within FSRM containing malicious extensions to screen on
# 5) Creates a File Screen Template utilising this File Group, with an Event notification and Command notification
# to run the scripts created in Step 3)
# 6) Creates File Screens utilising this template for each drive containing network shares
################################ 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
}
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 ################################
# 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 needing to be protected: $($drivesContainingShares -Join ",")"
$majorVer = [System.Environment]::OSVersion.Version.Major
$minorVer = [System.Environment]::OSVersion.Version.Minor
Write-Host "Checking 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 "Other version of Windows detected! 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 })
# 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)"
}
$scriptFilename = "C:\FSRMScripts\KillUserSession.ps1"
$batchFilename = "C:\FSRMScripts\KillUserSession.bat"
$eventConfFilename = "$env:Temp\cryptoblocker-eventnotify.txt"
$cmdConfFilename = "$env:Temp\cryptoblocker-cmdnotify.txt"
$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
}
# 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
# 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 '|')"
}
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"
ForEach ($group in $fileGroups) {
$screenArgs += "/Add-Filegroup:$($group.fileGroupName)"
}
$screenArgs += "/Add-Notification:E,$eventConfFilename","/Add-Notification:C,$cmdConfFilename",'/Type:Passive'
&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"
}
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