Vietare l'indirizzo IP in base al numero X di tentativi di accesso falliti?


47

È possibile vietare un indirizzo IP dopo il numero X di tentativi di accesso non riusciti su un server Windows? Non per un account particolare, che so come fare, ma per l'intera macchina.

Veniamo colpiti piuttosto duramente da attacchi di forza bruta che provano a indovinare i nomi utente, quindi questo aiuterebbe davvero a scaricare un po 'di carico dal server.


8
* nix ha fial2ban ... non sono sicuro che esista una porta / equivalente di Windows. fail2ban.org/wiki/index.php/Main_Page
Chris Nava,

5
Da Evan Anderson: serverfault.com/questions/43360/… ... sembra essere un buon equivalente della funzionalità di fail2ban ma poiché la tua domanda non è abbastanza specifica, non so se stai cercando di vietare gli IP che tentano di accedere a un sito Web ospitato, al tuo server (tramite SSH) o al tuo dominio. Il chiarimento farebbe molto. Inoltre, è possibile valutare il limite sul firewall, ma dipende dall'implementazione.

4
Potresti dare un'occhiata a serverfault.com/questions/216995/… per una discussione precedente su quanto sia utile il bannaggio automatico basato sull'IP.
martedì

1
Se stai parlando di Servizi terminal / Desktop remoto dai un'occhiata qui: serverfault.com/a/335976/7200
Evan Anderson

3
Ho fatto un servizio Windows su Github per fare proprio questo: github.com/jjxtra/Windows-IP-Ban-Service
jjxtra

Risposte:


28

Puoi farlo con PowerShell e Task Manager. Probabilmente non è la soluzione perfetta, ma funziona abbastanza bene e ho circa 100 indirizzi IP bloccati in due mesi. Ho scritto uno script, che seleziona tra gli eventi specificati da EventLog ("errore di controllo"). Se ci sono molti accessi non riusciti da qualsiasi indirizzo IP, viene aggiunto alla regola del firewall (creata manualmente) denominata "BlockAttackers" che blocca tutto il traffico verso gli indirizzi IP specificati.

Script PS1:

$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

Creare attività nello scheduler e impostare il trigger sull'evento 4625 (accesso a Windows inclusi i servizi terminal). Tuttavia, è possibile impostare l'esecuzione del trigger, ad es. Due volte all'ora per evitare il caricamento non necessario del server.

Trigger dello scheduler

e dopo l'attivazione eseguire lo script PowerShell. È inoltre necessario impostare privilegi più elevati per eseguire questo script, altrimenti fallirà con l'eccezione di sicurezza.

esecuzione script PowerShell

Puoi anche associare questo script ad altri eventi di sicurezza.


1
Eccellente sceneggiatura @remunda - grazie! Stavo ricevendo anche molti 4625 da FTP, per cui il registro di sicurezza non ha indirizzi IP, quindi ho ampliato il tuo script per farlo controllare anche il registro FTP del giorno corrente. Per ulteriori informazioni, consultare la risposta di seguito: serverfault.com/a/571903/107701
kevinmicke

Ci sono molti gotcha e edge case con i log degli eventi, la registrazione degli indirizzi IP, ecc. Che ho gestito in IPBan - gratuito e open source su github.com/jjxtra/Windows-IP-Ban-Service
jjxtra

7

So che questa domanda è vecchia ma in realtà è stato il primo post sul forum in cui mi sono imbattuto quando ho iniziato a provare a fare esattamente la stessa cosa un paio di settimane fa. Sono riuscito a inventare uno script funzionante che analizzerà i registri eventi 24 ore indietro per solo le voci del registro eventi di accesso non valide, afferrando quelli che hanno più di 10 accessi non validi e quindi li inserirà in un elenco di filtri ipsec usando comando netsh. Quindi ho scritto un file batch con questa riga powershell .\*scriptname.ps1*e ho creato un'attività pianificata per eseguire il file batch ogni 24 ore (per qualche motivo non sarebbe stato eseguito direttamente).

