it-swarm.com.de

IP-Adresse basierend auf X Anzahl erfolgloser Anmeldeversuche verbieten?

Ist es möglich, eine IP-Adresse nach X erfolglosen Anmeldeversuchen bei einem Windows Server zu sperren? Nicht auf ein bestimmtes Konto, das ich zu tun weiß, sondern auf die gesamte Maschine.

Wir werden ziemlich hart von Brute-Force-Angriffen getroffen, die versuchen, Benutzernamen zu erraten. Dies würde also wirklich dazu beitragen, den Server etwas zu entlasten.

47
HeavyWave

Sie können dies mit Powershell und Task-Manager tun. Es ist wahrscheinlich keine perfekte Lösung, aber es funktioniert ganz gut und ich habe ungefähr 100 blockierte IP-Adressen in zwei Monaten. Ich habe ein Skript geschrieben, das aus von EventLog angegebenen Ereignissen auswählt ("Überwachungsfehler"). Wenn viele Anmeldungen von einer IP-Adresse fehlgeschlagen sind, wird sie der (manuell erstellten) Firewall-Regel "BlockAttackers" hinzugefügt, die den Datenverkehr zu bestimmten IP-Adressen blockiert.

PS1-Skript:

$DT = [DateTime]::Now.AddDays(-1) # check only last 24 hours

$l = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $DT | Select-Object @{n='IpAddress';e={$_.ReplacementStrings[-2]} } # select Ip addresses that has audit failure 
$g = $l | group-object -property IpAddress  | where {$_.Count -gt 20} | Select -property Name # get ip adresses, that have more than 20 wrong logins

$fw = New-Object -ComObject hnetcfg.fwpolicy2 # get firewall object

$ar = $fw.rules | where {$_.name -eq 'BlockAttackers'} # get firewall rule named 'BlockAttackers' (must be created manually)

$arRemote = $ar.RemoteAddresses -split(',') #split the existing IPs into an array so we can easily search for existing IPs

$w = $g | where {$_.Name.Length -gt 1 -and  !($arRemote -contains $_.Name + '/255.255.255.255') } # get ip addresses that are not already in firewal rule. Include the subnet mask which is automatically added to the firewall remote IP declaration.

$w| %{$ar.remoteaddresses += ',' + $_.Name} # add IPs to firewall rule

Erstellen Sie eine Aufgabe im Scheduler und setzen Sie den Trigger auf Ereignis 4625 (Windows-Anmeldung einschließlich Terminaldienste). Sie können den Trigger jedoch so einstellen, dass er z. zweimal pro Stunde, um unnötiges Laden des Servers zu vermeiden.

Scheduler trigger

und nach dem Auslösen Powershell-Skript ausführen. Sie müssen auch höhere Berechtigungen festlegen, um dieses Skript auszuführen. Andernfalls schlägt es mit Sicherheitsausnahmen fehl.

runing powershell script

Sie können dieses Skript auch an andere Sicherheitsereignisse binden.

28
remunda

Ich weiß, dass diese Frage alt ist, aber es war tatsächlich der erste Forumsbeitrag, über den ich gestolpert bin, als ich vor ein paar Wochen angefangen habe, genau dasselbe zu tun. Ich habe es geschafft, ein funktionierendes Skript zu entwickeln, das die Ereignisprotokolle 24 Stunden zurück auf nur fehlerhafte Anmeldeereignisprotokolleinträge analysiert, diejenigen mit mehr als 10 fehlerhaften Anmeldungen abruft und sie dann mithilfe von in eine IPSec-Filterliste einfügt netsh Befehl. Dann habe ich eine Batch-Datei mit dieser Zeile geschrieben powershell .\*scriptname.ps1* und erstellte eine geplante Aufgabe, um die Batchdatei alle 24 Stunden auszuführen (aus irgendeinem Grund wurde sie nicht direkt ausgeführt).

$DATE = [DateTime]::Now.AddDays(-1)

