禁止基于X失败登录尝试次数的IP地址?


47

X次Windows服务器登录尝试失败后,是否可以禁止IP地址?不是到我知道该怎么做的特定帐户,而是整个机器。

试图猜测用户名的暴力攻击使我们遭受了沉重打击,因此这确实有助于减轻服务器的负担。


8
* nix具有fial2ban ...不确定是否有Windows等效/端口。 fail2ban.org/wiki/index.php/Main_Page
克里斯·纳瓦

5
从埃文·安德森(Evan Anderson):serverfault.com/questions/43360/… ...看起来与fail2ban的功能相当,但是由于您的问题不够具体,我不知道您是否要禁止尝试登录的IP到托管网站,您的服务器(通过SSH)或您的域。澄清将有很长的路要走。另外,您可以对防火墙进行速率限制,但这取决于实现方式。

4
您可能想看一下serverfault.com/questions/216995/…,以获得有关基于IP的自动禁止的实用性的先前讨论。
pehrs 2011年

1
如果您正在谈论终端服务/远程桌面,请在这里查看:serverfault.com/a/335976/7200
Evan Anderson

3
我在github上做了一个Windows服务来做到这一点:github.com/jjxtra/Windows-IP-Ban-Service
jjxtra 2012年

Answers:


28

您可以使用Powershell和任务管理器执行此操作。这可能不是一个完美的解决方案,但它工作得很好,并且我在两个月内约有100个被阻止的IP地址。我编写了脚本,该脚本从EventLog中选择指定的事件(“审计失败”)。如果有许多来自任何IP地址的失败登录,则会将其添加到名为“ BlockAttackers”的防火墙规则(手动创建)中,该规则将阻止到指定IP地址的任何流量。

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

在调度程序中创建任务,并将触发器设置为事件4625(Windows登录包括终端服务)。但是您可以将触发器设置为每小时运行两次,以避免不必要地加载服务器。

调度触发

并在触发后运行powershell脚本。您还必须设置更高的特权才能运行此脚本,否则它将因安全异常而失败。

运行PowerShell脚本

您还可以将此脚本绑定到其他安全事件。


1
优秀的脚本@remunda-谢谢!我也从FTP那里得到了4625,其中安全日志没有IP地址,因此我扩展了您的脚本以使其也可以检查当天的FTP日志。请参阅以下我的答案以获取更多信息:serverfault.com/a/571903/107701
kevinmicke 2014年

有很多陷阱和边缘情况与事件日志,IP地址记录等,我在IPBan已经处理的-在自由和开放源码github.com/jjxtra/Windows-IP-Ban-Service
jjxtra

7

我知道这个问题很旧,但这实际上是我几周前开始尝试做同样的事情时偶然发现的第一个论坛帖子。我设法提出了一个工作脚本,该脚本将在24小时后仅对不良登录事件日志条目进行事件日志分析,捕获具有10多个不良登录信息的条目,然后使用以下命令将其放入ipsec过滤器列表中netsh命令。然后,我用这一行编写了一个批处理文件,powershell .\*scriptname.ps1*并创建了一个计划任务,每24小时运行一次该批处理文件(由于某种原因,它不会直接执行)。

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

我知道该脚本可能效率不高,但是当我开始进行此工作时,我对Powershell完全没有经验,因此我有很多优化脚本的能力。但是,尽管有这个事实,我还是想与任何可以使用它的人分享。

我感谢Remunda给我的最初想法是,那个海报使我开始想到使用Powershell搜索事件日志的想法。


4

该脚本建立在remunda的答案上,并进一步延伸到https://serverfault.com/a/397637/155102。它说明了“ BlockAttackers”规则尚未输入任何IP(它以字符串形式返回“ *”)。它还会将注释写入日志文件,以使您知道何时将IP添加到规则中。

一个很好的技巧是创建一个“ BlockAttackers”规则,该规则将阻止IP地址,但首先将其禁用。然后,手动运行一次此脚本,以便它可以使用应阻止的实际IP地址填充“ RemoteAddresses”字段。查看这些IP地址,确保没有添加任何关键信息,然后启用防火墙规则。按照说明将此规则添加到防火墙。

该脚本的git

#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

让其他人控制您的防火墙规则通常不是一个好主意。这基本上就是您在这里要的。