$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}

So che questo script è probabilmente inefficiente, ma quando ho iniziato a lavorarci non avevo assolutamente esperienza in PowerShell, quindi la mia capacità di ottimizzare gli script lascia molto a desiderare. Tuttavia, nonostante ciò, ho pensato di condividere questo con chiunque potesse usarlo.

Ringrazio Remunda per avermi dato l'idea iniziale, quel poster è quello che mi ha dato l'idea di usare PowerShell per cercare nei registri degli eventi.


4

Questo script si basa sulla risposta di remunda e va un po 'più avanti https://serverfault.com/a/397637/155102 Rappresenta la regola "BlockAttackers" a cui non è stato ancora inserito alcun IP (che restituisce un "*" come stringa). Scrive anche un commento in un file di registro per farti sapere quando l'IP è stato aggiunto alla regola.

Un buon consiglio è quello di creare la regola "BlockAttackers" che blocca gli indirizzi IP, ma all'inizio lo disabilita. Quindi, eseguire questo script una volta manualmente in modo che possa popolare il campo "RemoteAddresses" con gli indirizzi IP effettivi che dovrebbero essere bloccati. Dai un'occhiata a quegli indirizzi IP per assicurarti che non sia stato aggiunto nulla di critico e quindi abilita la regola del firewall. Aggiungi questa regola al firewall come descritto di seguito.

Il git per questo script

#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'}
}


2

In genere non è una buona idea lasciare che qualcun altro controlli le regole del firewall. Questo è fondamentalmente quello che stai chiedendo qui.


1
+1, questo è un modo eccellente di prepararti per un attacco denial of service. E se stai utilizzando la limitazione della velocità, la maggior parte degli strumenti di forza bruta automatizzati distanzia i loro tentativi di accesso abbastanza da separarli per evitare di essere scoperti.

12
Vietare automaticamente gli IP dopo un certo numero di accessi non riusciti è una pratica molto comune. Vedo che gli host vengono bannati su base oraria dopo aver tentato di indovinare le password FTP. L'unico modo in cui questo può essere un attacco DoS è se qualcuno è riuscito a falsificare il tuo IP (impossibile su connessioni TCP) o se digiti ripetutamente la tua password (nel qual caso non è qualcun altro che controlla le regole del firewall, sei tu)
devicenull

18
Scusa, ma non ho chiesto se fosse una buona idea.
HeavyWave,

1
Ovviamente non vi è alcun motivo per cui non sia possibile impostare eccezioni per uno o più indirizzi IP specifici, il che eliminerebbe praticamente il problema DoS.
John Gardeniers,

2

Questo è un vecchio thread. Stavo usando la sceneggiatura fornita da kevinmicke nel 2014-2015. Quindi ha smesso di funzionare. Quindi ho dovuto modificarlo un po 'per adottare l'autenticazione di sicurezza della rete di Windows che non lascia gli indirizzi IP nel registro di sicurezza. Inoltre, poiché non ho FTP in esecuzione regolarmente, ho rimosso quella parte perché causava errori perché non c'era una cartella di registro. Il principale cambiamento è nella fonte degli eventi del PSR.

    $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
        }
    }

Lo script sopra funzionerà su Windows 2012. Se stai ancora utilizzando Desktop remoto con autenticazione a livello di accesso alla rete su Windows 2008, potrebbe essere necessario eseguire il seguente trucco. Windows 2008 non ha indirizzi IP nel registro di sicurezza e non sembra averli nemmeno nel registro Microsoft-Windows-RemoteDesktopServices-RdpCoreTS. Quindi ho dovuto effettivamente utilizzare 2 registri: abbinare gli eventi dal registro di sicurezza ai tentativi di accesso riusciti alla porta 3389 nel registro del firewall. Si tratta di un'ipotesi, ma sembra rilevare attacchi con password. Ecco la parte che raccoglie gli IP in violazione:

    $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