$EVS = Get-EventLog Security -InstanceId 529 -after $DATE

$EVS | select-string -inputobject {$_.message} -pattern "Source Network Address:(.)*\.*\.*\.*"  -allmatches | foreach-object {$_.Matches} | foreach-object {$_.Value} | foreach-object {$_.replace("Source Network Address:", "")} | group-object -property $_ | where-object {$_.count -gt 10} | select-object -property name | format-list | out-file c:\rdpblock.txt 

get-content -path c:\rdpblock.txt | foreach-object {$_.replace("Name :", "")} | out-file c:\rdpblockcleaned.txt 

get-content -path c:\rdpblockcleaned.txt | select-object -unique | out-file c:\rdpblocknospaces.txt

$RDPIP = get-content -path c:\rdpblocknospaces.txt | select-object -skip 1

$RDPIP | foreach-object {$_.replace("     ", "")} | foreach-object {netsh ipsec static add filter filterlist=RDP_BLOCK srcaddr=$($_) dstaddr=any}

Ich weiß, dass dieses Skript wahrscheinlich ineffizient ist, aber als ich anfing, daran zu arbeiten, hatte ich absolut keine Erfahrung mit Powershell, sodass meine Fähigkeit, Skripte zu optimieren, zu wünschen übrig lässt. Trotz dieser Tatsache dachte ich, ich würde dies mit jedem teilen, der es benutzen könnte.

Ich danke Remunda, dass sie mir die erste Idee gegeben hat. Dieses Poster hat mich auf die Idee gebracht, Powershell zum Durchsuchen der Ereignisprotokolle zu verwenden.

7
Keegan

Dieses Skript baut auf der Antwort von remunda auf und geht ein wenig weiter https://serverfault.com/a/397637/155102 Es berücksichtigt, dass für die "BlockAttackers" -Regel noch keine IPs eingegeben wurden (was ein "zurückgibt". * "als Zeichenfolge). Außerdem wird ein Kommentar in eine Protokolldatei geschrieben, um Sie darüber zu informieren, wann die IP zur Regel hinzugefügt wurde.

Ein guter Tipp ist, die "BlockAttackers" -Regel zu erstellen, die die IP-Adressen blockiert, ABER sie zuerst deaktiviert. Führen Sie dieses Skript dann einmal manuell aus, damit das Feld "RemoteAddresses" mit den tatsächlichen IP-Adressen gefüllt werden kann, die blockiert werden sollen. Sehen Sie sich diese IP-Adressen an, um sicherzustellen, dass nichts Kritisches hinzugefügt wurde, und aktivieren Sie dann die Firewall-Regel. Fügen Sie diese Regel Ihrer Firewall wie beschrieben hinzu.

Der Git für dieses Skript

#Checks for IP addresses that used incorrect password more than 10 times
#within 24 hours and blocks them using a firewall rule 'BlockAttackers'

#Check only last 24 hours
$DT = [DateTime]::Now.AddHours(-24)

#Select Ip addresses that has audit failure
$l = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $DT | Select-Object @{n='IpAddress';e={$_.ReplacementStrings[-2]} }

#Get ip adresses, that have more than 10 wrong logins
$g = $l | group-object -property IpAddress | where {$_.Count -gt 10} | Select -property Name

#Get firewall object
$fw = New-Object -ComObject hnetcfg.fwpolicy2

#Get firewall rule named 'BlockAttackers' (must be created manually)
$ar = $fw.rules | where {$_.name -eq 'BlockAttackers'}

#Split the existing IPs into an array so we can search it for existing IPs
$arRemote = $ar.RemoteAddresses -split(',')

#Only collect IPs that aren't already in the firewall rule
$w = $g | where {$_.Name.Length -gt 1 -and !($arRemote -contains $_.Name + '/255.255.255.255') }

#Add the new IPs to firewall rule
$w| %{
  if ($ar.RemoteAddresses -eq '*') {
    $ar.remoteaddresses = $_.Name
  }else{
    $ar.remoteaddresses += ',' + $_.Name
  }
}

