Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/EvanAnderson/ts_block.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Anderson <EAnderson@wellbury.com>2011-11-30 00:34:56 +0400
committerEvan Anderson <EAnderson@wellbury.com>2011-11-30 00:34:56 +0400
commit09d62b6275143e63c7506de84c2c58b436662bd9 (patch)
tree40a2399bd31d6f878875f3674264ec30ad15ab72
parentb1ceb7cad4aa8221214a5f287d4d2cd235fc4123 (diff)
First code checkin20110831
-rw-r--r--LICENSE198
-rw-r--r--ts_block.adm42
-rw-r--r--ts_block.vbs357
3 files changed, 597 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7332f58
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,198 @@
+Artistic License 2.0
+
+Copyright (c) 2000-2006, The Perl Foundation.
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Preamble
+********
+
+This license establishes the terms under which a given free software
+Package may be copied, modified, distributed, and/or redistributed. The
+intent is that the Copyright Holder maintains some artistic control over
+the development of that Package while still keeping the Package
+available as open source and free software.
+
+You are always permitted to make arrangements wholly outside of this
+license directly with the Copyright Holder of a given Package. If the
+terms of this license do not permit the full use that you propose to
+make of the Package, you should contact the Copyright Holder and seek a
+different licensing arrangement.
+
+Definitions
+***********
+
+"Copyright Holder" means the individual(s) or organization(s) named in
+the copyright notice for the entire Package.
+
+"Contributor" means any party that has contributed code or other
+material to the Package, in accordance with the Copyright Holder's
+procedures.
+
+"You" and "your" means any person who would like to copy, distribute, or
+modify the Package.
+
+"Package" means the collection of files distributed by the Copyright
+Holder, and derivatives of that collection and/or of those files. A
+given Package may consist of either the Standard Version, or a Modified
+Version.
+
+"Distribute" means providing a copy of the Package or making it
+accessible to anyone else, or in the case of a company or organization,
+to others outside of your company or organization.
+
+"Distributor Fee" means any fee that you charge for Distributing this
+Package or providing support for this Package to another party. It does
+not mean licensing fees.
+
+"Standard Version" refers to the Package if it has not been modified, or
+has been modified only in ways explicitly requested by the Copyright
+Holder.
+
+"Modified Version" means the Package, if it has been changed, and such
+changes were not explicitly requested by the Copyright Holder.
+
+"Original License" means this Artistic License as Distributed with the
+Standard Version of the Package, in its current version or as it may be
+modified by The Perl Foundation in the future.
+
+"Source" form means the source code, documentation source, and
+configuration files for the Package.
+
+"Compiled" form means the compiled bytecode, object code, binary, or any
+other form resulting from mechanical transformation or translation of
+the Source form.
+
+Permission for Use and Modification Without Distribution
+********************************************************
+
+(1) You are permitted to use the Standard Version and create and use
+Modified Versions for any purpose without restriction, provided that you
+do not Distribute the Modified Version.
+
+Permissions for Redistribution of the Standard Version
+******************************************************
+
+(2) You may Distribute verbatim copies of the Source form of the
+Standard Version of this Package in any medium without restriction,
+either gratis or for a Distributor Fee, provided that you duplicate all
+of the original copyright notices and associated disclaimers. At your
+discretion, such verbatim copies may or may not include a Compiled form
+of the Package.
+
+(3) You may apply any bug fixes, portability changes, and other
+modifications made available from the Copyright Holder. The resulting
+Package will still be considered the Standard Version, and as such will
+be subject to the Original License.
+
+Distribution of Modified Versions of the Package as Source
+**********************************************************
+
+(4) You may Distribute your Modified Version as Source (either gratis or
+for a Distributor Fee, and with or without a Compiled form of the
+Modified Version) provided that you clearly document how it differs from
+the Standard Version, including, but not limited to, documenting any
+non-standard features, executables, or modules, and provided that you do
+at least ONE of the following:
+
+(a) make the Modified Version available to the Copyright Holder of the
+Standard Version, under the Original License, so that the Copyright
+Holder may include your modifications in the Standard Version.
+
+(b) ensure that installation of your Modified Version does not prevent
+the user installing or running the Standard Version. In addition, the
+Modified Version must bear a name that is different from the name of the
+Standard Version.
+
+(c) allow anyone who receives a copy of the Modified Version to make the
+Source form of the Modified Version available to others under
+
+(i) the Original License or
+
+(ii) a license that permits the licensee to freely copy, modify and
+redistribute the Modified Version using the same licensing terms that
+apply to the copy that the licensee received, and requires that the
+Source form of the Modified Version, and of any works derived from it,
+be made freely available in that license fees are prohibited but
+Distributor Fees are allowed.
+
+Distribution of Compiled Forms of the Standard Version or Modified
+******************************************************************
+Versions without the Source
+***************************
+
+(5) You may Distribute Compiled forms of the Standard Version without
+the Source, provided that you include complete instructions on how to
+get the Source of the Standard Version. Such instructions must be valid
+at the time of your distribution. If these instructions, at any time
+while you are carrying out such distribution, become invalid, you must
+provide new instructions on demand or cease further distribution. If
+you provide valid instructions or cease distribution within thirty days
+after you become aware that the instructions are invalid, then you do
+not forfeit any of your rights under this license.
+
+(6) You may Distribute a Modified Version in Compiled form without the
+Source, provided that you comply with Section 4 with respect to the
+Source of the Modified Version.
+
+Aggregating or Linking the Package
+**********************************
+
+(7) You may aggregate the Package (either the Standard Version or
+Modified Version) with other packages and Distribute the resulting
+aggregation provided that you do not charge a licensing fee for the
+Package. Distributor Fees are permitted, and licensing fees for other
+components in the aggregation are permitted. The terms of this license
+apply to the use and Distribution of the Standard or Modified Versions
+as included in the aggregation.
+
+(8) You are permitted to link Modified and Standard Versions with other
+works, to embed the Package in a larger work of your own, or to build
+stand-alone binary or bytecode versions of applications that include the
+Package, and Distribute the result without restriction, provided the
+result does not expose a direct interface to the Package.
+
+Items That are Not Considered Part of a Modified Version
+********************************************************
+
+(9) Works (including, but not limited to, modules and scripts) that
+merely extend or make use of the Package, do not, by themselves, cause
+the Package to be a Modified Version. In addition, such works are not
+considered parts of the Package itself, and are not subject to the terms
+of this license.
+
+General Provisions
+******************
+
+(10) Any use, modification, and distribution of the Standard or Modified
+Versions is governed by this Artistic License. By using, modifying or
+distributing the Package, you accept this license. Do not use, modify,
+or distribute the Package, if you do not accept this license.
+
+(11) If your Modified Version has been derived from a Modified Version
+made by someone other than you, you are nevertheless required to ensure
+that your Modified Version complies with the requirements of this
+license.
+
+(12) This license does not grant you the right to use any trademark,
+service mark, tradename, or logo of the Copyright Holder.
+
+(13) This license includes the non-exclusive, worldwide, free-of-charge
+patent license to make, have made, use, offer to sell, sell, import and
+otherwise transfer the Package with respect to any patent claims
+licensable by the Copyright Holder that are necessarily infringed by the
+Package. If you institute patent litigation (including a cross-claim or
+counterclaim) against any party alleging that the Package constitutes
+direct or contributory patent infringement, then this Artistic License
+to you shall terminate on the date that such litigation is filed.
+
+(14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT
+HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT
+PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT
+HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE
+OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ts_block.adm b/ts_block.adm
new file mode 100644
index 0000000..eb582f9
--- /dev/null
+++ b/ts_block.adm
@@ -0,0 +1,42 @@
+CLASS MACHINE
+
+CATEGORY "Wellbury LLC"
+ CATEGORY "ts_block"
+ KEYNAME "Software\Policies\Wellbury LLC\ts_block"
+
+ POLICY "Block attempts"
+ PART "Block attempts threshold" NUMERIC REQUIRED SPIN 1
+ VALUENAME "BlockAttempts"
+ DEFAULT 5
+ MIN 2
+ END PART ; "Block attempts threshold"
+ EXPLAIN "The number of sequential failed logon attempts (with accounts that are not considered 'block immediately' accounts) that will trigger a block."
+ END POLICY
+
+ POLICY "Block duration"
+ PART "Block duration (seconds)" NUMERIC REQUIRED SPIN 1
+ VALUENAME "BlockDuration"
+ DEFAULT 300
+ MIN 1
+ END PART ; "Block duration"
+ EXPLAIN "The duration, in seconds, of a block (either because of reaching the BlockAttempts threshhold or because of a 'block immediately')."
+ END POLICY
+
+ POLICY "Block timeout"
+ PART "Block timeout (seconds)" NUMERIC REQUIRED SPIN 1
+ VALUENAME "BlockTimeout"
+ DEFAULT 120
+ MIN 1
+ END PART ; "Block timeout"
+ EXPLAIN "The duration, in seconds, that must elapse between failed logon attempts to reset the count of failed logon attempts for a given IP address."
+ END POLICY
+
+ POLICY "Black-hole IP address"
+ PART "Black-hole IP address" EDITTEXT REQUIRED
+ VALUENAME "BlackholeIP"
+ END PART ; "Block timeout"
+ EXPLAIN "The IP address used for the black-hole route (for Windows Server 2003). If not specified the default algorithm of selecting the IP address of a network interface with no default gateway specified will be used. This setting is not used in Windows Server 2008 and later versions of Windows."
+ END POLICY
+
+ END CATEGORY ; "ts_block"
+END CATEGORY ; "Wellbury LLC"
diff --git a/ts_block.vbs b/ts_block.vbs
new file mode 100644
index 0000000..2a772ba
--- /dev/null
+++ b/ts_block.vbs
@@ -0,0 +1,357 @@
+Option Explicit
+
+' ts_block.vbs - Blocks IP addresses generating invalid Terminal Services logons.
+' Copyright 2011 Wellbury LLC - See LICENSE for license information
+'
+' Release 20110831 - Adapted from sshd_block release 20100120
+
+' External executables required to be accessible from PATH:
+'
+' ROUTE.EXE For black-hole routing blocked IP addresses in Windows 2003
+' NETSH.EXE For black-hole firewall rule creation on Windows Vista / 2008 / 7 / 2008 R2
+' EVENTCREATE.EXE For writing to the event log (if enabled)
+'
+' For support, please contact Evan Anderson at Wellbury LLC:
+' EAnderson@wellbury.com, (866) 569-9799, ext 801
+
+' Main
+Dim objShell, objWMIService, objEventSink, blackHoleIPAddress, regexpSanitizeEventLog, regexpSanitizeIP
+Dim dictIPLastSeenTime, dictIPBadLogons, dictUnblockTime, dictBlockImmediatelyUsers
+Dim colOperatingSystem, intOSBuild, intBlackholeStyle
+Dim intBlockDuration, intBlockAttempts, intBlockTimeout
+
+' =====================( Configuration )=====================
+
+' Set to 0 to disable debugging output
+Const DEBUGGING = 0
+
+' Set to 0 to disable event log reporting of blocks / unblocks
+Const USE_EVENTLOG = 1
+Const EVENTLOG_SOURCE = "ts_block"
+Const EVENTLOG_TYPE_INFORMATION = "INFORMATION"
+Const EVENTLOG_TYPE_ERROR = "ERROR"
+Const EVENTLOG_ID_STARTED = 1
+Const EVENTLOG_ID_ERROR_NO_BLACKHOLE_IP = 2
+Const EVENTLOG_ID_ERROR_WIN_XP = 3
+Const EVENTLOG_ID_BLOCK = 256
+Const EVENTLOG_ID_UNBLOCK = 257
+
+' Registry path for configuration
+Const REG_CONFIG_PATH = "HKLM\Software\Policies\Wellbury LLC\ts_block\"
+
+' Number of failed logons in time window before IP will be blocked
+Const DEFAULT_BLOCK_ATTEMPTS = 5 ' Attempts
+Const REG_BLOCK_ATTEMPTS = "BlockAttempts"
+
+' Expiration (in seconds) for IPs to be blocked
+Const DEFAULT_BLOCK_DURATION = 300
+Const REG_BLOCK_DURATION = "BlockDuration"
+
+' Timeout for attempts before a new attempt is considered attempt #1
+Const DEFAULT_BLOCK_TIMEOUT = 120 ' in X seconds
+Const REG_BLOCK_TIMEOUT = "BlockTimeout"
+
+' Black hole IP address (if hard-specified)
+Const REG_BLACKHOLE_IP = "BlackholeIP"
+
+' Usernames that attempted logons for result in immediate blocking
+Set dictBlockImmediatelyUsers = CreateObject("Scripting.Dictionary")
+dictBlockImmediatelyUsers.Add "administrator", 1
+dictBlockImmediatelyUsers.Add "root", 1
+dictBlockImmediatelyUsers.Add "guest", 1
+
+' ===================( End Configuration )===================
+
+Const TS_BLOCK_VERSION = "20110831"
+Const BLACKHOLE_ROUTE = 1 ' Blackhole packets via routing table
+Const BLACKHOLE_FIREWALL = 2 ' Blackhole packets via firewall
+
+' =====================( Stress Testing )====================
+
+' Set to 1 to perform stress testing
+Const TESTING = 0
+
+' Number of "bogus" blocks to load
+Const TESTING_IP_ADDRESSES = 10000
+
+' Minimum and maximum milliseconds between adding "bogus" IPs to the block list during testing
+Const TESTING_IP_MIN_LATENCY = 10
+Const TESTING_IP_MAX_LATENCY = 50
+
+If TESTING Then
+ Dim testLatency, cumulativeLatency, testLoop, maxBlocked, blockedAddresses
+ Randomize
+End If
+
+' ===================( End Stress Testing )==================
+
+Set dictIPLastSeenTime = CreateObject("Scripting.Dictionary")
+Set dictIPBadLogons = CreateObject("Scripting.Dictionary")
+Set dictUnblockTime = CreateObject("Scripting.Dictionary")
+Set objShell = CreateObject("WScript.Shell")
+
+Set regexpSanitizeEventLog = new Regexp
+regexpSanitizeEventLog.Global = True
+regexpSanitizeEventLog.Pattern = "[^0-9a-zA-Z._ /:\-]"
+
+Set regexpSanitizeIP = new Regexp
+regexpSanitizeIP.Global = True
+regexpSanitizeIP.Pattern = "[^0-9.]"
+
+' Get OS build number
+Set objWMIService = GetObject("winmgmts:{(security)}!root/cimv2")
+Set colOperatingSystem = objWMIService.ExecQuery("SELECT BuildNumber FROM Win32_OperatingSystem")
+
+For Each intOSBuild in colOperatingSystem
+ ' Windows OS versions with the "Advanced Firewall" functionality have build numbers greater than 4000
+ If intOSBuild.BuildNumber < 4000 Then intBlackholeStyle = BLACKHOLE_ROUTE Else intBlackholeStyle = BLACKHOLE_FIREWALL
+
+ If intOSBuild.BuildNumber = 2600 Then
+ LogEvent EVENTLOG_ID_ERROR_WIN_XP, EVENTLOG_TYPE_ERROR, "Fatal Error - Windows XP does not provide an IP address to black-hole in failure audit event log entries."
+ WScript.Quit EVENTLOG_ID_ERROR_WIN_XP
+ End If
+
+ If DEBUGGING Then WScript.Echo "intBlackHoleStyle = " & intBlackHoleStyle
+Next ' intOSBuild
+
+' Read configuration from the registry, if present, in a really simplsitic way
+On Error Resume Next ' Noooo!!!
+intBlockDuration = DEFAULT_BLOCK_DURATION
+If CInt(objShell.RegRead(REG_CONFIG_PATH & REG_BLOCK_DURATION)) > 0 Then intBlockDuration = CInt(objShell.RegRead(REG_CONFIG_PATH & REG_BLOCK_DURATION))
+
+intBlockAttempts = DEFAULT_BLOCK_ATTEMPTS
+If CInt(objShell.RegRead(REG_CONFIG_PATH & REG_BLOCK_ATTEMPTS)) > 0 Then intBlockAttempts = CInt(objShell.RegRead(REG_CONFIG_PATH & REG_BLOCK_ATTEMPTS))
+
+intBlockTimeout = DEFAULT_BLOCK_TIMEOUT
+If CInt(objShell.RegRead(REG_CONFIG_PATH & REG_BLOCK_TIMEOUT)) > 0 Then intBlockTimeout = CInt(objShell.RegRead(REG_CONFIG_PATH & REG_BLOCK_TIMEOUT))
+
+If objShell.RegRead(REG_CONFIG_PATH & REG_BLACKHOLE_IP) <> "" Then
+ blackHoleIPAddress = regexpSanitizeIP.Replace(objShell.RegRead(REG_CONFIG_PATH & REG_BLACKHOLE_IP), "")
+Else
+ blackHoleIPAddress = ""
+End If
+
+On Error Goto 0
+
+' Only obtain a blackhole adapter address on versions of Windows where it is required
+If (intBlackholeStyle = BLACKHOLE_ROUTE) and (blackHoleIPAddress = "") Then
+ blackHoleIPAddress = GetBlackholeIP()
+ If IsNull(blackHoleIPAddress) Then
+ LogEvent EVENTLOG_ID_ERROR_NO_BLACKHOLE_IP, EVENTLOG_TYPE_ERROR, "Fatal Error - Could not obtain an IP address for an interface with no default gateway specified."
+ WScript.Quit EVENTLOG_ID_ERROR_NO_BLACKHOLE_IP
+ End If
+End If
+
+If DEBUGGING Then LogEvent EVENTLOG_ID_STARTED, EVENTLOG_TYPE_INFORMATION, "Block Duration: " & intBlockDuration
+If DEBUGGING Then LogEvent EVENTLOG_ID_STARTED, EVENTLOG_TYPE_INFORMATION, "Block Attempts: " & intBlockAttempts
+If DEBUGGING Then LogEvent EVENTLOG_ID_STARTED, EVENTLOG_TYPE_INFORMATION, "Block Timeout: " & intBlockTimeout
+If DEBUGGING Then LogEvent EVENTLOG_ID_STARTED, EVENTLOG_TYPE_INFORMATION, "Blackhole IP: " & blackHoleIPAddress
+
+' Create event sink to catch security events
+Set objEventSink = WScript.CreateObject("WbemScripting.SWbemSink", "eventSink_")
+objWMIService.ExecNotificationQueryAsync objEventSink, "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA 'Win32_NTLogEvent' AND TargetInstance.Logfile = 'Security' AND TargetInstance.EventType = 5 AND (TargetInstance.EventIdentifier = 529 OR TargetInstance.EventIdentifier = 4625) AND (TargetInstance.SourceName = 'Security' OR TargetInstance.SourceName = 'Microsoft-Windows-Security-Auditing')"
+
+LogEvent EVENTLOG_ID_STARTED, EVENTLOG_TYPE_INFORMATION, EVENTLOG_SOURCE & " (version " & TS_BLOCK_VERSION & ") started."
+
+If TESTING Then
+ If DEBUGGING Then WScript.Echo "Stress test loop"
+
+ For testLoop = 1 to TESTING_IP_ADDRESSES
+ testLatency = Int(Rnd() * (TESTING_IP_MAX_LATENCY - TESTING_IP_MIN_LATENCY)) + TESTING_IP_MIN_LATENCY
+
+ WScript.Sleep(testLatency)
+ Block(CStr(Int(Rnd * 256)) & "." & CStr(Int(Rnd * 256)) & "." & CStr(Int(Rnd * 256)) & "." & CStr(Int(Rnd * 256)))
+ blockedAddresses = blockedAddresses + 1
+
+ ' Try to ExpireBlocks no more often than once every 1000ms
+ cumulativeLatency = cumulativeLatency + testLatency
+ If cumulativeLatency >= 250 Then
+ if blockedAddresses > maxBlocked Then maxBlocked = blockedAddresses
+ cumulativeLatency = 0
+ ExpireBlocks
+ End If
+ Next ' testLoop
+
+ ' Drain the queue
+ While dictUnblockTime.Count > 0
+ WScript.Sleep(250)
+ ExpireBlocks
+ Wend
+
+ WScript.Echo "Stress test completed. " & TESTING_IP_ADDRESSES & " tested with a maximum of " & maxBlocked & " addresses blocked at once."
+
+ ' Loop until killed
+ While (True)
+ WScript.Sleep(250)
+ Wend
+
+Else
+
+ If DEBUGGING Then WScript.Echo "Entering normal operation busy-wait loop."
+
+ ' Loop sleeping for 250ms, expiring blocks
+ While (True)
+ WScript.Sleep(250)
+ ExpireBlocks
+ Wend
+
+End If
+
+
+Sub Block(IP)
+ ' Block an IP address and set the time for the block expiration
+ Dim strRunCommand
+ Dim intRemoveBlockTime
+
+ ' Block an IP address (either by black-hole routing it or adding a firewall rule)
+ If (TESTING <> 1) Then
+ If intBlackholeStyle = BLACKHOLE_ROUTE Then strRunCommand = "route add " & IP & " mask 255.255.255.255 " & blackHoleIPAddress
+ If intBlackholeStyle = BLACKHOLE_FIREWALL Then strRunCommand = "netsh advfirewall firewall add rule name=""Blackhole " & IP & """ dir=in protocol=any action=block remoteip=" & IP
+
+ If DEBUGGING Then WScript.Echo "Executing " & strRunCommand
+ objShell.Run strRunCommand
+ End If
+
+ ' Calculate time to remove block and add to dictUnblockTime
+ intRemoveBlockTime = (Date + Time) + (intBlockDuration / (24 * 60 * 60))
+
+ If NOT dictUnblockTime.Exists(intRemoveBlockTime) Then
+ Set dictUnblockTime.Item(intRemoveBlockTime) = CreateObject("Scripting.Dictionary")
+ End If
+ If NOT dictUnblockTime.Item(intRemoveBlockTime).Exists(IP) Then dictUnblockTime.Item(intRemoveBlockTime).Add IP, 1
+
+ LogEvent EVENTLOG_ID_BLOCK, EVENTLOG_TYPE_INFORMATION, "Blocked " & IP & " until " & intRemoveBlockTime
+End Sub
+
+Sub Unblock(IP)
+ ' Unblock an IP address
+ Dim strRunCommand
+
+ If (TESTING <> 1) Then
+ If intBlackholeStyle = BLACKHOLE_ROUTE Then strRunCommand = "route delete " & IP & " mask 255.255.255.255 " & blackHoleIPAddress
+ If intBlackholeStyle = BLACKHOLE_FIREWALL Then strRunCommand = "netsh advfirewall firewall delete rule name=""Blackhole " & IP & """"
+
+ If DEBUGGING Then WScript.Echo "Executing " & strRunCommand
+ objShell.Run strRunCommand
+ End If
+
+ LogEvent EVENTLOG_ID_UNBLOCK, EVENTLOG_TYPE_INFORMATION, "Unblocked " & IP
+End Sub
+
+Sub LogFailedLogonAttempt(IP)
+ ' Log failed logon attempts and, if necessary, block the IP address
+
+ ' Have we already seen this IP address before?
+ If dictIPLastSeenTime.Exists(IP) Then
+
+ ' Be sure that prior attempts, if they are older than intBlockTimeout, don't count it against the IP
+ If (dictIPLastSeenTime.Item(IP) + (intBlockTimeout / (24 * 60 * 60))) <= (Date + Time) Then
+ If dictIPBadLogons.Exists(IP) Then dictIPBadLogons.Remove(IP)
+ End If
+
+ dictIPLastSeenTime.Item(IP) = (Date + Time)
+ Else
+ dictIPLastSeenTime.Add IP, (Date + Time)
+ End If
+
+ ' Does this IP address already have a history of bad logons?
+ If dictIPBadLogons.Exists(IP) Then
+ dictIPBadLogons.Item(IP) = dictIPBadLogons.Item(IP) + 1
+ Else
+ dictIPBadLogons.Add IP, 1
+ End If
+
+ If DEBUGGING Then WScript.Echo "Logging bad attempt from " & IP & ", attempt # " & dictIPBadLogons.Item(IP)
+
+ ' Should we block this IP address?
+ If dictIPBadLogons.Item(IP) = intBlockAttempts Then Block(IP)
+End Sub
+
+Sub ExpireBlocks()
+ Dim unblockTime, ipAddress
+
+ For Each unblockTime in dictUnblockTime.Keys
+
+ If unblockTime <= (Date + Time) Then
+ For Each ipAddress in dictUnblockTime.Item(unblockTime)
+ Unblock(ipAddress)
+ If TESTING Then blockedAddresses = blockedAddresses - 1
+ Next ' ipAddress
+
+ dictUnblockTime.Remove unblockTime
+ End If
+ Next 'ipAddress
+End Sub
+
+' Should an invalid logon from specified user result in an immediate block?
+Function BlockImmediate(user)
+ Dim userToBlock
+
+ For Each userToBlock in dictBlockImmediatelyUsers.Keys
+ If UCase(user) = UCase(userToBlock) Then
+ BlockImmediate = True
+ Exit Function
+ End If
+ Next 'userToBlock
+
+ BlockImmediate = False
+End Function
+
+' Fires each time new security events are generated
+Sub eventSink_OnObjectReady(objEvent, objWbemAsyncContext)
+ Dim arrEventMessage, arrInvalidLogonText
+ Dim IP, user
+
+ ' Differentiate W2K3 and W2K8+
+ If objEvent.TargetInstance.SourceName = "Microsoft-Windows-Security-Auditing" Then
+ user = objEvent.TargetInstance.InsertionStrings(5)
+ IP = objEvent.TargetInstance.InsertionStrings(19)
+ Else
+ ' Assume W2K3
+ user = objEvent.TargetInstance.InsertionStrings(0)
+ IP = objEvent.TargetInstance.InsertionStrings(11)
+ End If
+
+ ' Make sure only characters allowed in IP addresses are passed to external commands
+ IP = regexpSanitizeIP.Replace(IP, "")
+
+ ' If the event didn't generate both a username and IP address then do nothing
+ If (IP <> "") AND (user <> "") Then
+ If BlockImmediate(user) Then Block(IP) Else LogFailedLogonAttempt(IP)
+ End If
+End Sub
+
+Function GetBlackholeIP()
+ ' Sift through the NICs on the machine to locate a NIC's IP to use to blackhole offending hosts.
+ ' Look for a NIC with no default gateway set and an IP address assigned. Return NULL if we can't
+ ' find one.
+
+ Dim objNICs, objNICConfig
+ Set objNICs = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = TRUE")
+
+ ' Scan for a NIC with no default gateway set and IP not 0.0.0.0
+ For Each objNICConfig in objNICs
+ If IsNull(objNICConfig.DefaultIPGateway) and (objNICConfig.IPAddress(0) <> "0.0.0.0") Then
+ If DEBUGGING Then WScript.Echo "Decided on black-hole IP address " & objNICConfig.IPAddress(0) & ", interface " & objNICConfig.Description
+ GetBlackholeIP = objNICConfig.IPAddress(0)
+ Exit Function
+ End If
+ Next
+
+ ' Couldn't find anything, return NULL to let caller know we failed
+ GetBlackHoleIP = NULL
+End Function
+
+Sub LogEvent(ID, EventType, Message)
+ ' Log an event to the Windows event log
+
+ ' Sanitize input string
+ Message = regexpSanitizeEventLog.Replace(Message, "")
+
+ If DEBUGGING Then WScript.Echo "Event Log - Event ID: " & ID & ", Type: " & EventType & " - " & Message
+
+ ' Don't hit the event log during testing
+ If TESTING Then Exit Sub
+
+ If USE_EVENTLOG Then objShell.Exec "EVENTCREATE /L APPLICATION /SO " & EVENTLOG_SOURCE & " /ID " & ID & " /T " & EventType & " /D """ & Message & """"
+End Sub