NOTA: non dimenticare di abilitare i log del firewall. NOTA 2: Non sono un esperto di PowerShell, quindi sarebbe bello se alcuni guru potessero correggere / migliorare il mio codice.


1

Sto usando ts_block freeby.

Fondamentalmente è un "programma VBScript che funge da sink di evento WMI per ricevere eventi registrati da Windows in risposta ad accessi non validi a Servizi terminal."

Sembra funzionare perfettamente e lo script è semplice se è necessario modificarlo. Puoi lasciare che registri i tentativi e quindi bannare in base al numero di tentativi consentiti e / o puoi codificare i nomi di accesso a cui non vuoi dare accesso.

Sono stato sorpreso aggiungendo accidentalmente lo stesso nome due volte e il servizio va semplicemente in un ciclo infinito riavviando ogni 1500 ms, ma molto facile da correggere / mod se stai bene con vbs.

Le mie impostazioni attuali sono solo un tentativo e verrai bannato per 2 giorni, con login come 'admin' 'Admin' 'Administrator' 'guest' ecc. Automaticamente banditi. Dovrebbe essere semplice passare a ip?

Un po 'avvincente per entrare e vedere quali creature sono state bandite da un giorno all'altro ...


0

Intendi accedere al server / dominio o accedere a un sito Web in esecuzione sul server? Se si intende accedere al server / dominio, la risposta è no. Windows non ha alcun concetto di blocco degli indirizzi IP in base a tentativi di accesso non riusciti poiché gli indirizzi IP non sono entità di sicurezza. Potrebbero esserci strumenti di terze parti che possono farlo, ma non ne sono a conoscenza poiché non ci ho mai guardato dentro.


0

Se è presente un server Web che viene attaccato, è possibile installare l' estensione delle restrizioni IP dinamiche . Se questo è per l'autenticazione standard sul server, dovresti essere in grado di implementare l' isolamento del dominio e del server che limiterebbe l'ambito degli attacchi ai computer aggiunti al dominio e potrebbe essere impostato per consentire solo i tentativi dai sistemi a cui devi avere accesso il server. In Windows la prevenzione degli attacchi di forza bruta consiste nell'impostare la politica di blocco dell'account su un'impostazione come 10 minuti e una politica di password errata su 3 tentativi - ciò significa che l'account attaccato si bloccherebbe per 10 minuti dopo 3 tentativi. Le connessioni IP non sono bloccabili per impostazione predefinita in Windows. (Per inciso, sono anche curioso di sapere quanti tentativi di accesso ci vogliono al secondo per avere un impatto sul sistema)


Nella mia piccola istanza AWS, è sufficiente 1 tentativo ogni 4 secondi per consumare il 50% di CPU. Che schifo se me lo chiedi ...
RomanSt

Wow, mi chiedo perché l'utilizzo sia così elevato. Dovrò fare alcuni test per vedere quanti tentativi ci vogliono sulle mie macchine virtuali per registrarsi.
Jim B

Penso che sia perché non sto usando l'autenticazione a livello di rete, quindi ogni tentativo di accesso fa girare un'interfaccia utente di accesso per presentarsi effettivamente all'attaccante attraverso una sessione desktop remota. Vedo perché potrebbe essere costoso.
Roman,

0

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

Se quello che vuoi è una soluzione pronta all'uso (Installa e fai) puoi trovare uno strumento gratuito qui, e probabilmente dovresti continuare a leggere questo:

Versione corrente: 1.2 (profilo client .NET Framework 4.0) -> Scarica la versione corrente di EvlWatcher (gratuita per uso personale e commerciale)

Novità in 1.2 (maggiori informazioni nella documentazione):

  • Console di gestione
  • Modello di servizio WCF
  • lista nera
  • Spostamento automatico nella lista nera dopo 3 strike (per impostazione predefinita)