#Write to logfile
if ($w.length -gt 1) {
  $w| %{(Get-Date).ToString() + ' ' + $_.Name >> '.\blocked.txt'}
}
4
Michael Khalili
3
becomingwisest

Es ist im Allgemeinen keine gute Idee, Ihre Firewall-Regeln von jemand anderem kontrollieren zu lassen. Das ist im Grunde das, wonach Sie hier fragen.

2
Thorsten

Dies ist ein alter Thread. Ich habe das von kevinmicke in den Jahren 2014-2015 bereitgestellte Skript verwendet. Dann hörte es einfach auf zu arbeiten. Daher musste ich es ein wenig bearbeiten, um die Windows-Netzwerksicherheitsauthentifizierung zu übernehmen, bei der keine IP-Adressen im Sicherheitsprotokoll verbleiben. Da kein reguläres FTP ausgeführt wird, habe ich diesen Teil entfernt, da er Fehler verursachte, da kein Protokollordner vorhanden war. Die Hauptänderung betrifft die Quelle der RDP-Ereignisse.

    $current_date_utc = (Get-Date).ToUniversalTime()

    # Set number of failed login attempts after which an IP address will be blocked
    $int_block_limit = 10

    # Time window during which to check the Security log, which is currently set to check only the last 24 hours
    $dat_time_window = [DateTime]::Now.AddDays(-1)

    $arr_new_bad_ips_all = (get-winevent -filterhashtable @{ logname='Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational'; starttime=$dat_time_window; id=140 }).message |
        % { if ($_ -match "of (.+) failed") { $Matches[1] }} |
        Group-Object |
        Where {$_.Count -ge $int_block_limit} |
        Select -property Name

    # Sort the array, selecting only unique IPs (in case one IP shows up in both the Security and FTP logs)
    $arr_new_bad_ips_all = $arr_new_bad_ips_all | Foreach-Object { [string]$_.Name } | Select-Object -unique

    # Get firewall object
    $firewall = New-Object -comobject hnetcfg.fwpolicy2

    # Get all firewall rules matching "BlockAttackers*"
    $arr_firewall_rules = $firewall.Rules | Where {$_.Name -like 'BlockAttackers*'}

    # If no "BlockAttackers*" firewall rule exists yet, create one and set it to a variable
    if ($arr_firewall_rules -eq $null) {
        $str_new_rule_name = "BlockAttackers (Created " + $current_date_utc.ToString("yyyy-MM-dd HH:mm:ss") + " UTC)"
        netsh advfirewall firewall add rule dir=in action=block name=$str_new_rule_name description="Rule automatically created." enable=yes remoteip="0.0.0.0" | Out-Null
        $arr_firewall_rules = $firewall.Rules | Where {$_.Name -like 'BlockAttackers*'}
    }

    # Split the existing IPs from current "BlockAttackers*" firewall rule(s) into an array so we can easily search them
    $arr_existing_bad_ips = @()
    foreach ($rule in $arr_firewall_rules) {
        $arr_existing_bad_ips += $rule.RemoteAddresses -split(',')
    }

    # Clean subnet masks off of IPs that are currently blocked by the firewall rule(s)
    $arr_existing_bad_ips_without_masks = $arr_existing_bad_ips | ForEach-Object {$_ -replace "/.*", ""}

    # Select IP addresses to add to the firewall, but only ones that...
    $arr_new_bad_ips_for_firewall = $arr_new_bad_ips_all | Where {
        # contain an IP address (i.e. aren't blank or a dash, which the Security log has for systems that failed FTP logins)
        $_.Length -gt 6 -and
        # aren't already in the firewall rule(s)
        !($arr_existing_bad_ips_without_masks -contains $_) -and
        # aren't the local loopback
        !($_.StartsWith('127.0.0.1')) -and
        # aren't part of the local subnet
        !($_.StartsWith('192.168.')) -and
        !($_.StartsWith('0.0.'))
    }

    # If there are IPs to block, do the following...
    if ($arr_new_bad_ips_for_firewall -ne $null) {
        # Write date and time to script-specific log file
        [DateTime]::Now | Out-File -Append -Encoding utf8 C:\Security\blockattackers.txt
        # Write newly-blocked IP addresses to log file
        $arr_new_bad_ips_for_firewall | Out-File -Append -Encoding utf8 C:\Security\blockattackers.txt

        # Boolean to make sure the new IPs are only added on one rule
        $bln_added_to_rule = 0

        # Array to hold bad IPs from each rule one at a time, so we can count to make sure adding the new ones won't exceed 1000 IPs
        $arr_existing_bad_ips_current_rule = @()

        # For each "BlockAttackers*" rule in the firewall, do the following...
        foreach ($rule in $arr_firewall_rules) {
            if ($bln_added_to_rule -ne 1) {
                # Split the existing IPs from the current rule into an array so we can easily count them
                $arr_existing_bad_ips_current_rule = $rule.RemoteAddresses -split(',')

                # If the number of IPs to add is less than 1000 minus the current number of IPs in the rule, add them to this rule
                if ($arr_new_bad_ips_for_firewall.Count -le (1000 - $arr_existing_bad_ips_current_rule.Count)) {
                    # Add new IPs to firewall rule
                    $arr_new_bad_ips_for_firewall | %{$rule.RemoteAddresses += ',' + $_}

                    # Write which rule the IPs were added to to log file
                    echo "New IP addresses above added to Windows Firewall rule:" $rule.Name | Out-File -Append -Encoding utf8 C:\Security\blockattackers.txt

                    # Set boolean so any other rules are skipped when adding IPs
                    $bln_added_to_rule = 1
                }
            }
        }

        # If there wasn't room in any other "BlockAttackers*" firewall rule, create a new one and add the IPs to it
        if ($bln_added_to_rule -ne 1) {
            $str_new_rule_name = "BlockAttackers (Created " + $current_date_utc.ToString("yyyy-MM-dd HH:mm:ss") + " UTC)"
            netsh advfirewall firewall add rule dir=in action=block name=$str_new_rule_name description="Rule automatically created." enable=yes remoteip="0.0.0.0" | Out-Null
            $new_rule = $firewall.rules | Where {$_.Name -eq $str_new_rule_name}

            # Add new IPs to firewall rule
            $arr_new_bad_ips_for_firewall | %{$new_rule.RemoteAddresses += ',' + $_}

            # Write which rule the IPs were added to to log file
            echo "New IP addresses above added to newly created Windows Firewall rule:" $new_rule.Name | Out-File -Append -Encoding utf8 C:\Security\blockattackers.txt
        }
    }

