Запретить IP-адрес на основании количества неудачных попыток входа в систему?

47

Можно ли забанить IP-адрес после Х числа неудачных попыток входа на Windows Server? Не для конкретного аккаунта, который я умею делать, а для всей машины.

Мы очень сильно пострадали от атак грубой силы, пытаясь угадать имена пользователей, так что это действительно помогло бы получить некоторую нагрузку на сервер.

HeavyWave
источник
8
* nix имеет fial2ban ... не уверен, что есть эквивалент Windows / порт. fail2ban.org/wiki/index.php/Main_Page
Крис Нава
5
От Эвана Андерсона: serverfault.com/questions/43360/… ... выглядит хорошим эквивалентом функциональности fail2ban, но поскольку ваш вопрос недостаточно конкретен, я не знаю, хотите ли вы запретить IP-адреса, пытающиеся войти в систему на хостинг веб-сайт, ваш сервер (через SSH) или ваш домен. Разъяснение будет иметь большое значение. Кроме того, вы можете ограничить скорость на своем брандмауэре, но это зависит от реализации.
4
Возможно, вы захотите взглянуть на serverfault.com/questions/216995/… для предыдущего обсуждения того, насколько полезен автоматизированный бан на основе IP.
pehrs
1
Если вы говорите о службах терминалов / удаленном рабочем столе, посмотрите здесь: serverfault.com/a/335976/7200
Эван Андерсон,
3
Я сделал службу Windows на GitHub, чтобы сделать это: github.com/jjxtra/Windows-IP-Ban-Service
jjxtra

Ответы:

28

Вы можете сделать это с PowerShell и диспетчером задач. Вероятно, это не идеальное решение, но оно работает довольно хорошо, и у меня есть около 100 заблокированных IP-адресов за два месяца. Я написал скрипт, который выбирает из EventLog указанные события («ошибка аудита»). Если существует много неудачных входов с любого IP-адреса, он добавляется в правило брандмауэра (созданное вручную) с именем «BlockAttackers», которое блокирует любой трафик на указанные IP-адреса.

PS1 Script:

$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

Вы также можете привязать этот скрипт к другим событиям безопасности.

remunda
источник
1
Отличный скрипт @remunda - спасибо! Я также получил 4625 с FTP-сервера, для которого в журнале безопасности нет IP-адресов, поэтому я расширил ваш скрипт, чтобы он также проверял журнал FTP текущего дня. Пожалуйста, смотрите мой ответ ниже для получения дополнительной информации: serverfault.com/a/571903/107701
kevinmicke
Есть много ошибок и крайних случаев с журналами событий, регистрацией 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, поэтому моя способность оптимизировать сценарии оставляет желать лучшего. Однако, несмотря на этот факт, я подумал, что поделюсь этим с любым, кто мог бы его использовать.

Я благодарю Ремунду за то, что она дала мне первоначальную идею, что именно этот плакат заставил меня задуматься об использовании PowerShell для поиска в журналах событий.

Киган
источник
4

Этот скрипт основан на ответе remunda и идет немного дальше https://serverfault.com/a/397637/155102 Он учитывает правило «BlockAttackers», для которого еще не введены IP-адреса (который возвращает «*» в виде строки). Он также записывает комментарий в файл журнала, чтобы сообщить, когда IP-адрес был добавлен в правило.

Хороший совет - создать правило «BlockAttackers», которое блокирует IP-адреса, НО сначала отключить его. Затем запустите этот скрипт один раз вручную, чтобы он мог заполнить поле «Удаленные адреса» фактическими IP-адресами, которые должны быть заблокированы. Посмотрите на эти IP-адреса, чтобы убедиться, что ничего критического не было добавлено, а затем включите правило брандмауэра. Добавьте это правило в брандмауэр, как описано в remunda.

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-соединениях), или если вы неоднократно
неправильно набираете
18
Извините, но я не спрашивал, было ли это хорошей идеей.
HeavyWave
1
Конечно, нет причин, по которым исключения не могут быть установлены для одного или нескольких конкретных IP-адресов, что в значительной степени устранит проблему DoS.
Джон Гарденер,
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. Поэтому мне пришлось использовать 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?