1
+1,这是设置拒绝服务攻击的绝佳方法。而且,如果您使用速率限制,则大多数自动暴力破解工具会将其登录尝试间隔得足够远,以免被捕获。

12
在一定数量的失败登录后自动禁止IP是非常常见的做法。尝试猜测FTP密码后,我看到主机每小时被禁止一次。DoS攻击的唯一方法是,如果有人设法欺骗了您的IP(在TCP连接上是不可能的),或者您反复输入错误的密码(在这种情况下,不是其他人控制防火墙规则,而是您自己)
devicenull

18
抱歉,但我没有问这是否是个好主意。
HeavyWave

1
当然,没有理由不能为一个或多个特定IP地址设置例外,这几乎可以消除对DoS的担忧。
John Gardeniers

2

这是一种旧思路。我使用了kevinmicke在2014-2015年提供的脚本。然后它停止工作了。因此,我不得不对其进行一些编辑以采用Windows Network Security身份验证,该身份验证不会在安全日志中保留IP地址。另外,由于我没有常规的FTP运行,因此删除了该部分,因为它没有日志文件夹,从而导致了错误。主要变化在于RDP事件的来源。

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

上面的脚本将在Windows 2012上运行。如果您仍在Windows 2008上使用具有网络访问级别身份验证的远程桌面,则可能需要执行以下技巧。Windows 2008在安全日志中没有IP地址,并且在Microsoft-Windows-RemoteDesktopServices-RdpCoreTS日志中似乎也没有IP地址。因此,我实际上必须使用2个日志-将安全日志中的事件与防火墙日志中对端口3389的成功访问尝试进行匹配。这是一个猜测,但似乎正在检测密码攻击。这是收集违规IP的部分:

    $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

注意:不要忘记启用防火墙日志。注意2:我不是Powershell专家,所以如果一些专家可以纠正/改进我的代码,那就太好了。


1

我正在使用ts_block freeby。

基本上,这是一个“ VBScript程序,充当WMI事件接收器,以接收Windows记录的事件以响应无效的终端服务登录。”

似乎可以完美运行,并且如果需要修改脚本,该脚本非常简单。您可以让它记录尝试次数,然后根据允许的尝试次数进行禁止,和/或可以对不想授予访问权限的登录名进行硬编码。

我被偶然添加两次相同的名称所吸引,并且该服务进入了一个无限循环,每1500毫秒重新启动一次,但是如果您对vbs感到满意,则很容易修复/修改。

我当前的设置只有一次重试,并且被禁止了2天,并且自动禁止了“ admin”,“ Admin”,“ Administrator”,“ guest”等登录名。应该直接更改为ip吗?

Kinda会上瘾,看看一夜之间禁止了哪些生物。


0

您是要登录到服务器/域还是登录到服务器上运行的网站?如果您要登录到服务器/域,则答案为否。Windows没有基于失败的登录尝试来阻止IP地址的概念,因为IP地址不是安全实体。可能有第三方工具可以做到这一点,但是我从来没有研究过,所以我还没有发现任何工具。


0

如果有一个正在受到攻击的Web服务器,则可以安装动态IP限制扩展。如果这是对服务器的标准身份验证,则您应该能够实现域和服务器隔离,从而将攻击范围限制在加入域的计算机上,并且可以设置为仅允许来自需要访问权限的系统的尝试服务器。在Windows中,防止暴力攻击的方法是将帐户锁定策略设置为10分钟,将错误的密码策略设置为3次尝试-这意味着被攻击的帐户将在3次尝试后锁定10分钟。在Windows中,默认情况下IP连接是不可锁定的。(顺便说一句,我也很好奇每秒需要多少次登录尝试才能影响系统)


在我的AWS小实例上,每4秒进行1次尝试足以消耗50%的CPU。如果你问我,我真是个废话……
RomanSt 2012年

哇,我想知道为什么利用率如此之高。我必须进行一些测试,以查看我的VM注册需要进行多少次尝试。
Jim B

我认为这是因为我没有使用网络级别身份验证,所以每次登录尝试都会启动一个登录UI,以通过远程桌面会话实际向攻击者展示。我明白为什么这可能会很昂贵。
RomanSt 2012年

0

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

如果您想要的是开箱即​​用的解决方案(安装并完成),则可以在此处找到免费的工具,并且可能应该继续阅读以下内容:

当前版本:1.2(.NET Framework 4.0客户端配置文件)-> 下载EvlWatcher的当前版本(免费供个人和商业使用)

1.2中的新增功能(文档中的更多信息):

  • 管理控制台
  • WCF服务模式
  • 黑名单
  • 3次打击后自动移至黑名单(默认情况下)

对于较旧的服务器(.NET Framework 2.0)

->下载简化版的EvlWatcher(免费供个人和商业使用)


0

remunda的出色脚本为起点,我添加了一个缺少的主要内容:阻止IP地址登录失败。当有人无法通过FTP登录时,Windows Server不会将IP地址记录到安全日志中,而是将“源网络地址”设置为破折号。FTP是蛮力攻击的一种非常常见的攻击媒介,因此我在他的脚本中添加了扫描当今FTP日志中是否存在多个登录失败并阻止这些IP地址的功能。

2014年2月7日更新:当我对此进行一些调整以处理所有旧的FTP日志时,我意识到当它们进行大量尝试(50,000+)时,它创建的阵列将非常庞大,并且处理速度会异常缓慢。从那以后,我已经对其进行了重写,以使其在处理FTP日志时更加高效。

我还发现,一个Windows防火墙规则中可以有多少个IP的硬限制是1000。由于该限制,我需要它在最新规则填满时自动创建新规则。现在,它会执行此操作,并且还会创建初始防火墙规则(如果您未创建自己的防火墙规则),因此唯一要做的设置是将其添加到计划程序中,以便在发生事件4625时运行。

以下是已在Windows Server 2008 R2和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
    }
}

仅供参考:对于以前没有在系统上运行Powershell脚本的用户,您需要首先打开一个新的Powershell并运行,Set-ExecutionPolicy RemoteSigned以便可以运行本地脚本。否则,您将得到一个错误:“由于在该系统上禁用了脚本的执行,因此无法加载blockattackers.ps1。”
kevinmicke 2014年

0

的脚本remuda,主编kevinmicke(2月7日21:59)没有检查FTP的控制通道,里面有我的系统(在Windows Server 2008 R2)上的自己的文件夹。另外530 11001-events未被识别,这似乎在黑客仅尝试访问控制通道时出现。因此,我在脚本中附加了几行以检查第二个FTP日志文件夹:

#此Windows Powershell脚本将自动阻止尝试登录系统的IP地址
#并失败下面使用$ int_block_limit变量或更多变量设置的次数。既扫描安全性
#日志,涵盖远程桌面和其他尝试,以及当日的FTP日志。如果$ int_block_limit
#在这两个日志中的任何一个日志上都达到限制(分别,不合并),然后将IP地址添加到
#防火墙规则。
#
#该脚本将使用以下命令自动创建一个名为“ BlockAttackers(已创建yyyy-MM-dd HH:mm:ss UTC)”的防火墙规则
#当前时间,如果名称中包含“ BlockAttackers”的名称不存在。因为那里很难
每个规则最多可以限制1000个条目(IP地址)的数量,一旦创建该规则,它也会创建名称相似的规则
已达到最新的#个限制。
#
#我建议将脚本设置为由事件4625登录审核失败触发的计划任务运行
#安全日志,或者您可以将其设置为在一定时间后(即每10分钟)运行一次。
#
#作者:
#由serverfault.com用户kevinmicke编写的大多数脚本
#serverfault.com用户remunda编写的Windows安全日志部分,它为kevinmicke提供了起点
#检查serverfault.com用户Uwe Martens添加的FTP控制通道
#
#详细信息:https://serverfault.com/questions/233222/ban-ip-address-based-on-x-number-of-unsuccessful-login-attempts


#设置失败的登录尝试次数,此后将阻止IP地址
$ int_block_limit = 3

#检查安全日志的时间窗口,当前设置为仅检查最近24小时
$ dat_time_window = [DateTime] :: Now.AddDays(-1)

#从安全日志中选择$ dat_time_window内所有$ int_block_limit审核失败(事件4625)以上的IP地址
$ arr_new_bad_ips_security_log = @()
$ arr_new_bad_ips_security_log = Get-EventLog -LogName'Security'-InstanceId 4625-$ dat_time_window之后|
    选择对象@ {n ='IpAddress'; e = {$ _。ReplacementStrings [-2]}} |
    组对象属性IpAddress |
    其中{$ _。Count -ge $ int_block_limit} |
    选择-属性名称