Das obige Skript funktioniert unter Windows 2012. Wenn Sie unter Windows 2008 weiterhin Remotedesktop mit Authentifizierung auf Netzwerkzugriffsebene verwenden, müssen Sie möglicherweise den folgenden Trick ausführen. Windows 2008 enthält keine IP-Adressen im Sicherheitsprotokoll und scheint diese auch nicht im Microsoft-Windows-RemoteDesktopServices-RdpCoreTS-Protokoll zu haben. Ich musste also tatsächlich zwei Protokolle verwenden - Ereignisse aus dem Sicherheitsprotokoll mit erfolgreichen Zugriffsversuchen auf Port 3389 im Firewall-Protokoll abgleichen. Dies ist eine Vermutung, aber es scheint Passwortangriffe zu erkennen. Hier ist der Teil, der verletzende IPs sammelt:

    $current_date_utc = (Get-Date).ToUniversalTime()

    # Set number of failed login attempts after which an IP address will be blocked
    $int_block_limit = 10

    $dat_time_window = [DateTime]::Now.AddDays(-1)

    $logfn = (netsh advfirewall show allprofiles | Select-String Filename | select-object -unique | % { $_ -replace "%systemroot%",$env:systemroot }).substring(10).trimstart().trimend()

    $badevts = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $dat_time_window | foreach-object { [datetime]$_.TimeWritten } | sort-object

    $fwlog = Select-String -Path $logfn -Pattern "ALLOW TCP" |
        % {
            if ($_ -match "(201.-..-..) (.+) ALLOW TCP (.+) (.+) (.+) 3389") 
            {
                new-object psobject -property @{ 
                  dt = $Matches[1] + ' ' + $Matches[2]
                  ip = $Matches[3]
                }
            }
        }

    $ipa = @()
    $j = 0

    for ($i=0; $i -lt $fwlog.Count; $i++)
    {
        $conn = ([datetime]$fwlog[$i].dt).ticks
        while (($j -lt $badevts.Count) -and (($badevts[$j]).ticks -lt $conn)) { $j++ }
        if ($j -ge $badevts.Count) { break }
        if ((($badevts[$j]).ticks - $conn) -le 30000000) { $ipa += ,($fwlog[$i].ip) }
    }

    $arr_new_bad_ips_all = $ipa |
        Group-Object |
        Where {$_.Count -ge $int_block_limit} |
        Select -property Name