Какая-то захватывающая, чтобы пойти и посмотреть, какие твари были забанены за одну ночь ...

chipbug
источник
0

Вы имеете в виду вход на сервер / домен или вход на веб-сайт, работающий на сервере? Если вы имеете в виду вход на сервер / домен, то ответ - нет. В Windows отсутствует концепция блокировки IP-адресов на основании неудачных попыток входа в систему, поскольку IP-адреса не являются объектами безопасности. Могут быть сторонние инструменты, которые могут сделать это, но я не знаю ни одного, так как никогда не обращал на это внимания.

joeqwerty
источник
0

Если существует атакуемый веб-сервер, вы можете установить расширение динамических ограничений IP . Если это для стандартной аутентификации на сервере, то вы должны иметь возможность реализовать изоляцию домена и сервера, которая ограничивала бы объем атак на компьютеры, присоединенные к домену, и могла бы быть настроена таким образом, чтобы разрешать попытки только со стороны систем, к которым вам необходим доступ. сервер. В окнах предотвращение грубых атак состоит в том, чтобы установить политику блокировки учетной записи равной 10 минутам, а политику плохого пароля - 3 попыткам - это означает, что атакующая учетная запись блокируется в течение 10 минут после 3 попыток. IP-соединения не блокируются по умолчанию в Windows. (Кроме того, мне также любопытно, сколько попыток входа в систему требуется в секунду, чтобы повлиять на систему)

Джим Б
источник
На моем маленьком экземпляре AWS 1 попытка каждые 4 секунды достаточна для загрузки 50% ЦП. Довольно дерьмо, если вы спросите меня ...
RomanSt
Вау, мне интересно, почему коэффициент использования настолько высок. Я должен сделать некоторое тестирование, чтобы увидеть, сколько попыток требуется моей виртуальной машине, чтобы зарегистрироваться.
Джим Б
Я думаю, это потому, что я не использую аутентификацию на уровне сети, поэтому при каждой попытке входа в систему пользовательский интерфейс входа в систему раскручивается, чтобы фактически представить злоумышленнику через сеанс удаленного рабочего стола. Я понимаю, почему это может быть дорого.
RomanSt
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 (бесплатно для личного и коммерческого использования)

Mastro
источник
0

Используя отличный сценарий remunda в качестве отправной точки, я добавил одну важную вещь, которой не хватало: блокировка IP-адресов от неудачных входов на FTP . Windows Server не регистрирует IP-адрес в журнале безопасности, когда кто-то не может войти в систему через FTP, но вместо этого устанавливает «Исходный сетевой адрес» на тире. FTP является очень распространенным вектором атак для атак методом "грубой силы", поэтому я добавил к его сценарию возможность сканировать журналы FTP текущего дня на наличие множества ошибок входа и блокировать эти IP-адреса.

Обновление 2014/02/07: Когда я сделал несколько настроек для обработки всех моих старых журналов FTP, я понял, что когда у них было огромное количество попыток (более 50 000), создаваемые им массивы были бы огромными и делали обработку невероятно медленной. С тех пор я переписал его, чтобы сделать его намного более эффективным при обработке журналов FTP.

Я также обнаружил, что существует произвольное жесткое ограничение в 1000 для количества IP-адресов в одном правиле брандмауэра Windows. Из-за этого ограничения мне нужно было автоматически создавать новое правило при заполнении последнего. Теперь он делает это, а также создает исходное правило брандмауэра (если вы не создаете свое собственное), так что единственная настройка, которую нужно сделать, - это добавить его в планировщик для запуска при событии 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
    }
}
kevinmicke
источник
К вашему сведению: для тех, кто не запускал скрипт powershell в системе раньше, вам нужно сначала открыть новый PowerShell и запустить его, Set-ExecutionPolicy RemoteSignedчтобы вы могли запускать локальные сценарии. В противном случае вы получите сообщение об ошибке: «blockattackers.ps1 не может быть загружен, потому что выполнение сценариев отключено в этой системе».
kevinmicke
0