Per server meno recenti (.NET Framework 2.0)

-> Scarica la versione ridotta di EvlWatcher (gratuita per uso personale e commerciale)


0

Usando il grande script di remunda come punto di partenza, ho aggiunto una cosa importante che mancava: bloccare gli indirizzi IP da accessi FTP non riusciti . Windows Server non registra l'indirizzo IP nel registro di sicurezza quando qualcuno non riesce ad accedere tramite FTP, ma imposta "Indirizzo di rete di origine" su un trattino. L'FTP è un vettore di attacco molto comune per gli attacchi di forza bruta, quindi ho aggiunto al suo script la possibilità di scansionare i log FTP del giorno corrente alla ricerca di più errori di accesso e bloccare anche quegli indirizzi IP.

Aggiornamento 2014/02/07: Quando ho apportato alcune modifiche a questo per elaborare tutti i miei vecchi log FTP, mi sono reso conto che quando avevano avuto un numero immenso di tentativi (oltre 50.000), gli array che ha creato sarebbero stati enormi e avrebbero reso l'elaborazione incredibilmente lenta. Da allora l'ho riscritto per renderlo molto più efficiente durante l'elaborazione dei log FTP.

Ho anche scoperto che esiste un limite arbitrario di 1000 per quanti IP possono essere presenti in una regola di Windows Firewall. A causa di quel limite, ne avevo bisogno per creare automaticamente una nuova regola quando si riempie l'ultima. Ora lo fa e crea anche la regola del firewall iniziale (se non ne crei una tua) in modo che l'unica configurazione da fare sia aggiungerla allo Scheduler per l'esecuzione quando c'è un evento 4625.

Ecco il codice, che è stato testato su Windows Server 2008 R2 e Windows 7:

# 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
    }
}

Cordiali saluti: Per coloro che non hanno mai eseguito uno script PowerShell su un sistema in precedenza, è necessario prima aprire una nuova PowerShell ed eseguire in Set-ExecutionPolicy RemoteSignedmodo da poter eseguire gli script locali. Altrimenti riceverai un errore: "Impossibile caricare blockattackers.ps1 perché l'esecuzione degli script è disabilitata su questo sistema."
Kevinevke

0

Lo script di remuda , modificato da kevinmicke (7 febbraio alle 21:59) non controllava il canale di controllo dell'FTP, che ha una propria cartella sul mio sistema (Windows Server 2008 R2). Inoltre, gli 530 11001eventi non sono stati riconosciuti, che sembrano apparire quando l'hacker tenta solo di accedere al canale di controllo. Quindi ho aggiunto alcune righe nello script per controllare una seconda cartella di registro FTP:

# Questo script di Windows Powershell bloccherà automaticamente gli indirizzi IP che tentano di accedere al sistema
# e fallisce il numero di volte impostato di seguito con la variabile $ int_block_limit o più. Esegue la scansione sia della sicurezza
# log, che copre Desktop remoto e altri tentativi, nonché il registro FTP del giorno corrente. Se $ int_block_limit
Il limite # viene raggiunto su uno di questi registri (separatamente, non combinato), quindi l'indirizzo IP verrà aggiunto a
# regola del firewall.
#
# Lo script creerà automaticamente una regola firewall denominata "BlockAttackers (Created yyyy-MM-dd HH: mm: ss UTC)" utilizzando
# l'ora corrente se uno con un nome che include "BlockAttackers" non esiste già. Perché c'è un duro
# limite di 1000 voci (indirizzi IP) che puoi bloccare per regola, in seguito creerà anche regole con nomi simili
Il limite # viene raggiunto per l'ultimo.
#
# Raccomando di impostare l'esecuzione dello script come attività pianificata attivata da errori di controllo dell'accesso 4625 dell'evento da
# Registro di sicurezza o, in alternativa, è possibile impostarlo per l'esecuzione dopo un certo periodo di tempo (ovvero ogni 10 minuti).
#
# Autori:
# Maggioranza dello script scritto dall'utente kevinmicke di serverfault.com
# Parte del registro di sicurezza di Windows scritta dall'utente remunda di serverfault.com, che ha fornito il punto di partenza per kevinmicke
# Verifica del canale di controllo dell'FTP aggiunto dall'utente Uwe Martens di serverfault.com
#
# Dettagli: https://serverfault.com/questions/233222/ban-ip-address-based-on-x-number-of-unsuccessful-login-attempts