HINWEIS: Vergessen Sie nicht, Firewall-Protokolle zu aktivieren. HINWEIS 2: Ich bin kein Powershell-Experte, daher wäre es schön, wenn einige Gurus meinen Code korrigieren/verbessern könnten.

2
Calm Down

Ich benutze ts_block freeby.

Grundsätzlich handelt es sich um ein "VBScript-Programm, das als WMI-Ereignissenke fungiert, um Ereignisse zu empfangen, die von Windows als Antwort auf ungültige Terminaldiensteanmeldungen protokolliert wurden."

Scheint perfekt zu funktionieren und das Skript ist unkompliziert, wenn Sie es modifizieren müssen. Sie können entweder zulassen, dass Versuche protokolliert und dann basierend auf der Anzahl der zulässigen Versuche gesperrt werden, und/oder Sie können Anmeldenamen, auf die Sie keinen Zugriff gewähren möchten, fest codieren.

Ich wurde durch zweimaliges versehentliches Hinzufügen des gleichen Namens überrascht und der Dienst geht nur in eine Endlosschleife, die alle 1500 ms neu gestartet wird, aber sehr einfach zu reparieren/modifizieren, wenn Sie mit vbs einverstanden sind.

Meine aktuellen Einstellungen sind nur ein erneuter Versuch und Sie sind für 2 Tage gesperrt. Anmeldungen wie "admin", "admin", "Administrator", "guest" usw. werden automatisch gesperrt. Sollte es einfach sein, auf IP zu wechseln?

Es macht süchtig, nachzusehen, welche Tiere über Nacht verboten wurden ...

1
chipbug

Meinen Sie die Anmeldung am Server/der Domäne oder die Anmeldung an einer Website, die auf dem Server ausgeführt wird? Wenn Sie sich am Server/in der Domäne anmelden möchten, lautet die Antwort Nein. Windows hat kein Konzept zum Blockieren von IP-Adressen basierend auf fehlgeschlagenen Anmeldeversuchen, da IP-Adressen keine Sicherheitsentitäten sind. Möglicherweise gibt es Tools von Drittanbietern, die dies tun können, aber mir sind keine bekannt, da ich mich noch nie darum gekümmert habe.

0
joeqwerty