Скрипт remuda , отредактированный kevinmicke (7 февраля в 21:59), не проверял канал управления FTP, который имеет собственную папку в моей системе (Windows Server 2008 R2). Также 530 11001не были распознаны события, которые появляются, когда хакер пытается получить доступ только к каналу управления. Поэтому я добавил несколько строк в скрипт, чтобы проверить вторую папку FTP-log:

# Этот скрипт Windows Powershell автоматически блокирует IP-адреса, которые пытаются войти в систему
# и потерпеть неудачу в количестве, указанном ниже с переменной $ int_block_limit или более. Сканирует как Совет
# log, который охватывает Remote Desktop и другие попытки, а также журнал FTP текущего дня. Если $ int_block_limit
Ограничение # достигнуто в любом из этих журналов (отдельно, а не вместе), тогда IP-адрес будет добавлен к
# правило брандмауэра.
#
# Сценарий автоматически создаст правило брандмауэра с именем «BlockAttackers (Создано гггг-мм-дд ЧЧ: мм: сс UTC)», используя
# текущее время, если имя с именем «BlockAttackers» еще не существует. Потому что там трудно
# ограничение в 1000 записей (IP-адресов), которое вы можете заблокировать для каждого правила, оно также создаст правила с одинаковыми именами, как только
# предел достигнут для самого последнего.
#
# Рекомендую настроить запуск сценария как запланированной задачи, вызванной сбоем аудита входа в систему события 4625 из
# Журнал безопасности, или, в качестве альтернативы, вы можете настроить его запуск через некоторое время (т.е. каждые 10 минут).
#
# Авторы:
# Большинство сценариев написано пользователем serverfault.com kevinmicke
# Часть журнала безопасности Windows, написанная пользователем remunda serverfault.com, которая послужила отправной точкой для kevinmicke
# Проверка канала управления FTP добавлена ​​пользователем serverfault.com Уве Мартенсом
#
# Подробности: 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)

# Выберите из журнала безопасности все IP-адреса, которые имеют более чем $ int_block_limit сбоев аудита (событие 4625) в пределах $ 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]}} |
    Групповой объект -свойство IpAddress |
    Где {$ _. Count -ge $ int_block_limit} |
    Выберите имя свойства

# Получить текущее время UTC, чтобы выяснить имя файла для текущего журнала FTP
$ current_date_utc = (Get-Date) .ToUniversalTime ()

# Установить путь к текущему файлу журнала канала управления FTP
$ str_log_file_name_control_channel = "C: \ inetpub \ logs \ LogFiles \ FTPSVC \ u_ex" + $ current_date_utc.ToString ("yyMMdd") + ".log"

# Найдите в сегодняшнем файле журнала FTP Control Channel значение «530 1», чтобы найти строки, содержащие IP-адреса систем, которые не смогли войти в систему,
# получить только IP-адрес из каждой строки, сгруппировать IP-адреса по IP, чтобы подсчитать количество попыток для каждой из них, и выбрать только
# IP-адреса, которые имеют $ int_block_limit или более неудачных входов в систему сегодня
$ arr_new_bad_ips_ftp_control_channel = @ ()
$ arr_new_bad_ips_ftp_control_channel = строка выбора $ str_log_file_name_control_channel -pattern "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, чтобы подсчитать количество попыток для каждой из них, и выбрать только
# IP-адреса, которые имеют $ int_block_limit или более неудачных входов в систему сегодня
# В FTPSVC * необходимо добавить идентификатор FTP-сервера вместо * или просто взять нужную лог-папку
$ arr_new_bad_ips_ftp = @ ()
$ arr_new_bad_ips_ftp = Select-String $ 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-адреса (если один IP-адрес отображается в журналах безопасности и FTP)
$ arr_new_bad_ips_all_sorted = @ ()
$ arr_new_bad_ips_all_sorted = $ arr_new_bad_ips_all |
    Foreach-Object {[string] $ _. Name} |
    Select-Object - уникальный

# Получить объект брандмауэра
$ firewall = New-Object -comobject hnetcfg.fwpolicy2