# Imposta il numero di tentativi di accesso falliti dopo i quali verrà bloccato un indirizzo IP
$ int_block_limit = 3

# Finestra temporale durante la quale controllare il registro di sicurezza, che è attualmente impostato per controllare solo le ultime 24 ore
$ dat_time_window = [DateTime] :: Now.AddDays (-1)

# Seleziona dal registro sicurezza tutti gli indirizzi IP che hanno più di $ int_block_limit errori di controllo (evento 4625) in $ dat_time_window
$ arr_new_bad_ips_security_log = @ ()
$ arr_new_bad_ips_security_log = Get-EventLog -LogName 'Security' -InstanceId 4625 -Dopo $ dat_time_window |
    Select-Object @ {n = 'IpAddress'; e = {$ _. ReplacementStrings [-2]}} |
    Indirizzo IP proprietà-gruppo |
    Dove {$ _. Count -ge $ int_block_limit} |
    Seleziona -property Name

# Ottieni l'ora UTC corrente per capire il nome del file per il registro FTP corrente
$ current_date_utc = (Get-Date) .ToUniversalTime ()

# Imposta il percorso del file di registro del canale di controllo FTP di oggi
$ str_log_file_name_control_channel = "C: \ inetpub \ logs \ LogFiles \ FTPSVC \ u_ex" + $ current_date_utc.ToString ("yyMMdd") + ".log"

# Cerca nel file di registro del canale di controllo FTP di oggi "530 1" per trovare le linee che contengono IP dei sistemi che non sono riusciti ad accedere,
# ottiene solo l'IP da ciascuna linea, raggruppa gli IP per IP per contare i tentativi di ciascuno e seleziona solo il
# IP che hanno $ int_block_limit o più accessi non validi oggi
$ arr_new_bad_ips_ftp_control_channel = @ ()
$ arr_new_bad_ips_ftp_control_channel = Seleziona-stringa $ str_log_file_name_control_channel -pattern "530 1" |
    ForEach-Object {$ _. Line.Substring (20,15) -replace ". *", ""} |
    Gruppo |
    Dove {$ _. Count -ge $ int_block_limit} |
    Seleziona -property Name

# Imposta il percorso per il file di registro FTP di oggi
$ str_log_file_name = "C: \ inetpub \ logs \ LogFiles \ FTPSVC * \ u_ex" + $ current_date_utc.ToString ("yyMMdd") + ".log"

# Cerca il file di registro FTP di oggi per "530 1" per trovare linee che contengono IP di sistemi che non sono riusciti ad accedere,
# ottiene solo l'IP da ciascuna linea, raggruppa gli IP per IP per contare i tentativi di ciascuno e seleziona solo il
# IP che hanno $ int_block_limit o più accessi non validi oggi
# In FTPSVC * è necessario aggiungere l'ID del server FTP anziché *, oppure semplicemente prendere la cartella di registro corretta
$ arr_new_bad_ips_ftp = @ ()
$ arr_new_bad_ips_ftp = Seleziona-stringa $ str_log_file_name -pattern "530 1" |
    ForEach-Object {$ _. Line.Substring (20,15) -replace ". *", ""} |
    Gruppo |
    Dove {$ _. Count -ge $ int_block_limit} |
    Seleziona -property Name

# Concatena i due array di IP (uno dal registro di sicurezza, uno dal registro FTP)
$ 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_control_channel) + @ ($ arr_new_bad_ips_ftp)