#获取当前时间UTC以找出当前FTP日志的文件名
$ current_date_utc =(获取日期).ToUniversalTime()

#设置今天的FTP控制通道日志文件的路径
$ str_log_file_name_control_channel =“ C:\ inetpub \ logs \ LogFiles \ FTPSVC \ u_ex” + $ current_date_utc.ToString(“ yyMMdd”)+“ .log”

#在今天的FTP控制频道日志文件中搜索“ 530 1”,以查找包含未能登录的系统IP的行,
#仅获取每行的IP,将IP按IP分组,以计算每行的尝试次数,并仅选择
#今天具有$ int_block_limit个或更多错误登录的IP
$ arr_new_bad_ips_ftp_control_channel = @()
$ arr_new_bad_ips_ftp_control_channel =选择字符串$ str_log_file_name_control_channel-模式“ 530 1” |
    ForEach-Object {$ _。Line.Substring(20,15)-replace“。*”,“”} |
    集团|
    其中{$ _。Count -ge $ int_block_limit} |
    选择-属性名称

#设置今天的FTP日志文件的路径
$ str_log_file_name =“ C:\ inetpub \ logs \ LogFiles \ FTPSVC * \ u_ex” + $ current_date_utc.ToString(“ yyMMdd”)+“ .log”

#在今天的FTP日志文件中搜索“ 530 1”,以查找包含未能登录的系统IP的行,
#仅获取每行的IP,将IP按IP分组,以计算每行的尝试次数,并仅选择
#今天具有$ int_block_limit个或更多错误登录的IP
#在FTPSVC *中,必须添加FTP服务器的ID而不是*,或者仅使用正确的日志文件夹
$ arr_new_bad_ips_ftp = @()
$ arr_new_bad_ips_ftp =选择字符串$ str_log_file_name -pattern“ 530 1” |
    ForEach-Object {$ _。Line.Substring(20,15)-replace“。*”,“”} |
    集团|
    其中{$ _。Count -ge $ int_block_limit} |
    选择-属性名称

#连接两个IP阵列(一个来自安全日志,一个来自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)

#对阵列进行排序,仅选择唯一的IP(以防在安全日志和FTP日志中同时显示一个IP)
$ arr_new_bad_ips_all_sorted = @()
$ arr_new_bad_ips_all_sorted = $ arr_new_bad_ips_all |
    Foreach对象{[string] $ _。Name} |
    选择对象唯一

#获取防火墙对象
$ firewall =新对象-comobject hnetcfg.fwpolicy2

#获取所有匹配“ BlockAttackers *”的防火墙规则
$ arr_firewall_rules = $ firewall.Rules | 其中{$ _。Name-like'BlockAttackers *'}

#如果尚不存在“ BlockAttackers *”防火墙规则,请创建一个并将其设置为变量
如果($ arr_firewall_rules -eq $ null){
    $ str_new_rule_name =“ BlockAttackers(已创建” + $ current_date_utc.ToString(“ yyyy-MM-dd HH:mm:ss”)+“ UTC)”
    “ netsh advfirewall防火墙添加规则dir =起作用=块名称= $ str_new_rule_name description =”自动创建的规则。“ enable = yes remoteip =“ 0.0.0.0” | 空空
    $ arr_firewall_rules = $ firewall.Rules | 其中{$ _。Name-like'BlockAttackers *'}
}

#将现有IP从当前“ BlockAttackers *”防火墙规则拆分为一个数组,以便我们轻松搜索它们
$ arr_existing_bad_ips = @()
foreach($ arr_firewall_rules中的$ rule){
    $ arr_existing_bad_ips + = $ rule.RemoteAddresses -split(',')
}

#清除当前被防火墙规则阻止的IP的子网掩码
$ arr_existing_bad_ips_without_masks = @()
$ arr_existing_bad_ips_without_masks = $ arr_existing_bad_ips | ForEach-Object {$ _ -replace“ /.*”,“”}

