Заборонити IP-адресу на основі X кількості невдалих спроб входу?


47

Чи можна заборонити IP-адресу після кількості X невдалих спроб входу на сервер Windows? Не до конкретного рахунку, який я вмію робити, а до цілої машини.

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


8
* nix має fial2ban ... не впевнений, чи є еквівалент / порт Windows. fail2ban.org/wiki/index.php/Main_Page
Chris Nava

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

Зробити це можна за допомогою повноважень та менеджера завдань. Це, мабуть, не ідеальне рішення, але воно працює досить добре, і у мене є близько 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, включаючи послуги терміналу). Але ви можете встановити тригер, наприклад, двічі на годину, щоб уникнути зайвого завантаження сервера.

Тригер планувальника

і після тригера запустіть скрипт powerhell. Ви також повинні встановити більш високі привілеї для запуску цього сценарію, інакше він вийде з ладу за винятком безпеки.

сценарій управління силою оболонки

Ви також можете прив’язати цей сценарій до інших подій безпеки.


1
Відмінний сценарій @remunda - дякую! Я також отримував багато 4625 з FTP, для якого журнал безпеки не має IP-адрес, тому я розширив ваш сценарій, щоб він також міг перевірити FTP-журнал поточного дня. Будь ласка, дивіться мою відповідь нижче для отримання додаткової інформації: serverfault.com/a/571903/107701
kevinmicke

Існує дуже багато випадків і кращих справ із журналами подій, реєстрацією ip-адрес тощо, якими я працював у IPBan - вільному та відкритому коді на веб-
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}

Я знаю, що цей сценарій, ймовірно, неефективний, але коли я почав працювати над цим, у мене абсолютно не було досвіду роботи із силою, тому моя здатність оптимізувати сценарії залишає бажати кращого. Однак, незважаючи на цей факт, я думав, що поділюсь цим усім, хто міг би ним скористатися.

Я вдячний Ремунді за те, що він дав мені початкову ідею, саме цей плакат наштовхнув мене на ідею використання паперів для пошуку в журналах подій.


4

Цей скрипт ґрунтується на відповіді remunda і йде трохи далі https://serverfault.com/a/397637/155102 На нього припадає правило "BlockAttackers", але ще не введені IP-адреси (що повертає "*" у вигляді рядка). Він також пише коментар до файлу журналу, щоб повідомити, коли в правило було додано IP-адресу.

Хороша порада - створити правило "BlockAttackers", яке блокує IP-адреси, АЛЕ спочатку його відключають. Потім запустіть цей скрипт один раз вручну, щоб він міг заповнити поле "RemoteAddresses" фактичними IP-адресами, які слід заблокувати. Погляньте на ці IP адреси, щоб переконатися, що нічого критичного не додано, а потім увімкніть правило брандмауера. Додайте це правило до свого брандмауера, як описано в Remunda.

Суть цього сценарію

#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, яка не залишає 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: Я не є експертом з питань оболонки, тому було б добре, якщо деякі гуру можуть виправити / покращити мій код.


1

Я використовую ts_block безкоштовно.

В основному це "програма VBScript, яка діє як раковина подій WMI для отримання подій, зареєстрованих Windows у відповідь на недійсні логотипи служб терміналів."

Здається, працює ідеально, і сценарій є простим, якщо вам потрібно його модифікувати. Ви можете дозволити йому реєструвати спроби, а потім заборонити, залежно від кількості дозволених спроб, та / або ви можете ввімкнути імена для входу в жорсткий код, до яких не хочете надавати доступ.

Мене зловили випадково додавши одне й те саме ім'я двічі, і служба просто переходить у нескінченний цикл, перезапускаючи кожні 1500 мс, але дуже легко виправити / мод, якщо ви все добре з vbs.

Мої поточні налаштування - це лише одна спроба, і ви забороняєтесь протягом 2 днів, і вхід, як-от "адміністратор", "адміністратор", "адміністратор", "гість" тощо, автоматично забороняється. Потрібно прямо змінити ip?

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


0

Ви маєте на увазі вхід на сервер / домен або вхід на веб-сайт, який працює на сервері? Якщо ви маєте на увазі вхід на сервер / домен, то відповідь - ні. У Windows немає концепції блокування ip-адрес на основі невдалої спроби входу, оскільки ip-адреси не є об'єктами безпеки. Можливо, є сторонні інструменти, які можуть це зробити, але я не знаю жодного, оскільки я ніколи не заглядав у це.


0

Якщо на вас нападає веб-сервер, ви можете встановити динамічне розширення обмежень IP-адреси . Якщо це стандартна автентифікація на сервері, то ви повинні мати змогу реалізувати ізоляцію домену та сервера, яка обмежує обсяг атак на комп’ютери, що приєдналися до домену, і може бути встановлена ​​таким чином, щоб дозволяти лише спроби систем, до яких потрібно мати доступ. сервер. У Windows запобігання жорстоких атак полягає у встановленні політики блокування облікового запису на такому рівні, як 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 (безкоштовно для особистого та комерційного використання)