# Ordina l'array, selezionando solo IP univoci (nel caso in cui un IP venga visualizzato nei registri Sicurezza e FTP)
$ arr_new_bad_ips_all_sorted = @ ()
$ arr_new_bad_ips_all_sorted = $ arr_new_bad_ips_all |
    Foreach-Object {[stringa] $ _. Nome} |
    Select-Object -unique

# Ottieni oggetto firewall
$ firewall = New-Object -comobject hnetcfg.fwpolicy2

# Ottieni tutte le regole del firewall corrispondenti a "BlockAttackers *"
$ arr_firewall_rules = $ firewall.Rules | Dove {$ _. Simile a BlockAttackers * '}

# Se non esiste ancora una regola firewall "BlockAttackers *", crearne una e impostarla su una variabile
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 aggiungi regola dir = in action = nome blocco = $ str_new_rule_name description = "Regola creata automaticamente." enable = yes remoteip = "0.0.0.0" | Out-Null
    $ arr_firewall_rules = $ firewall.Rules | Dove {$ _. Simile a BlockAttackers * '}
}

# Dividi gli IP esistenti dalle attuali regole del firewall "BlockAttackers *" in un array in modo da poterle cercare facilmente
$ arr_existing_bad_ips = @ ()
foreach ($ rule in $ arr_firewall_rules) {
    $ arr_existing_bad_ips + = $ rule.RemoteAddresses -split (',')
}

# Elimina le maschere di sottorete dagli IP attualmente bloccati dalle regole del firewall
$ arr_existing_bad_ips_without_masks = @ ()
$ arr_existing_bad_ips_without_masks = $ arr_existing_bad_ips | ForEach-Object {$ _ -replace "/.*", ""}

# Immettere l'IP del server (IPv4 e IPv6) nelle righe 115 e 116.
# Seleziona gli indirizzi IP da aggiungere al firewall, ma solo quelli che ...
$ arr_new_bad_ips_for_firewall = @ ()
$ arr_new_bad_ips_for_firewall = $ arr_new_bad_ips_all_sorted | Dove {
    # contiene un indirizzo IP (ovvero non è vuoto o un trattino, che ha il registro di sicurezza per i sistemi che non hanno effettuato l'accesso FTP)
    $ _. Lunghezza -gt 6 -e
    # non sono già nelle regole del firewall
    ! ($ arr_existing_bad_ips_without_masks -contains $ _) -e
    # non sono il loopback locale
    ! ($ _. StartsWith ('127.0.0.1')) -e
    # non fanno parte della sottorete locale
    ! ($ _. StartsWith ('192.168.')) -E
    ! ($ _. Inizia con ('0.0.')) -E
    ! ($ _. Inizia con ('10 .0. ')) -E
    ! ($ _. Inizia con ('*. *. *. *')) -E
    ($ _ StartsWith (. '*: *: *: *: *: *'))
}

# Se ci sono IP da bloccare, procedi come segue ...
if ($ arr_new_bad_ips_for_firewall -ne $ null) {
    # Scrivi data e ora nel file di registro specifico dello script
    [DateTime] :: Now | Out-File -Append -Codifica utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt
    # Scrivere gli indirizzi IP appena bloccati nel file di registro
    $ arr_new_bad_ips_for_firewall | Out-File -Append -Codifica utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt

    # Booleano per assicurarsi che i nuovi IP vengano aggiunti solo su una regola
    $ bln_added_to_rule = 0

    # Array per contenere IP non validi da ciascuna regola una alla volta, quindi possiamo contare per assicurarci che l'aggiunta di quelli nuovi non superi i 1000 IP
    $ arr_existing_bad_ips_current_rule = @ ()

    # Per ogni regola "BlockAttackers *" nel firewall, procedi come segue ...
    foreach ($ rule in $ arr_firewall_rules) {
        if ($ bln_added_to_rule -ne 1) {
            # Dividi gli IP esistenti dalla regola corrente in un array in modo da poterli contare facilmente
            $ arr_existing_bad_ips_current_rule = $ rule.RemoteAddresses -split (',')

            # Se il numero di IP da aggiungere è inferiore a 1000 meno il numero corrente di IP nella regola, aggiungerli a questa regola
            if ($ arr_new_bad_ips_for_firewall.Count -le (1000 - $ arr_existing_bad_ips_current_rule.Count)) {
                # Aggiungi nuovi IP alla regola del firewall
                $ arr_new_bad_ips_for_firewall | % {$ rule.RemoteAddresses + = ',' + $ _}

                # Scrivere a quale regola sono stati aggiunti gli IP al file di registro
                echo "Nuovi indirizzi IP sopra aggiunti alla regola di Windows Firewall:" $ rule.Name | Out-File -Append -Codifica utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt

                # Imposta il valore booleano in modo che eventuali altre regole vengano ignorate quando si aggiungono IP
                $ bln_added_to_rule = 1
            }
        }
    }

    # Se non c'era spazio in nessun'altra regola firewall "BlockAttackers *", creane una nuova e aggiungi gli IP ad essa
    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 aggiungi regola dir = in action = nome blocco = $ str_new_rule_name description = "Regola creata automaticamente." enable = yes remoteip = "0.0.0.0" | Out-Null
        $ new_rule = $ firewall.rules | Dove {$ _. Nome -eq $ str_new_rule_name}

        # Aggiungi nuovi IP alla regola del firewall
        $ arr_new_bad_ips_for_firewall | % {$ new_rule.RemoteAddresses + = ',' + $ _}

        # Scrivere a quale regola sono stati aggiunti gli IP al file di registro
        echo "Nuovi indirizzi IP sopra aggiunti alla regola Windows Firewall appena creata:" $ new_rule.Name | Out-File -Append -Codifica utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt
    }
}