# Получить все правила брандмауэра, соответствующие "BlockAttackers *"
$ arr_firewall_rules = $ firewall.Rules | Где {$ _. Имя-как 'BlockAttackers *'}

# Если правила брандмауэра "BlockAttackers *" еще не существует, создайте его и установите для него переменную
if ($ arr_firewall_rules -eq $ null) {
    $ str_new_rule_name = "BlockAttackers (Created" + $ current_date_utc.ToString ("гггг-мм-дд ЧЧ: мм: сс") + "UTC)"
    netsh advfirewall firewall добавить правило dir = в действии = имя блока = $ str_new_rule_name description = "Правило создано автоматически." enable = yes remoteip = "0.0.0.0" | Из-Null
    $ arr_firewall_rules = $ firewall.Rules | Где {$ _. Имя-как 'BlockAttackers *'}
}

# Разделить существующие IP-адреса из текущих правил брандмауэра "BlockAttackers *" в массив, чтобы мы могли легко найти их
$ arr_existing_bad_ips = @ ()
foreach ($ rule в $ arr_firewall_rules) {
    $ 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 "/.*", ""}

# Введите IP-адрес вашего сервера (IPv4 и IPv6) в строках 115 и 116.
# Выберите IP-адреса для добавления в брандмауэр, но только те, которые ...
$ arr_new_bad_ips_for_firewall = @ ()
$ arr_new_bad_ips_for_firewall = $ arr_new_bad_ips_all_sorted | Где {
    # содержат IP-адрес (т. е. не являются пустыми или тире, которые есть в журнале безопасности для систем, которые не прошли FTP-вход)
    $ _. Длина -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-адреса, сделайте следующее ...
if ($ arr_new_bad_ips_for_firewall -ne $ null) {
    # Записать дату и время в лог-файл конкретного скрипта
    [DateTime] :: Сейчас | Out-File -Append -Encoding utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt
    # Записать недавно заблокированные IP-адреса в файл журнала
    $ arr_new_bad_ips_for_firewall | Out-File -Append -Encoding utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt

    # Boolean, чтобы убедиться, что новые IP-адреса добавляются только в одно правило
    $ bln_added_to_rule = 0

    # Массив для хранения плохих IP-адресов из каждого правила по одному, поэтому мы можем рассчитывать, чтобы добавление новых IP-адресов не превышало 1000 IP-адресов.
    $ arr_existing_bad_ips_current_rule = @ ()

    # Для каждого правила «BlockAttackers *» в брандмауэре выполните следующие действия ...
    foreach ($ rule в $ arr_firewall_rules) {
        if ($ bln_added_to_rule -ne 1) {
            # Разделить существующие IP-адреса из текущего правила в массив, чтобы мы могли легко их посчитать
            $ arr_existing_bad_ips_current_rule = $ rule.RemoteAddresses -split (',')

            # Если количество добавляемых IP-адресов меньше 1000 минус текущее количество IP-адресов в правиле, добавьте их в это правило
            if ($ 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-адреса в лог-файл
                echo "Новые IP-адреса, добавленные выше к правилу брандмауэра Windows:" $ rule.Name | Out-File -Append -Encoding utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt

                # Установите логическое значение, чтобы при добавлении IP-адресов любые другие правила были пропущены.
                $ bln_added_to_rule = 1
            }
        }
    }

    # Если в другом правиле брандмауэра «BlockAttackers *» не было места, создайте новое и добавьте в него IP-адреса.
    if ($ bln_added_to_rule -ne 1) {
        $ str_new_rule_name = "BlockAttackers (Created" + $ current_date_utc.ToString ("гггг-мм-дд ЧЧ: мм: сс") + "UTC)"
        netsh advfirewall firewall добавить правило dir = в действии = имя блока = $ str_new_rule_name description = "Правило создано автоматически." enable = yes remoteip = "0.0.0.0" | Из-Null
        $ 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 | Out-File -Append -Encoding utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt
    }
}

Имя папки журнала FTP FTPSVC*на строке 54 должно быть заполнено по причине. В строке 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)
Винс Винчи
источник