forked from TRI0N/ip-security
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Import-Firewall-Blocklist.ps1
199 lines (176 loc) · 9.68 KB
/
Import-Firewall-Blocklist.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
####################################################################################
#.Synopsis
# Block IP addresses associated with countries listed in a text file using the
# Windows Firewall.
#
#.Description
# Script will create inbound and outbound rules in the Windows Firewall to
# block all the IPv4 and/or IPv6 addresses listed in an input text file. IP
# address ranges can be defined with CIDR notation (10.4.0.0/16) or with a
# dash (10.4.0.0-10.4.255.255). Comments and blank lines are ignored in the
# input file. The script deletes and recreates the rules each time the
# script is run, so don't edit the rules by hand. Requires admin privileges.
# Multiple rules will be created if the input list is large. Requires
# Windows Vista, Windows 7, Server 2008 or later operating system. Blocking
# more than 5000 IP address ranges does delay initial connections, will slow
# the loading of the Windows Firewall snap-in, and will lengthen the time
# to disable/enable a network interface. This script is just a wrapper for
# the netsh.exe tool. You can block individual IP addresses too, you do not
# need to use CIDR notation for this (10.1.1.1/32), though this does work.
#
#.Parameter ZonesFile
# File containing ISO 3166-1 alpha-2 country codes to lookup IP address info;
# By default, the script will look for and use a file named 'countrycodes.txt'.
#
#.Parameter RuleName
# (Optional) Override default firewall rule name; default based on file name.
# When used with -DeleteOnly, just give the rule basename without the "-#1".
#
#.Parameter ProfileType
# (Optional) Comma-delimited list of network profile types for which the
# blocking rules will apply: public, private, domain, any (default = any).
#
#.Parameter InterfaceType
# (Optional) Comma-delimited list of interface types for which the
# blocking rules will apply: wireless, ras, lan, any (default = any).
#
#.Parameter DeleteOnly
# (Switch) Matching firewall rules will be deleted, none will be created.
# When used with -RuleName, leave off the "-#1" at the end of the rulename.
#
#.Parameter KeypressProtectionOff
# (Switch) If keypress protection is turned off, then the script will not
# enforce pressing a key at the end, be very careful when using this!
#
#.Example
# import-firewall-blocklist.ps1 -ZonesFile IpToBlock.txt
#
#.Example
# import-firewall-blocklist.ps1 -ZonesFile iptoblock.txt -profiletype public
#
#.Example
# import-firewall-blocklist.ps1 -ZonesFile iptoblock.txt -interfacetype wireless
#
#.Example
# import-firewall-blocklist.ps1 -ZonesFile IpToBlock.txt -deleteonly
#
#.Example
# import-firewall-blocklist.ps1 -rulename IpToBlock -deleteonly
#
#Requires -Version 1.0
#
#.Notes
# Author: Jason Fossen (http://www.sans.org/windows-security/)
# Version: 1.2
# Updated: 20.Mar.2012
#
# Author: Brandon Buchanan (willjasen)
# Updated: 7/25/2019
#
# LEGAL: PUBLIC DOMAIN. SCRIPT PROVIDED "AS IS" WITH NO WARRANTIES OR GUARANTEES OF
# ANY KIND, INCLUDING BUT NOT LIMITED TO MERCHANTABILITY AND/OR FITNESS FOR
# A PARTICULAR PURPOSE. ALL RISKS OF DAMAGE REMAINS WITH THE USER, EVEN IF
# THE AUTHOR, SUPPLIER OR DISTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF
# ANY SUCH DAMAGE. IF YOUR STATE DOES NOT PERMIT THE COMPLETE LIMITATION OF
# LIABILITY, THEN DELETE THIS FILE SINCE YOU ARE NOW PROHIBITED TO HAVE IT.
####################################################################################
# Parameters
param ($ZonesFile = "countrycodes.txt", $RuleNameParam, $ProfileTypeParam = "any", $InterfaceTypeParam = "any", [Switch] $DeleteOnlyParam, [Switch] $KeypressProtectionOffParam)
# Functions
Function ProcessZones {
Param($RuleName,$ProfileType,$InterfaceType,$DeleteOnly)
# Process the zone files
$zonefiles = Get-ChildItem "zones\." -Filter *.zone
ForEach($file in $zonefiles) {
$zfile = $file.FullName
if (-not $? -and -not $DeleteOnly) { "`nCannot find $ZonesFile, quitting...`n" ; exit }
$rulename = ($file.basename) # The '-#1' will be appended later.
# Description will be seen in the properties of the firewall rules.
$description = "Rule created by script on $(get-date). Do not edit rule by hand, it will be overwritten when the script is run again. By default, the name of the rule is named after the input file."
# Any existing firewall rules which match the name are deleted every time the script runs.
"`nDeleting any inbound or outbound firewall rules named like '$rulename-#*'`n"
$currentrules = netsh.exe advfirewall firewall show rule name=all | select-string '^[Rule Name|Regelname]+:\s+(.+$)' | foreach { $_.matches[0].groups[1].value }
if ($currentrules.count -lt 3) {"`nProblem getting a list of current firewall rules, quitting...`n" ; exit }
# Note: If you are getting the above error, try editing the regex pattern two lines above to include the 'Rule Name' in your local language.
$currentrules | foreach { if ($_ -like "$rulename-#*"){ netsh.exe advfirewall firewall delete rule name="$_" | out-null } }
# Don't create the firewall rules again if the -DeleteOnly switch was used.
if ($deleteonly -and $rulename) { "`nReminder: when deleting by name, leave off the '-#1' at the end of the rulename.`n" }
if ($deleteonly) { continue }
# Create array of IP ranges; any line that doesn't start like an IPv4/IPv6 address is ignored.
$ranges = get-content $zfile | where {($_.trim().length -ne 0) -and ($_ -match '^[0-9a-f]{1,4}[\.\:]')}
if (-not $?) { "`nCould not parse $zfile, quitting...`n" ; exit }
$linecount = $ranges.count
if ($linecount -eq 0) { "`nZero IP addresses to block, quitting...`n" ; exit }
# Now start creating rules with hundreds of IP address ranges per rule. Testing shows
# that netsh.exe errors begin to occur with more than 400 IPv4 ranges per rule, and
# this number might still be too large when using IPv6 or the Start-to-End format, so
# default to only 100 ranges per rule, but feel free to edit the following variable:
$MaxRangesPerRule = 100
$i = 1 # Rule number counter, when more than one rule must be created, e.g., BlockList-#001.
$start = 1 # For array slicing out of IP $ranges.
$end = $maxrangesperrule # For array slicing out of IP $ranges.
do {
$icount = $i.tostring().padleft(3,"0") # Used in name of rule, e.g., BlockList-#042.
# If there is only one line, then only apply only it
if($linecount -eq 1) {
$textranges = $ranges
}
# otherwise, apply a list
else {
if ($end -gt $linecount) { $end = $linecount }
$textranges = [System.String]::Join(",",$($ranges[$($start - 1)..$($end - 1)]))
}
"Creating an inbound firewall rule named '$rulename-#$icount' for IP ranges $start - $end"
netsh.exe advfirewall firewall add rule name="$rulename-#$icount" dir=in action=block localip=any remoteip="$textranges" description="$description" profile="$profiletype" interfacetype="$interfacetype"
if (-not $?) { "`nFailed to create '$rulename-#$icount' inbound rule for some reason, continuing anyway..."}
"Creating an outbound firewall rule named '$rulename-#$icount' for IP ranges $start - $end"
netsh.exe advfirewall firewall add rule name="$rulename-#$icount" dir=out action=block localip=any remoteip="$textranges" description="$description" profile="$profiletype" interfacetype="$interfacetype"
if (-not $?) { "`nFailed to create '$rulename-#$icount' outbound rule for some reason, continuing anyway..."}
$i++
$start += $maxrangesperrule
$end += $maxrangesperrule
} while ($start -le $linecount) #>
}
}
# Look for some help arguments, show help, then quit.
if ($ZonesFile -match '/[?h]') { "`nPlease run 'get-help .\import-firewall-blocklist.ps1 -full' for help on PowerShell 2.0 and later, or just read the script's header in a text editor.`n" ; exit }
# Get input file and set the name of the firewall rule.
$file = Get-Item $ZonesFile -ErrorAction SilentlyContinue # Sometimes rules will be deleted by name and there is no file.
$zones = Get-Content $file
$WebClient = New-Object System.Net.WebClient
# If the zones directory doesn't exist, create it
If(!(Test-Path "zones\")) {
New-Item "zones" -Type Directory
}
# Download and save each country zone file
ForEach($zone in $zones) {
$url = "http://www.ipdeny.com/ipblocks/data/countries/" + $zone.ToLower() + ".zone"
$zonefile = "zones\$zone.zone"
Invoke-WebRequest -Uri $url -OutFile $zonefile
}
# Process the zones
ProcessZones -RuleName $RuleNameParam -ProfileType $ProfileTypeParam -InterfaceType $InterfaceTypeParam -DeleteOnly $DeleteOnlyParam
If(!$KeypressProtectionOffParam) {
# Wait for a key press so we know connection has not been lost, otherwise roll back changes
$secondsRunning = 0;
$timeLimit = 15;
Write-Output "Press any key to verify that connection has not been lost..."
while($secondsRunning -lt $timeLimit) {
if ($host.UI.RawUI.KeyAvailable) {
Exit
}
Write-Host ("Waiting for " + ($timeLimit-$secondsRunning) + " seconds")
Start-Sleep -Seconds 1
$secondsRunning++
}
# A key wasn't pressed, so roll back!
Write-Host "A key wasn't pressed, rolling back changes."
ProcessZones -RuleName $RuleNameParam -ProfileType $ProfileTypeParam -InterfaceType $InterfaceTypeParam -DeleteOnly $True
}
# END-O-SCRIPT
# Incidentally, testing shows a delay of 2-5 seconds sometimes for the initial
# connection when there are more than 5000 IP address ranges total in the various
# outbound rules (once established, there is no delay). However, it does not seem
# consistent. Also, at 5000+ subnets in one's rules, it delays the opening of the
# Windows Firewall snap-in, and at 9000+ subnets it sometimes prevents the WF snap-in
# from opening successfully at all. However, this behavior is not consistent either.