Il nome della cartella di registro dell'FTP FTPSVC*alla riga 54 deve essere completato dalla causa. Nelle righe 115 e 116 deve essere inserito l'IP del server (IPv4 e IPv6), altrimenti l'IP del proprio server potrebbe essere aggiunto alla regola del firewall centinaia di volte. La variabile $int_block_limitche sto impostando su 1 sul mio server, quindi lo script sta bloccando un attacco di hacker causando un evento 4625 entro due secondi. Sto ancora pensando di eseguire lo script in aggiunta agli eventi 4625 che si verificano in un periodo di tempo di pochi minuti. Di causa, sarebbe anche possibile separare gli script e lasciare che uno script controlli gli eventi 4625 attivati ​​dall'evento 4625 e un altro che le cartelle di log dell'FTP controllino periodicamente ogni 5 o 10 minuti, anche con una regola firewall separata e file di registro.


-1

Ho aggiunto il mio per SQL

# Select from the Application log (SQL) all IP addresss that have more than $int_block_limit logon failure within $dat_time_window
$arr_new_bad_ips_SQL_log = @()
$arr_new_bad_ips_SQL_log = Get-EventLog -LogName 'Application' -After $dat_time_window |
    Where-Object{$_.EventID -eq 18456} |
    Select-Object @{n='CLIENT';e={$_.ReplacementStrings[-1]}} |
    Group-Object -property CLIENT |
    Where {$_.Count -ge $int_block_limit} |
    Select -property Name |
    {
        $_.Name = $_.Name.Replace(" [CLIENT: ", "");
        $_.Name = $_.Name.Replace("]", "");
        return $_;
    }

Quindi dovrai aggiungere l'array in ips_all

$arr_new_bad_ips_all = @($arr_new_bad_ips_SQL_log) + @($arr_new_bad_ips_security_log) + @($arr_new_bad_ips_ftp_control_channel) + @($arr_new_bad_ips_ftp)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.