#在第115和116行中输入服务器的IP(IPv4和IPv6)。
#选择要添加到防火墙中的IP地址,但只有那些...
$ arr_new_bad_ips_for_firewall = @()
$ arr_new_bad_ips_for_firewall = $ arr_new_bad_ips_all_sorted | {
    #包含一个IP地址(例如,对于FTP登录失败的系统,安全日志中不包含空格或破折号)
    $ _。Length -gt 6-和
    #尚未在防火墙规则中
    !($ arr_existing_bad_ips_without_masks-包含$ _)-并且
    #不是本地环回
    !($ _。StartsWith('127.0.0.1'))-和
    #不属于本地子网
    !($ _。StartsWith('192.168。'))-然后
    !($ _。StartsWith('0.0。'))-和
    !($ _。StartsWith('10 .0。'))-然后
    !($ _。StartsWith('*。*。*。*'))-和
    !($ _。StartsWith('*:*:*:*:*:*'))
}

#如果有IP要阻止,请执行以下操作...
如果($ arr_new_bad_ips_for_firewall -ne $ null){
    #将日期和时间写入特定于脚本的日志文件
    [DateTime] :: Now | 外档-附加-编码utf8 C:\ inetpub \ logs \ LogFiles \ blockattackers.txt
    #将新阻止的IP地址写入日志文件
    $ arr_new_bad_ips_for_firewall | 外档-附加-编码utf8 C:\ inetpub \ logs \ LogFiles \ blockattackers.txt

    #布尔值,以确保仅在一个规则上添加新IP
    $ bln_added_to_rule = 0

    #数组一次可容纳每个规则的错误IP,因此我们可以确保添加新规则不会超过1000个IP
    $ arr_existing_bad_ips_current_rule = @()

    #对于防火墙中的每个“ BlockAttackers *”规则,请执行以下操作...
    foreach($ arr_firewall_rules中的$ rule){
        如果($ bln_added_to_rule -ne 1){
            #将现有规则中的现有IP拆分为一个数组,以便我们轻松计算它们
            $ arr_existing_bad_ips_current_rule = $ rule.RemoteAddresses -split(',')

            #如果要添加的IP数量小于1000减去规则中的当前IP数量,请将其添加到此规则中
            如果($ arr_new_bad_ips_for_firewall.Count -le(1000-$ arr_existing_bad_ips_current_rule.Count)){
                #将新IP添加到防火墙规则
                $ arr_new_bad_ips_for_firewall | %{$ rule.RemoteAddresses + =','+ $ _}

                #写下将IP添加到日志文件的规则
                回显“以上添加到Windows防火墙规则的新IP地址:” $ rule.Name | 外档-附加-编码utf8 C:\ inetpub \ logs \ LogFiles \ blockattackers.txt

                #设置布尔值,以便在添加IP时跳过任何其他规则
                $ bln_added_to_rule = 1
            }
        }
    }

    #如果其他“ BlockAttackers *”防火墙规则中没有空间,请创建一个新规则并将IP添加到其中
    如果($ bln_added_to_rule -ne 1){
        $ str_new_rule_name =“ BlockAttackers(已创建” + $ current_date_utc.ToString(“ yyyy-MM-dd HH:mm:ss”)+“ UTC)”
        “ netsh advfirewall防火墙添加规则dir =起作用=块名称= $ str_new_rule_name description =”自动创建的规则。“ enable = yes remoteip =“ 0.0.0.0” | 空空
        $ new_rule = $ firewall.rules | 其中{$ _。Name -eq $ str_new_rule_name}

        #将新IP添加到防火墙规则
        $ arr_new_bad_ips_for_firewall | %{$ new_rule.RemoteAddresses + =','+ $ _}

        #写下将IP添加到日志文件的规则
        echo“上面的新IP地址已添加到新创建的Windows防火墙规则中:” $ new_rule.Name | 外档-附加-编码utf8 C:\ inetpub \ logs \ LogFiles \ blockattackers.txt
    }
}

FTPSVC*54行的FTP日志文件夹的名称必须完整填写。在第115和116行中,必须输入服务器的IP(IPv4和IPv6),否则可能会将自己的服务器IP添加到防火墙规则中一百次。$int_block_limit我在服务器上将变量设置为1,因此脚本阻止了黑客攻击,并在两秒钟内导致了4625事件。我仍在考虑在几分钟的时间内运行4625个事件以外的脚本。当然,也有可能分开脚本,让一个脚本检查4625事件触发的4625事件,而另一个FTP日志文件夹每5或10分钟定期检查一次,即使有单独的防火墙规则也是如此。和日志文件。


-1

我为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 $_;
    }

然后,您必须将数组添加到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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.