поскольку я только что зарегистрировался, у меня нет репутации, чтобы комментировать это:
Запретить IP-адрес на основании X неудачных попыток входа в систему?
Я обновил сценарий, потому что он не работал на немецкой установке Server 2012R2, и я добавил некоторые дополнительные функции.
сценарий проверяет три разных случая. также есть переключатель, для которого следует использовать журнал событий, поскольку в 2012 году у нас были проблемы, когда некоторые попытки входа в систему (в пределах несуществующего имени пользователя) не генерировали 140 событий.
Также я исправил теперь обработку ipV6, потому что это не работало.
Теперь мой колледж дважды проверил сценарий после того, как он понял, что он больше не работает правильно после моих исправлений ipv6. он исправил некоторые проблемы, и теперь все снова работает нормально. также он изменил сценарий, так что он будет использовать как событие 140, так и 4625. и вы можете установить белые списки IP.
вот последняя версия, надеюсь, это кому-то поможет:
$current_date_utc = (Get-Date).ToUniversalTime()
# Set number of failed login attempts after which an IP address will be blocked
$int_block_limit = 8
# Set number of failed login attempts within 15 seconds
$int_block_limit_seconds = 5
# 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)
$short_window = [DateTime]::Now.AddSeconds(-15)
$micro_window = [DateTime]::Now.AddSeconds(-3)
#Whitelist
$arr_whitelist=@("123.123.123.123")
# if set to true, the Security-Event will be used, on Server 2012(R2) to have IP-Adresses inside the 4625 event of the securityLog inside tsconfig.msc the securitylayer has to be set to "RDP security layer"
# if you use 140 within RdpCoreTS/Operational on Server 2012, you should know that we had some logon-attempts, that did not generate Event 140 within a NOT EXISTENT username and was not recognized - so we switched to RDP security layer and checked 4625
write-host "Phase 1 - Searching Log 'Security' ID 4625"
$arr_new_bad_ips_all = @()
$l = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $dat_time_window | Select-Object @{n = 'IpAddress'; e = { $_.ReplacementStrings[-2] } } | Group-Object -Property IpAddress
foreach ($ipgroup in $l) {
if ($ipgroup.Name -ne "-") {
$arr_new_bad_ips_all += $ipgroup.Name
Write-host "$($ipgroup.Name) - More than $int_block_limit logins in the last 24 hours"
}
}
$l = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $short_window | Select-Object @{n = 'IpAddress'; e = { $_.ReplacementStrings[-2] } } | Group-Object -Property IpAddress
foreach ($ipgroup in $l) {
if ($ipgroup.Name -ne "-") {
$arr_new_bad_ips_all += $ipgroup.Name
Write-host "$($ipgroup.Name) - More than $int_block_limit_seconds logins in 15 seconds"
}
}
$l = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $micro_window | Select-Object @{n = 'IpAddress'; e = { $_.ReplacementStrings[-2] } } | Group-Object -Property IpAddress
foreach ($ipgroup in $l) {
if ($ipgroup.Name -ne "-") {
$arr_new_bad_ips_all += $ipgroup.Name
Write-host "$($ipgroup.Name) - More than 2 Logins in 1 second"
}
}
write-host "Phase 1 - Searching Log 'Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational' ID 140"
$l = (get-winevent -filterhashtable @{ logname = 'Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational'; starttime = $dat_time_window; id = 140 } -ErrorAction SilentlyContinue).message |
#% { if ($_ -match "of (.+) failed") { $Matches[1] }} |
ForEach-Object { if ($_ -match "Fehler einer Verbindung vom Clientcomputer mit der IP-Adresse (.+)\, da der Benutzername oder das Kennwort") { $Matches[1] } } |
Group-Object |
Where-Object { $_.Count -ge $int_block_limit }
foreach ($ipgroup in $l) {
$singleip = $($ipgroup.Group[0].split('"'))[1]
Write-host "$singleip - More than $int_block_limit logins in the last 24 hours"
$arr_new_bad_ips_all += $singleip
}
$l = (get-winevent -filterhashtable @{ logname = 'Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational'; starttime = $short_window; id = 140 } -ErrorAction SilentlyContinue).message |
#% { if ($_ -match "of (.+) failed") { $Matches[1] }} |
ForEach-Object { if ($_ -match "Fehler einer Verbindung vom Clientcomputer mit der IP-Adresse (.+)\, da der Benutzername oder das Kennwort") { $Matches[1] } } |
Group-Object |
Where-Object { $_.Count -ge $int_block_limit_seconds }
foreach ($ipgroup in $l) {
$singleip = $($ipgroup.Group[0].split('"'))[1]
Write-host "$singleip - More than $int_block_limit_seconds logins in 15 seconds"
$arr_new_bad_ips_all += $singleip
}
# the probality of two failed logins with the same IP within one second from a valid user is extreme low, but very high that this is caused by a bruteforce-script - so we block this IP!
$l = (get-winevent -filterhashtable @{ logname = 'Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational'; starttime = $short_window; id = 140 } -ErrorAction SilentlyContinue).message |
#% { if ($_ -match "of (.+) failed") { $Matches[1] }} |
ForEach-Object { if ($_ -match "Fehler einer Verbindung vom Clientcomputer mit der IP-Adresse (.+)\, da der Benutzername oder das Kennwort") { $Matches[1] } } |
Group-Object |
Where-Object { $_.Count -gt 1 }
foreach ($ipgroup in $l) {
$singleip = $($ipgroup.Group[0].split('"'))[1]
Write-host "$singleip - More than 2 Logins in 1 second"
$arr_new_bad_ips_all += $singleip
}
Write-Host ""
Write-Host "Phase 2 - Remove Whitelistet IPs"
foreach($whitelistip in $arr_whitelist) {
$arr_new_bad_ips_all = $arr_new_bad_ips_all | Where-Object { $_ -ne $whitelistip }
write-host "Whitelist $whitelistip"
}
Write-Host ""
Write-Host "Phase 3 - Check up Ruleset"
# Get firewall object
$firewall = New-Object -comobject hnetcfg.fwpolicy2
# Get all firewall rules matching "BlockAttackers*"
$arr_firewall_rules = $firewall.Rules | Where-Object { $_.Name -like 'BlockAttackers*' }
# If no "BlockAttackers*" firewall rule exists yet, create one and set it to a variable
if ($null -eq $arr_firewall_rules) {
$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-Object { $_.Name -like 'BlockAttackers*' }
write-host "Creating Rule"
}
else
{
foreach($rule in $arr_firewall_rules)
{
$arr_remoteaddresses=$rule.RemoteAddresses -split (',')
write-host "Rulename: $($rule.Name) Remoteaddresses: $($arr_remoteaddresses.count)"
}
}
Write-Host ""
Write-Host "Phase 4 - Reading IPs from Firewall Rule"
# 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 "/.*", "" }
$arr_existing_bad_ips_without_masks = $arr_existing_bad_ips_without_masks | ForEach-Object { $_ -replace "-.*", "" } #fixing IPv6
foreach ($oldip in $arr_existing_bad_ips_without_masks) {
write-host $oldip
}
write-host "$($arr_existing_bad_ips.Count) IPs blocked"
Write-Host ""
Write-Host "Phase 5 - Extract new IPs, Remove IPs from private Subnets"
# Select IP addresses to add to the firewall, but only ones that...
$arr_new_bad_ips_for_firewall = $arr_new_bad_ips_all | Where-Object {
# 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.')) -and
!($_.StartsWith('0.0.'))
}
# If there are IPs to block, do the following...
if ($null -ne $arr_new_bad_ips_for_firewall) {
write-host ""
write-host "Phase 6 - Adding New IPs to Rule"
# 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
foreach ( $newip in $arr_new_bad_ips_for_firewall) {
if ($newip.Contains(":")) {
# if adress contains : it is ipv6, then no subnet can be added
$ipstring = ',' + $newip
$rule.RemoteAddresses += $ipstring
write-host "New IPv6 $ipstring"
}
else {
$ipstring = ',' + $newip + '/255.255.255.255'
$rule.RemoteAddresses += $ipstring
write-host "New IPv4 $ipstring"
}
}
# Write which rule the IPs were added to to log file
Write-Output "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." enable=yes remoteip="0.0.0.0" | Out-Null
$new_rule = $firewall.rules | Where-Object { $_.Name -eq $str_new_rule_name }
# Add new IPs to firewall rule
$arr_new_bad_ips_for_firewall | ForEach-Object { $new_rule.RemoteAddresses += ',' + $_ }
# Write which rule the IPs were added to to log file
Write-Output "New IP addresses above added to newly created Windows Firewall rule:" $new_rule.Name | Out-File -Append -Encoding utf8 C:\blockattackers.txt
}
}
else {
write-host ""
write-host "Phase 6 - Adding New IPs to Rule - No New IPs found"
}
возможно, это поможет кому-то в будущем сэкономить время ....
удачной блокировки брутфорсом!