Wenn ein Webserver angegriffen wird, können Sie Erweiterung für dynamische IP-Einschränkungen installieren. Wenn dies für die Standardauthentifizierung beim Server vorgesehen ist, sollten Sie in der Lage sein, Domänen- und Serverisolation zu implementieren, wodurch der Umfang der Angriffe auf Computer mit Domänenbeitritt begrenzt wird und nur Versuche von der Server-Datenbank zugelassen werden können Systeme, für die Sie Zugriff auf den Server benötigen. In Windows besteht die Verhinderung von Brute-Force-Angriffen darin, die Kontosperrungsrichtlinie auf eine Einstellung wie 10 Minuten und eine Richtlinie für ein falsches Kennwort auf 3 Versuche festzulegen. Dies bedeutet, dass das angegriffene Konto nach 3 Versuchen für 10 Minuten gesperrt wird. IP-Verbindungen können in Windows standardmäßig nicht gesperrt werden. (Nebenbei bin ich auch gespannt, wie viele Anmeldeversuche pro Sekunde erforderlich sind, um das System zu beeinflussen.)

0
Jim B

http://nerderies.blogspot.co.at/2012/12/automatically-banning-ips-with-windows.html

Wenn Sie eine sofort einsatzbereite Lösung (Install & done) wünschen, finden Sie hier ein kostenloses Tool, das Sie wahrscheinlich weiterlesen sollten:

Aktuelle Version: 1.2 (.NET Framework 4.0-Clientprofil) -> Laden Sie die aktuelle Version von EvlWatcher herunter (kostenlos für den persönlichen und kommerziellen Gebrauch)

Neu in 1.2 (weitere Informationen in der Dokumentation):

  • Managementkonsole
  • WCF-Servicemuster
  • Blacklisting
  • Automatisches Verschieben auf die schwarze Liste nach 3 Schlägen (standardmäßig)

Für ältere Server (.NET Framework 2.0)

-> Laden Sie die reduzierte Version von EvlWatcher herunter (kostenlos für den persönlichen und kommerziellen Gebrauch)

0
Mastro

Mit dem großartigen Skript von remunda als Ausgangspunkt habe ich eine wichtige Sache hinzugefügt, die fehlte: Blockieren von IP-Adressen für fehlgeschlagene FTP-Anmeldungen . Windows Server protokolliert die IP-Adresse nicht im Sicherheitsprotokoll, wenn sich jemand nicht über FTP anmeldet, sondern setzt die "Quellnetzwerkadresse" auf einen Bindestrich. FTP ist ein sehr häufiger Angriffsvektor für Brute-Force-Angriffe. Daher habe ich seinem Skript die Möglichkeit hinzugefügt, die FTP-Protokolle des aktuellen Tages auf mehrere Anmeldefehler zu scannen und diese IP-Adressen ebenfalls zu blockieren.

Update 07.02.2014: Als ich einige Änderungen daran vorgenommen habe, um alle meine alten FTP-Protokolle zu verarbeiten, wurde mir klar, dass sie eine immense Anzahl von Versuchen hatten ( 50.000+), die von ihm erstellten Arrays wären riesig und würden die Verarbeitung unglaublich langsam machen. Ich habe es seitdem umgeschrieben, um es bei der Verarbeitung von FTP-Protokollen viel effizienter zu machen.

Ich habe auch herausgefunden, dass es eine willkürliche feste Grenze von 1000 für die Anzahl der IPs in einer Windows-Firewall-Regel gibt. Aufgrund dieser Begrenzung musste es automatisch eine neue Regel erstellen, wenn die letzte voll ist. Dies geschieht jetzt und es wird auch die anfängliche Firewall-Regel erstellt (wenn Sie keine eigene erstellen), sodass Sie sie nur dem Scheduler hinzufügen müssen, um sie auszuführen, wenn ein Ereignis 4625 vorliegt.

Hier ist der Code, der sowohl unter Windows Server 2008 R2 als auch unter Windows 7 getestet wurde:

# This Windows Powershell script will automatically block IP addresses that attempt to login to the system
# and fail the number of times set below with the $int_block_limit variable or more. Is scans both the Security
# log, which covers Remote Desktop and other attempts, as well as the current day's FTP log. If the $int_block_limit
# limit is hit on either of those logs (separately, not combined), then the IP address will be added to the
# firewall rule.
#
# The script will automatically create a firewall rule named "BlockAttackers (Created yyyy-MM-dd HH:mm:ss UTC)" using
# the current time if one with a name that includes "BlockAttackers" doesn't already exist. Because there's a hard
# limit of 1000 entries (IP addresses) you can block per rule, it will also create similarly-named rules once that
# limit is reached for the latest one.
#
# I recommend setting the script to run as a scheduled task triggered by event 4625 login audit failures from the
# Security log, or alternatively you could set it to run after some amount of time (i.e. every 10 minutes).
#
# Authors:
# Majority of script written by serverfault.com user kevinmicke
# Windows Security Log portion written by serverfault.com user remunda, which provided the starting point for kevinmicke
#
# Details: https://serverfault.com/questions/233222/ban-ip-address-based-on-x-number-of-unsuccessful-login-attempts


# Set number of failed login attempts after which an IP address will be blocked
$int_block_limit = 10

# Time window during which to check the Security log, which is currently set to check only the last 24 hours
$dat_time_window = [DateTime]::Now.AddDays(-1)

# Select from the Security log all IP addresses that have more than $int_block_limit audit failures (event 4625) within $dat_time_window
$arr_new_bad_ips_security_log = @()
$arr_new_bad_ips_security_log = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $dat_time_window |
    Select-Object @{n='IpAddress';e={$_.ReplacementStrings[-2]}} |
    Group-Object -property IpAddress |
    Where {$_.Count -ge $int_block_limit} |
    Select -property Name

# Get current time UTC to figure out filename for current FTP log
$current_date_utc = (Get-Date).ToUniversalTime()

# Set path to today's FTP log file
$str_log_file_name = "C:\inetpub\logs\LogFiles\FTPSVC2\u_ex" + $current_date_utc.ToString("yyMMdd") + ".log"

# Search today's FTP log file for "530 1326" to find lines that contain IPs of systems that failed to log in,
# get just the IP from each line, group the IPs by IP to count the attempts from each one, and select only the
# IPs that have $int_block_limit or more bad logins today
$arr_new_bad_ips_ftp = @()
$arr_new_bad_ips_ftp = Select-String $str_log_file_name -pattern "530 1326" |
    ForEach-Object {$_.Line.Substring(20,15) -replace " .*", ""} |
    Group |
    Where {$_.Count -ge $int_block_limit} |
    Select -property Name

# Concatenate the two arrays of IPs (one from Security log, one from FTP log)
$arr_new_bad_ips_all = @()
# $arr_new_bad_ips_all = @($arr_new_bad_ips_security_log) + @($arr_new_bad_ips_ftp_over_limit)
$arr_new_bad_ips_all = @($arr_new_bad_ips_security_log) + @($arr_new_bad_ips_ftp)

# Sort the array, selecting only unique IPs (in case one IP shows up in both the Security and FTP logs)
$arr_new_bad_ips_all_sorted = @()
$arr_new_bad_ips_all_sorted = $arr_new_bad_ips_all |
    Foreach-Object { [string]$_.Name } |
    Select-Object -unique

# Get firewall object
$firewall = New-Object -comobject hnetcfg.fwpolicy2

# Get all firewall rules matching "BlockAttackers*"
$arr_firewall_rules = $firewall.Rules | Where {$_.Name -like 'BlockAttackers*'}

# If no "BlockAttackers*" firewall rule exists yet, create one and set it to a variable
if ($arr_firewall_rules -eq $null) {
    $str_new_rule_name = "BlockAttackers (Created " + $current_date_utc.ToString("yyyy-MM-dd HH:mm:ss") + " UTC)"
    netsh advfirewall firewall add rule dir=in action=block name=$str_new_rule_name description="Rule automatically created by BlockAttackers Powershell script written by Kevin Micke." enable=yes remoteip="0.0.0.0" | Out-Null
    $arr_firewall_rules = $firewall.Rules | Where {$_.Name -like 'BlockAttackers*'}
}