0

Використовуючи чудовий сценарій remunda в якості вихідного пункту, я додав одне головне, чого бракувало: блокування IP-адрес від невдалих FTP-входів . Windows Server не записує IP-адресу до журналу безпеки, коли хтось не входить у систему через FTP, а натомість встановлює тире "Source Network Address". 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
    }
}

FYI: Для тих, хто раніше не запускав скрипт powerhell в системі, потрібно спочатку відкрити нову панель повноважень та запустити, Set-ExecutionPolicy RemoteSignedщоб ви могли запускати локальні сценарії. В іншому випадку ви отримаєте помилку: "blockattackers.ps1 не можна завантажити, оскільки виконання скриптів вимкнено в цій системі."
kevinmicke

0

Сценарій ремуди за редакцією kevinmicke (7 лютого о 21:59) не перевірив канал управління FTP, який має власну папку в моїй системі (Windows Server 2008 R2). Також 530 11001не було розпізнано події, які, здається, з’являються, коли хакер намагається отримати доступ до каналу управління. Тому я додав рядки до сценарію, щоб перевірити другу FTP-журнал-папку:

# Цей скрипт Powershell для Windows автоматично блокує 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
# Частина журналу безпеки Windows, написана користувачем remunda сервера defaultfault, яка послужила початковою точкою для кевінміке
# Перевірка каналу управління FTP, який додав користувач serverfault.com Uwe Martens
#
# Деталі: 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 -Після $ dat_time_window |
    Select-Object @ {n = 'IpAddress'; e = {$ _. ReplacementStrings [-2]}} |
    Group-Object -властивість IpAddress |
    Де {$ _. Розрахунок -ge $ int_block_limit} |
    Виберіть -ім'я власності

# Отримайте поточний час UTC, щоб визначити ім'я файлу для поточного журналу FTP
$ current_date_utc = (Дата отримання) .ToUniversalTime ()

# Встановити шлях до сьогоднішнього файлу журналу FTP Control Channel
$ 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-адресою, щоб підрахувати спроби кожного та виберіть лише те
# IP-адреси, які мають $ int_block_limit або більше поганих входів сьогодні
$ arr_new_bad_ips_ftp_control_channel = @ ()
$ arr_new_bad_ips_ftp_control_channel = Select-String $ str_log_file_name_control_channel -pattern "530 1" |
    ForEach-Object {$ _. Line.Substring (20,15) -замінити ". *", ""} |
    Група |
    Де {$ _. Розрахунок -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) -замінити ". *", ""} |
    Група |
    Де {$ _. Розрахунок -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 {[рядок] $ _. Ім'я} |
    Вибрати-Об'єкт -уніке

# Отримати об’єкт брандмауера
$ firewall = New-Object -comobject hnetcfg.fwpolicy2

# Отримати всі правила брандмауера, що відповідають "BlockAttackers *"
$ arr_firewall_rules = $ firewall.Правила | Де {$ _. Ім'я, схоже на "BlockAttackers *"}

# Якщо ще немає правила брандмауера "BlockAttackers *", створіть його та встановіть його змінну
if ($ 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 = так remoteip = "0.0.0.0" | Зовнішнє
    $ arr_firewall_rules = $ firewall.Правила | Де {$ _. Ім'я, схоже на "BlockAttackers *"}
}

# Розділіть існуючі IP-адреси з поточних правил брандмауера "BlockAttackers *" на масив, щоб ми могли їх легко шукати
$ arr_existing_bad_ips = @ ()
foreach ($ правило в $ 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')) -і
    # не входять до локальної підмережі
    ! ($ _. ПочинаєWith ('192.168.')) -І
    ! ($ _. ПочинаєWith ('0,0.')) -І
    ! ($ _. ПочинаєWith ('10 .0. ')) -І
    ! ($ _. ПочинаєWith ('*. *. *. *')) -І
    ! ($ _. ПочинаєWith ('*: *: *: *: *: *'))
}

# Якщо є 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

    # Булевий, щоб переконатися, що нові IP-адреси додаються лише за одним правилом
    $ bln_added_to_rule = 0

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

    # Для кожного правила "BlockAttackers *" у брандмауері виконайте наступне ...
    foreach ($ правило в $ 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 (Створено" + $ current_date_utc.ToString ("yyyy-MM-dd HH: mm: ss") + "UTC)"
        netsh advfirewall брандмауер додати правило dir = в дії = ім'я блоку = $ str_new_rule_name description = "Правило створено автоматично." enable = так remoteip = "0.0.0.0" | Зовнішнє
        $ new_rule = $ firewall.rules | Де {$ _. Ім'я -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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.