# Split the existing IPs from current "BlockAttackers*" firewall rule(s) into an array so we can easily search them
$arr_existing_bad_ips = @()
foreach ($rule in $arr_firewall_rules) {
    $arr_existing_bad_ips += $rule.RemoteAddresses -split(',')
}

# Clean subnet masks off of IPs that are currently blocked by the firewall rule(s)
$arr_existing_bad_ips_without_masks = @()
$arr_existing_bad_ips_without_masks = $arr_existing_bad_ips | ForEach-Object {$_ -replace "/.*", ""}

# Select IP addresses to add to the firewall, but only ones that...
$arr_new_bad_ips_for_firewall = @()
$arr_new_bad_ips_for_firewall = $arr_new_bad_ips_all_sorted | Where {
    # contain an IP address (i.e. aren't blank or a dash, which the Security log has for systems that failed FTP logins)
    $_.Length -gt 6 -and
    # aren't already in the firewall rule(s)
    !($arr_existing_bad_ips_without_masks -contains $_) -and
    # aren't the local loopback
    !($_.StartsWith('127.0.0.1')) -and
    # aren't part of the local subnet
    !($_.StartsWith('192.168.')) -and
    !($_.StartsWith('10.0.'))
}

# If there are IPs to block, do the following...
if ($arr_new_bad_ips_for_firewall -ne $null) {
    # Write date and time to script-specific log file
    [DateTime]::Now | Out-File -Append -Encoding utf8 C:\blockattackers.txt
    # Write newly-blocked IP addresses to log file
    $arr_new_bad_ips_for_firewall | Out-File -Append -Encoding utf8 C:\blockattackers.txt

    # Boolean to make sure the new IPs are only added on one rule
    $bln_added_to_rule = 0

    # Array to hold bad IPs from each rule one at a time, so we can count to make sure adding the new ones won't exceed 1000 IPs
    $arr_existing_bad_ips_current_rule = @()

    # For each "BlockAttackers*" rule in the firewall, do the following...
    foreach ($rule in $arr_firewall_rules) {
        if ($bln_added_to_rule -ne 1) {
            # Split the existing IPs from the current rule into an array so we can easily count them
            $arr_existing_bad_ips_current_rule = $rule.RemoteAddresses -split(',')

            # If the number of IPs to add is less than 1000 minus the current number of IPs in the rule, add them to this rule
            if ($arr_new_bad_ips_for_firewall.Count -le (1000 - $arr_existing_bad_ips_current_rule.Count)) {
                # Add new IPs to firewall rule
                $arr_new_bad_ips_for_firewall | %{$rule.RemoteAddresses += ',' + $_}

                # Write which rule the IPs were added to to log file
                echo "New IP addresses above added to Windows Firewall rule:" $rule.Name | Out-File -Append -Encoding utf8 C:\blockattackers.txt

                # Set boolean so any other rules are skipped when adding IPs
                $bln_added_to_rule = 1
            }
        }
    }

    # If there wasn't room in any other "BlockAttackers*" firewall rule, create a new one and add the IPs to it
    if ($bln_added_to_rule -ne 1) {
        $str_new_rule_name = "BlockAttackers (Created " + $current_date_utc.ToString("yyyy-MM-dd HH:mm:ss") + " UTC)"
        netsh advfirewall firewall add rule dir=in action=block name=$str_new_rule_name description="Rule automatically created by BlockAttackers Powershell script written by Kevin Micke." enable=yes remoteip="0.0.0.0" | Out-Null
        $new_rule = $firewall.rules | Where {$_.Name -eq $str_new_rule_name}

        # Add new IPs to firewall rule
        $arr_new_bad_ips_for_firewall | %{$new_rule.RemoteAddresses += ',' + $_}

        # Write which rule the IPs were added to to log file
        echo "New IP addresses above added to newly created Windows Firewall rule:" $new_rule.Name | Out-File -Append -Encoding utf8 C:\blockattackers.txt
    }
}
0
kevinmicke