На любом хосте Windows, напрямую подключённом к Интернету, с открытым наружу портом RDP периодически будут фиксироваться попытки удаленного перебора паролей. Для эффективной защиты стандартного RDP порта
3389
от перебора паролей и эксплуатации уязвимостей рекомендуется разместить RDP сервер за VPN или шлюзом RD Gateway. Если реализовать такую схему невозможно, нужно внедрять дополнительные средства для защиты RDP:
- Не использовать стандартные имена учетных записей в Windows (если это не сделать, популярные имена учетных записей {
admin
,administrator
,user1
}будут периодически блокироваться в соответствии с настройками политики паролей Windows); - Использовать сложные политики паролей пользователей;
- Изменить стандартный RDP порт 3389 на другой;
- Настроить 2FA для RDP входа (пример настройки двухфакторной аутентификации для RDP с помощью open-source multiOTP).
В этой статье мы настроим автоматическую блокировку IP адресов, с которых выполняются неудачные попытки RDP аутентификации.
PowerShell скрипт для блокировки IP адресов-источников RDP атак
При неудачной попытке аутентификации в Windows по RDP в журнале событий Security регистрируется событие с EventID 4625 (неудачный вход —
An account failed to log on
и
LogonType = 3
, см. статью Анализ RDP логов в Windows ). В описании события указано имя пользователя, под которым выполнялась попытка подключения и IP адрес источника.
Можно вывести список таких событий с неудачными попытками входа за последний час по с помощью PowerShell командлета Get-WinEvent:$result = Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625; EndTime=(get-date).AddHours(-1)} | ForEach-Object {
$eventXml = ([xml]$_.ToXml()).Event
[PsCustomObject]@{
UserName = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
IpAddress = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'IpAddress' }).'#text'
EventDate = [DateTime]$eventXml.System.TimeCreated.SystemTime
}
}
$result
С помощью PowerShell скрипта можно анализировать этот лог, и, если с конкретного IP адреса за последние 2 часа было зафиксировано более 5 неудачных попыток входа по RDP, IP адрес будет добавлен в блокирующее правило Windows Firewall.
# количество неудачных попыток входа с одного IP адреса, при достижении которого нужно заблокировать IP $badAttempts = 5 # Просмотр лога за последние 2 часа $intervalHours = 2 # Если в блокирующем правиле более 3000 уникальных IP адресов, создать новое правило Windows Firewall $ruleMaxEntries = 3000 # номер порта, на котором слушает RDP $RdpLocalPort=3389 # файл с логом работы PowerShell скрипта $log = "c:\ps\rdp_block.log" # Список доверенных IP адресов, которые нельзя блокировать $trustedIPs = @("192.168.1.100", "192.168.1.101","8.8.8.8") $startTime = [DateTime]::Now.AddHours(-$intervalHours) $badRDPlogons = Get-EventLog -LogName 'Security' -After $startTime -InstanceId 4625 | Where-Object { $_.Message -match 'logon type:\s+(3)\s' } | Select-Object @{n='IpAddress';e={$_.ReplacementStrings[-2]}} $ipsArray = $badRDPlogons | Group-Object -Property IpAddress | Where-Object { $_.Count -ge $badAttempts } | ForEach-Object { $_.Name } # Удалить доверенные IP адреса $ipsArray = $ipsArray | Where-Object { $_ -notin $trustedIPs } if ($ipsArray.Count -eq 0) { return } [System.Collections.ArrayList]$ips = @() [System.Collections.ArrayList]$current_ip_lists = @() $ips.AddRange([string[]]$ipsArray) $ruleCount = 1 $ruleName = "BlockRDPBruteForce" + $ruleCount $foundRuleWithSpace = 0 while ($foundRuleWithSpace -eq 0) { $firewallRule = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue if ($null -eq $firewallRule) { New-NetFirewallRule -DisplayName $ruleName –RemoteAddress 1.1.1.1 -Direction Inbound -Protocol TCP –LocalPort $RdpLocalPort -Action Block $firewallRule = Get-NetFirewallRule -DisplayName $ruleName $current_ip_lists.Add(@(($firewallRule | Get-NetFirewallAddressFilter).RemoteAddress)) $foundRuleWithSpace = 1 } else { $current_ip_lists.Add(@(($firewallRule | Get-NetFirewallAddressFilter).RemoteAddress)) if ($current_ip_lists[$current_ip_lists.Count – 1].Count -le ($ruleMaxEntries – $ips.Count)) { $foundRuleWithSpace = 1 } else { $ruleCount++ $ruleName = "BlockRDPBruteForce" + $ruleCount } } } # Удалить IP адреса, которые уже есть в правиле for ($i = $ips.Count – 1; $i -ge 0; $i--) { foreach ($current_ip_list in $current_ip_lists) { if ($current_ip_list -contains $ips[$i]) { $ips.RemoveAt($i) break } } } if ($ips.Count -eq 0) { exit } # Заблокировать IP в firewall и записать в лог $current_ip_list = $current_ip_lists[$current_ip_lists.Count – 1] foreach ($ip in $ips) { $current_ip_list += $ip (Get-Date).ToString().PadRight(22) + ' | ' + $ip.PadRight(15) + ' | The IP address has been blocked due to ' + ($badRDPlogons | Where-Object { $_.IpAddress -eq $ip }).Count + ' failed login attempts over ' + $intervalHours + ' hours' >> $log } Set-NetFirewallRule -DisplayName $ruleName -RemoteAddress $current_ip_list
$badRDPlogons = Get-EventLog -LogName ...
На блок кода:
$ipPattern = '\b(?:\d{1,3}\.){3}\d{1,3}\b'
$badRDPlogons = @()
$events = Get-WinEvent -FilterHashTable @{LogName='Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational';ID='140';StartTime=$startTime}
$events.message | ForEach-Object {
if ($_ -match $ipPattern) {
$ipObject = [PSCustomObject]@{
IpAddress = $matches[0]
}
$badRDPlogons += $ipObject
}
}
После запуска PoweShell скрипт создаст правило в Windows Defender Firewall, которое заблокирует подключение к RDP порту для полученного списка IP адресов.
В лог файл скрипт PowerShell будет записывать список заблокированных IP:
Чтобы скачать PS1 скрипт с GitHub на локальный диск, выполните:
$path = "C:\PS\" If(!(test-path -PathType container $path)) { New-Item -ItemType Directory -Path $path } $url = "https://raw.githubusercontent.com/winadm/posh/master/RemoteDesktop/block_rdp_attack.ps1" $output = "$path\block_rdp_attack.ps1" Invoke-WebRequest -Uri $url -OutFile $output
Можно запускать скрипт автоматически при появлении в логе события 4625. Такое задание планировщика можно создать с помощью PowerShell скрипта:
$taskname="BlockRDPBruteForce_Attack_PS"
$scriptPath="C:\PS\block_rdp_attack.ps1"
$triggers = @()
$triggers += New-ScheduledTaskTrigger -AtLogOn
$CIMTriggerClass = Get-CimClass -ClassName MSFT_TaskEventTrigger -Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskEventTrigger
$trigger = New-CimInstance -CimClass $CIMTriggerClass -ClientOnly
$trigger.Subscription =
@"
<QueryList><Query Id="0" Path="Security"><Select Path="Security">*[System[(EventID=4625)]]</Select></Query></QueryList>
"@
$trigger.Enabled = $True
$triggers += $trigger
$User='Nt Authority\System'
$Action=New-ScheduledTaskAction -Execute "Powershell.exe" -Argument "-NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -File $scriptPath"
Register-ScheduledTask -TaskName $taskname -Trigger $triggers -User $User -Action $Action -RunLevel Highest -Force
Задание будет запускаться при каждом неудачном RDP входе, анализировать журнал событий и блокировать IP адреса. Задание запускается от имени System и не зависит от того, выполнени ли вход пользователем или нет.
disable-NetFirewallRule -DisplayName "BlockRDPBruteForce"
Мы ж таким образом отключаем правило….
Фенкс ) Скопировал код из черновика. Убрал эту строку.
Благодарю! Очень полезный скрипт. У нас на Windows VDS сервере постоянно идет долбежка с подбором паролей по RDP.
Один вопрос: можно вести лог событий блокировки IP для дальнейшего разбора полетов?
Добавил в скипт логирование. В резульатте в файле C:\ps\blocked_ip.txt у вас должны появляться строки вида:
10/3/2019 7:46:52 AM 192.168.1.11 IP заблокирован за 15 попыток за 2 часа
10/3/2019 7:46:52 AM 192.168.255.60 IP заблокирован за 7 попыток за 2 часа
Вот. Вот. Очень знакомый сценарий. Это называется Soft Lock в Cyberarms Intrusion Detection and Defense Software (IDDS) 🙂
А дальше, для особо «ретивых», включается Hard Lock, то сть IP уже не удаляется из списка заблокированных в Windows Firewall.
Так же хотел использовать для данных целей IDDS. Но он к сожалению никак не реагирует на попытки подбора пароля. Есть подозрение что IDDS ищет в журнале события на английском языке, в то время как у меня сервер на русском. Или версия сервера устаревшая. Использую еще 2008 R2.
Не могли бы Вы поделиться своим опытом настроили IDDS. Или толковым мануалом
для 2008r2 есть RdpGuard
Была такая хорошая штука как EvlWatcher, но более не разрабатывается, увы
Подскажите, если в журнале Security замечены попытки брутфорса, но не регистрируется удаленный IP. Поле пустое. Как защищаться в таком случае?
Аудит доступа включен? События с отказом в доступе с EventID 4652 в журнале есть? Покажите, что в них содержится. Вожмноу вас там фигурируют имена удаленных хостов.
Столкнулся с такой же проблемой на server 2012r2. На 16-19 всё норм. Может кому то удалось это победить?? В сети ответа не нашёл….
Учетной записи не удалось выполнить вход в систему.
Субъект:
ИД безопасности: NULL SID
Имя учетной записи: —
Домен учетной записи: —
Код входа: 0x0
Тип входа: 3
Учетная запись, которой не удалось выполнить вход:
ИД безопасности: NULL SID
Имя учетной записи: NIKITA
Домен учетной записи:
Сведения об ошибке:
Причина ошибки: Неизвестное имя пользователя или неверный пароль.
Состояние: 0xC000006D
Подсостояние: 0xC0000064
Сведения о процессе:
Идентификатор процесса вызывающей стороны: 0x0
Имя процесса вызывающей стороны: —
Сведения о сети:
Имя рабочей станции: —
Сетевой адрес источника: —
Порт источника: —
Сведения о проверке подлинности:
Процесс входа: NtLmSsp
Пакет проверки подлинности: NTLM
Промежуточные службы: —
Имя пакета (только NTLM): —
Длина ключа: 0
Попробуйте мой, я переделал на другой журнал событий — ‘Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational’;ID=’140′, там ip есть, и нету зависимости от языка системы
if($null -eq (Get-NetFirewallRule -DisplayName BlockRDP -ErrorAction SilentlyContinue)){New-NetFirewallRule -DisplayName "BlockRDP" –RemoteAddress 1.1.1.1 -Direction Inbound -Protocol TCP –LocalPort 3389 -Action Block}
#за сколько времени
$Hours = 1
$Last_n_Hours = [DateTime]::Now.AddHours(-$Hours)
$badRDPlogons = Get-WinEvent -FilterHashTable @{LogName='Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational';ID='140';StartTime=$Last_n_Hours}
# берем 30 и больше неудачных входов
$getip = $badRDPlogons.Properties | group-object -property value | where {$_.Count -gt 30} | Select -property Name
$log = "C:\blocked_ip_rdp.txt" # лог файл
$current_ips = (Get-NetFirewallRule -DisplayName "BlockRDP" | Get-NetFirewallAddressFilter ).RemoteAddress -split(',')
for($i = 0; $i -lt @($getip).Count; $i++) {
$current_ips += $getip[$i].name.Trim()
(Get-Date -Format G) + ' ' + $getip[$i].name + ' IP заблокировано за ' + ($badRDPlogons.Properties | where {$_.Value -eq $getip[$i].name}).count + ' неудачных попыток за ' + $Hours + 'ч.'>> $log
}
Set-NetFirewallRule -DisplayName "BlockRDP" -RemoteAddress $current_ips
## Приветствую
## Вот педали из моего велосипеда
## И тут нет сложностей с языком системы
## Привожу кусок, так как остальное отличается от ваших самокатов тем, что блокирует адреса на Mikrotik
$interval = 600000; #600000ms = 10min
# фильтр событий в журнале
$XPath = "*[System[Provider[@Name=""Microsoft-Windows-Security-Auditing""]
and Task = 12544
and (band(Keywords,4503599627370496))
and (EventID=4625)
and TimeCreated[timediff(@SystemTime) <= $interval]]]";
$list_IP =@();
$Events = @();
# выбираем события
try { $Events = Get-WinEvent -Logname "security" -FilterXPath $XPath -ErrorAction Stop
}
catch [Exception] {
if ($_.Exception -match "Не удалось найти события, соответствующие указанному условию выбора.") {
Write-Host "Не найдены события перебора паролей за последние $($interval/60000) мин.";
exit;
}
}
# выбираем IP адреса
$list_IP = $Events | ForEach-Object {
([xml]$_.ToXML()).Event.EventData.Data | Where-Object {$_.Name -eq "IpAddress"} | ForEach-Object {$_."#text"}} | Where-Object {$_ -ne "-" };
это всё хорошо, но что делать ддя защиты от постоянно обнаруживаемых уязвимостях в протоколе RDP, когда для взлома используют другие методы, помимо грубого подбора? для своих клиентов мы давно практикуем доступ извне исключительно через VPN…
Обновляться. 80-90% эксплойтов создано после выхода патча на уязвимость. А 100% гарантии не даст никто и ничто.
Это защита от придурков, конечно же. От школьников-студентов которым попался скрипт и база для перебора «стандартных» логинов-паролей, которые настроили такие же школьники-студенты без мозгов. Отшибание на входе, по IP, попросту разгружет сам RDP и систему авторизации. Я подобный «контингент» отрезаю на уровне железного
fierwall , а с другими уязвимостями, боремся\ соответствующими методами.
VPN — единственно правильный вариант защиты от подбора паролей через RDP. Если совсем никак не получается реализовать VPN — ставить блокировку учетной записи при неправильном вводе пароля, например 5 раз на 30 минут — помогает, хотя это и не полноценное решение.
Не надо так категорично.
1 — VPN тоже не всегда хорошо, именно потому, что в большинстве случаев предоставляет доступ в сеть по множеству протоколов. Внешние подрядчики (или сотрудники) + шифровальщики на их ПК + доступ по SMB = ваша дополнительная работа.
2 — блокировка именно учётных записей … ну-у-у … а вот например я хулиган, у которого есть частичный список ваших учёток и я начинаю тупо на них ломиться именно с той самой целью — чтобы они заблокировались и ваши сотрудники перестали работать, тогда что?
ReverseProxy / Callback / FailToBan и т.п. придумали не просто так.
Почему не сделать такой функционал «на интернет-шлюзе с Linux» и сразу на все проброшенные порты, например?
Там это всё как-бы штатный функционал…
А зачем (Лялих) Linux? В игрушки поиграться? :—) Если уж делать полноценно, то на FreeBSD 🙂 Но статья не об этом, если вы не заметили. 🙂
Ок, готов посмотреть на Ваше архитектурное решение, когда linux аналзирует access логи с Windows и блокирует доступ в FW в зависимости от успешности аутентфикации по RDP.
Почему-то кажется, что это будет тот еще костыль.
И еще добавлю. Авторизация через Linux в AD/ Просто не делал никогда. Ввиду нецелесообразности. Вот FreeBSD, да. Да и то если заказчик ну очень попросит.
V согласен с тем, что руководство, как правило, идет по пути наименьшего сопротивления, особенно в малом бизнесе. Нанимать отдельно линуксоида, для реализации? Нет. Брать на время фрилансера, ну может быть. Но учитывая и зависимость от него в дальнейшем. А им оно надо?
По моему опыту, линуксоиды не очень тянут в Windows, а как не крути, офисы рботают на Windows/Office на 99.9% Поэтому нужно два админа. Один из которых линуксоид, … который слабо окупается.
Есть отличная и уже бесплатная программа
Cyberarms Intrusion Detection and Defense Software (IDDS)
Делает ровно тоже самое — набмивает Windows Firewall блокированными IP
Работает не только с RDP, но и может отслеживать:
-FTP
— TLS/SSL
— RRAS — Routing and Remote Access
— Kerberos pre-authentication
— AD Credential Validation
— Windows Base
— FileMaker
— SMTP
— SQL Server
Хотя, в качестве пособия по PS, статья годная 🙂
Не PS, конечно же, а VisualBasic, который ходит в логи 🙂
Странное приложение. Сразу после установки и запуска логин в систему с амазоновского айпишника.
Похоже удобнее распространять это приложение, чем брутфорсить.
Странный комментарий. Использую и не тлько я. Работает. А что вы называете «логин в систему с амазоновского айпишника». Или вы только после запуска приложения заметили дыу в защите? Если защита была.
Это все хорошо, но какого черта вообще рдп смотрит туда где могут подбирать пароль?
А как вы себе, «иначе» (не глядя) представляете авторизацию на RDP?
А «дятлы», которые долбятся с брутфорсом, всегда были, есть и будут.
Особенно сейчас. Все вокруг «кул хацкеры», насмотревшись видосов на YouTube и начитавших «хацкерских» форумов. Возрастная категория, этих придурков, от 12 до 20 лет.
скажу за Евгения, хоть и не принято встревать: можно (многие, как и я, скажут «нужно») делать доступ по RDP через VPN подключение, клиент vpn всегда подключен к серверу, но трафик туда не завёрнут, клиент rdp подключается по локальному адресу, часто отключают доступ ко всему, кроме ip сервера терминалов при подключении, т.е. доступ к ресурсам внутренней сети возможен только внутри RDP сессии, это всё обычные практики
«Как надо» и без вас понятно. 🙂
Была рассмотрена вполне конкретная ситуация.
Как я написал выше, это «пособие по VB и анализу лог-файлов и работе с Windows firewall.
Мне приходилось отказываться «сделать через VPN» потому что я устал
объяснять «топеам» — «почему не работает?» и из какого места растут руки у их детей-вундеркиндов. И по сто рах, снова и снова,
перенастраивать их ноутбуки.
RDP выставлять в интернет это плохо, но не все готовы себе разворачивать VPN или RD Web Access. По крайней мере в малом бизнесе не все готовы себе даже лицензию на Windows Server купить. Поэтому такая семы будет сплошь и рядом.
И я не говорю, что RDP из интернета это правильно. Статья это пример анализа логов и реагирования на события на файерволе из PowerShell.
Используем RDPGuard, работает нормально. Ну а скрипт однозначно мастхэв
Не эксперт по powershell, но у меня скрипт не работает.
Что такое foreach ($ip in $iparr)? $iparr нету ж такой переменной..
Для себе переделал в такой:
$Last_n_Hours = [DateTime]::Now.AddHours(-2)
$badRDPlogons = Get-EventLog -LogName ‘Security’ -after $Last_n_Hours -InstanceId 4625 | ?{$_.Message -match ‘logon type:\s+(3)\s’} | Select-Object @{n=’IpAddress’;e={$_.ReplacementStrings[-2]} }
$getip = $badRDPlogons | group-object -property IpAddress | where {$_.Count -gt 3} | Select -property Name
$log = «D:\blocked_ip_rdp.txt»
$current_ips = (Get-NetFirewallRule -DisplayName «BlockRDP» | Get-NetFirewallAddressFilter ).RemoteAddress -split(‘,’)
#смотрим нету ли такого ip уже заблоченого
$ip = $getip | where {$getip.Name.Length -gt 1 -and !($current_ips -contains $getip.Name) }
$ip|%{
$current_ips += $ip.name
(Get-Date).ToString() + ‘ ‘ + $ip.name + ‘ IP заблокирован за ‘ + ($badRDPlogons | where {$_.IpAddress -eq $ip.name}).count + ‘ попыток за 2 часа’>> $log # запись события блокировки IP адреса в лог файл
}
Set-NetFirewallRule -DisplayName «BlockRDP» -RemoteAddress $current_ips
Да, была ошибка в скрипте. Поправил.
За ваш вариант спасибо )
Спасибо, работает. Только для русской версии ОС надо кодировку 1251 (а то у меня не работало, и никак не мог понять почему). Сделал вариант с автоматическим выбором языка. Ну и добавил настройку порта.
# Кодировка - Windows 1251, если ОС русской версии
# номер порта RDP
$RDPPort = "45678"
# Сначала создадим на компьютере правило брандмауэра, которое блокирует входящее RDP подключение с определённых IP адресов:
# В дальнейшем в это правило мы будем добавлять IP адреса, с которых фиксируется попытки подбора паролей по RDP.
$RDPRule = Get-NetFirewallRule -DisplayName "Block RDP Attack"
if ($RDPRule -eq $null) { New-NetFirewallRule -DisplayName "Block RDP Attack" –RemoteAddress 1.1.1.1 -Direction Inbound -Protocol TCP –LocalPort $RDPPort -Action Block }
# можете запускать скрипт PowerShell при появлении события 4625 в журнале, таким образом вы будете более быстро реагировать на атаку подбора пароля по RDP.
$Last_n_Hours = [DateTime]::Now.AddHours(-2)
$Log = "C:\Windows\Block-RDP-Attack.log"
$OSLang = (Get-WmiObject Win32_OperatingSystem).OSLanguage
switch ($OSLang) {
1049 { $badRDPlogons = Get-EventLog -LogName 'Security' -after $Last_n_Hours -InstanceId 4625 | ? { $_.Message -match 'Тип входа:\s+(3)\s' } | Select-Object @{n = 'IpAddress'; e = { $_.ReplacementStrings[-2] } } }
1033 { $badRDPlogons = Get-EventLog -LogName 'Security' -after $Last_n_Hours -InstanceId 4625 | ? { $_.Message -match 'logon type:\s+(3)\s' } | Select-Object @{n = 'IpAddress'; e = { $_.ReplacementStrings[-2] } } }
}
$getip = $badRDPlogons | group-object -property IpAddress | where { $_.Count -gt 10 } | Select -property Name
$current_ips = (Get-NetFirewallRule -DisplayName "Block RDP Attack" | Get-NetFirewallAddressFilter ).RemoteAddress -split (',')
# смотрим нет ли такого IP среди заблокированных
$ip = $getip | where { $getip.Name.Length -gt 1 -and !($current_ips -contains $getip.Name) }
$ip | % {
$current_ips += $ip.name
(Get-Date).ToString() + ' ' + $ip.name + ' IP заблокирован за ' + ($badRDPlogons | where { $_.IpAddress -eq $ip.name }).count + ' попыток за 2 часа.' >> $Log
}
Set-NetFirewallRule -DisplayName "Block RDP Attack" -RemoteAddress $current_ips
Доступ снаружи — ТОЛЬКО по VPN, никаких пробросов портов + блокировка учетных записей при неправильном вводе паролей более 5 раз на 30 минут.
Какие вы категоричные. Всякие ситуации бывают, по статье есть что сказать?
Вопрос в том, что адреса, с которых идут атаки, меняются в очень широком диапазоне — я пробовал их анализировать, так что сама идея блокировки по адресам — это лечение последствий, а не болезни. Закрыть саму идею проброса RDP и запускать пользователей только по VPN.
Я хотел б посмотреть на вас, как вы будете поддержывать работу RDP через VPN для +500 пользователей(онлайн ~150), с разношерстной техникой, за NAT-ами. Что б все стабильно работало, что б у пользователя на компьютере интернет не пропадал и не ходил через vpn канал, и т. д.
Смена порта RDP уже отсекает в большенстве случаев все попытки мамкиных хакеров. На остальное как раз нужет такой скрипт для подстраховки, ну и + в домене контроль сложности пароля, блокировка неудачного входа, +установка обновлений, антивирус, software restriction policies никто не отменял
Как вариант при таком количестве — реализовать VPN сервер аппаратно на сетевом оборудовании, и про всё остальное не забывать. Проброс портов — не лучшее решение, только для небольших сетей.
Ну и вообще отредактированный отдебаженный скрипт, работающий на Windows 2012R2:
$Last_n_Hours = [DateTime]::Now.AddHours(-2)
$log = "C:\Security\blocked_ip_rdp.txt"
$badRDPlogons = Get-EventLog -LogName 'Security' -after $Last_n_Hours -InstanceId 4625 | ?{$_.Message -match 'Тип входа:\s+(3)\s'} | Select-Object @{n='IpAddress';e={$_.ReplacementStrings[-2]} }
$getip = $badRDPlogons | group-object -property IpAddress | where {$_.Count -gt 5} | Select -property Name
#$getip>$log
$current_ips = (Get-NetFirewallRule -DisplayName "BlockRDPBruteForce" | Get-NetFirewallAddressFilter ).RemoteAddress -split(",")
foreach ($ip in $getip)
{
if ($ip.name -and $ip.name -ne "-" -and !($current_ips -contains $ip.Name)) {
$current_ips += $ip.name
# Write-Output $ip.name
(Get-Date).ToString() + ' ' + $ip.name + ' IP заблокирован за ' + ($badRDPlogons | where {$_.IpAddress -eq $ip.name}).count + ' попыток за 2 часа'>> $log # запись события блокировки IP адреса в лог файл
}
}
#Write-Output "---------------------------------"
#Write-Output $current_ips
Set-NetFirewallRule -DisplayName "BlockRDPBruteForce" -RemoteAddress $current_ips
Вывод в терминале после первого выполнения:
C:\Security>powershell .\block_ip_rdp.ps1
37.29.118.68
168.228.182.73
186.91.168.99
185.81.152.124
———————————
1.1.1.1
37.29.118.68
168.228.182.73
186.91.168.99
185.81.152.124
Вывод в терминале после второго выполнения:
C:\Security>powershell .\block_ip_rdp.ps1
———————————
1.1.1.1
37.29.118.68
168.228.182.73
186.91.168.99
185.81.152.124
Как я понял, это скрипт для русской версии Windows Server, где в событии 4625 вместо «logon type» пишется «Тип входа»
Спасибо! Как раз зашёл запостить свой вариант. Оказалось он такой же как у вас ))
Топикстартеру спасибо за направление мысли
А у меня не пошел. Матерится вот тут
PS C:\Windows\system32> $current_ips = (Get-NetFirewallRule -DisplayName «BlockRDPBruteForce» | Get-NetFirewallAddr
lter ).RemoteAddress -split(«,»)
Get-NetFirewallRule : No MSFT_NetFirewallRule objects found with property ‘DisplayName’ equal to ‘BlockRDPBruteForc
Verify the value of the property and retry.
At line:1 char:17
+ $current_ips = (Get-NetFirewallRule -DisplayName «BlockRDPBruteForce» | Get-NetF …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (BlockRDPBruteForce:String) [Get-NetFirewallRule], CimJobException
+ FullyQualifiedErrorId : CmdletizationQuery_NotFound_DisplayName,Get-NetFirewallRule
Вы не создали правило BlockRDPBruteForce:
New-NetFirewallRule -DisplayName "BlockRDPBruteForce" –RemoteAddress 1.1.1.1 -Direction Inbound -Protocol TCP –LocalPort 3389 -Action Block
Подскажите, плиз, если в логах безопасности не видно IP того, кто пытается подключится?
Какая версия Windows, язык?
Вручную события по коду удалось найти? Что в них вообще есть? Пришлите содержимое.
WinServer 2012 RU, события в журнале есть, но вот IP можно увидеть только при успешной авторизации, в противном случае видно только логин, под которым пытались залогиниться, IP не видно.
4625
0
0
12544
0
0x8010000000000000
1010715
Security
parus
—
S-1-0-0
—
—
0x0
S-1-0-0
VANAF
0xc000006d
%%2313
0xc0000064
3
NtLmSsp
NTLM
—
—
0
0x0
—
—
—
4625
0
0
12544
0
0x8010000000000000
1010715
Security
parus
-
S-1-0-0
-
-
0x0
S-1-0-0
VANAF
0xc000006d
%%2313
0xc0000064
3
NtLmSsp
NTLM
-
-
0
0x0
-
-
-
EventData
SubjectUserSid S-1-0-0
SubjectUserName —
SubjectDomainName —
SubjectLogonId 0x0
TargetUserSid S-1-0-0
TargetUserName VANAF
TargetDomainName
Status 0xc000006d
FailureReason %%2313
SubStatus 0xc0000064
LogonType 3
LogonProcessName NtLmSsp
AuthenticationPackageName NTLM
WorkstationName
TransmittedServices —
LmPackageName —
KeyLength 0
ProcessId 0x0
ProcessName —
IpAddress —
IpPort —
Хотел XML вставить, а он его как теги HTML воспринимает, по удаляйте лишнее плиз
Подскажите, плиз, если в логах безопасности не видно IP того, кто пытается подключится?
Это очень актуально….. блокировка по открытому IP уже не актуально, те кто этим занимаются давно скрывают эту информацию как быть в таком случае????
Вот таких подборов бесконечно много…… :
Учетной записи не удалось выполнить вход в систему
Субъект:
ИД безопасности: NULL SID
Имя учетной записи: —
Домен учетной записи: —
Код входа: 0x0
Тип входа: 3
Учетная запись, которой не удалось выполнить вход:
ИД безопасности: NULL SID
Имя учетной записи: BUHGALTER
Домен учетной записи:
Сведения об ошибке:
Причина ошибки: Неизвестное имя пользователя или неверный пароль.
Состояние: 0xc000006d
Подсостояние: 0xc0000064
Сведения о процессе:
Идентификатор процесса вызывающей стороны: 0x0
Имя процесса вызывающей стороны: —
Сведения о сети:
Имя рабочей станции:
Сетевой адрес источника: —
Порт источника: —
Сведения о проверке подлинности:
Процесс входа: NtLmSsp
Пакет проверки подлинности: NTLM
Промежуточные службы: —
Имя пакета (только NTLM): —
Длина ключа: 0
Данное событие возникает при неудачной попытке входа. Оно регистрируется на компьютере, попытка доступа к которому была выполнена.
Поля «Субъект» указывают на учетную запись локальной системы, запросившую вход. Обычно это служба, например, служба «Сервер», или локальный процесс, такой как Winlogon.exe или Services.exe.
В поле «Тип входа» указан тип выполненного входа. Наиболее распространенными являются типы 2 (интерактивный) и 3 (сетевой).
В полях «Сведения о процессе» указано, какая учетная запись и процесс в системе выполнили запрос на вход.
Поля «Сведения о сети» указывают на источник запроса на удаленный вход. Имя рабочей станции доступно не всегда, и в некоторых случаях это поле может оставаться незаполненным.
Поля сведений о проверке подлинности содержат подробные данные о конкретном запросе на вход.
— В поле «Промежуточные службы» указано, какие промежуточные службы участвовали в данном запросе на вход.
— Поле «Имя пакета» указывает на подпротокол, использованный с протоколами NTLM.
— Поле «Длина ключа» содержит длину созданного ключа сеанса. Это поле может иметь значение «0», если ключ сеанса не запрашивался.
Ещё раз — закрыть RDP снаружи, и пусть подбирают до потери пульса, доступ исключительно через VPN.
Отключите LM и NTLM входы через политику. Оставьте только NTLMv2
Локальная политика безопасности -> Локальные политики -> Параметры безопасности -> Сетевая безопасность: ограничения NTLM: входящий трафик NTLM -> Запретить все учетные записи
Смотрите здесь еще:
https://winitpro.ru/index.php/2019/03/13/otklyuchenie-ntlm-autentifikacii-v-domene-ad/
На входе linux в минимальной конфигурации и hashlimit на new соединения. Всё.
Спасибо за статью! выполнил, скрипты но у меня ничего не появилось (добавилось только правило в брандмауэре ). Windows Server2019RU
Скрипт в статье для Eng версии windows. См. в комментах рабочий скрипт по блокировке IP в RU версии. Также можете для начала проверить, что у вас в журнале Безопасность появляются события с кодом 4625.
Есть такая крутая программка RDP Defender (бесплатная). Блокирует подборщиков с помощью стандартного файрвола. Есть белый список. Можно указать кол-во неудачных попыток ввода пароля.
Благодарю!!
К сожалению, он бессилен, если дятел скрыл свой iP.
да, уже вижу ((( продолжают бомбить и рдп-дефендер не помогает.. да и скрипты из топика вряд ли помогут, или нет?
Защита от подбора пароля делается средствами системы за минуту — зачем для этого программа? Белый список можно и нужно сделать на раутере/прокси, естественно, с перенаправлением на нестандартный порт — что крутого в программе?
Yaromax, Вы про какой метод?
Общий комментарий.
Количество идиотов-пионеров, пытающихся всякими кул-хацкерными» программами «пробить RDP» растет непрерывно. Замена стандартного порта 3389 на лругой, помогает, но только от совсем уж «клинических недо-хаЦкеров».
Есть большой и длительный опыт использования подобной блокировки. Из опыта, примерно через год, Windows начинал сильно тормозить. Причина — переполненное правило Windows Firewall
Поэтому способ хорош, но лишь как «промежуточный».
Я делаю так. Собираю это правило Windows Firewall примерно неделю, а потом, скриптом (или как вам удобнее), переношу IP адреса в Black List железного роутера.
Какие кул хацкеры о чем вы говорите любой публичный IP используемый на предприятии проходит последовательные переборы портов определяет какие сервисы на каком порту и затем ведется перебор по всем сервисам. После блокировки зловредных IP он тут же меняется.
Есть наверное смысл брать IP отсюда _https://www.abuseipdb.com/ и сразу их добавлять в основной файрвол. Но не все а первую 1000 с наивысшим рейтингом. Потому что есть минусы как у всех подобных сервисов.
приветствую всех! Спасибо за статью, очень актуально. server 2016 en с русской локализацией. сработал скрипт только от Владимир 23.11.2019
ip уже в блокирующем правиле, но продолжается сыпаться лог 4625.
Переключаемся на использование NTLMv2 —
выполнил
Подскажите плиз, куда копать?
Учетной записи не удалось выполнить вход в систему.
Субъект:
ИД безопасности: NULL SID
Имя учетной записи: —
Домен учетной записи: —
Код входа: 0x0
Тип входа: 3
Учетная запись, которой не удалось выполнить вход:
ИД безопасности: NULL SID
Имя учетной записи: administrator
Домен учетной записи:
Сведения об ошибке:
Причина ошибки: Неизвестное имя пользователя или неверный пароль.
Состояние: 0xC000006D
Подсостояние: 0xC0000064
Сведения о процессе:
Идентификатор процесса вызывающей стороны: 0x0
Имя процесса вызывающей стороны: —
Сведения о сети:
Имя рабочей станции: —
Сетевой адрес источника: 182.69.101.242
Порт источника: 56349
Сведения о проверке подлинности:
Процесс входа: NtLmSsp
Пакет проверки подлинности: NTLM
Промежуточные службы: —
Имя пакета (только NTLM): —
Длина ключа: 0
У меня rdp порт открыт только разрешённому списку ip, там десяток адресов. С других адресов зайти не могу. Это было даже до скрипта. Почему тогда виндоус позволяет себя бомбить? или у меня это подпор не по rdp происходит?
Сетевой адрес источника: 182.69.101.242 — заблокировать на прокси или раутере.
эти адреса обрабатывает скрипт, добавляет их в черный список. вопрос в другом: почему есть эти логи\попытки входа, если у меня закрыт рдп порт(открыт только для своих)? и значит ли этот лог, что пытаются войти через рдп? может как-то можно закрыть даже возможность этих входов?
Это хорошо, когда так можно сделать.
А если сотрудники на удаленке, в командировке когда IP «плавает»?
Пробовал сделать подключение через VPN, но … дома у сотрудников такой «зоопарк», что пришлось отказаться от этой, правильной идеи.
Да и тяжко объяснять каждому и настраивать. Напомню, компьютеры домашние.
В итоге тем, кто постоянно ездит в командировки, купил и настроил ноуты, остальные ходят просто на RDP.
Здравствуйте.
При создании задания в планировщике Windows Server 2019 через указанный скриптn такая ошибка
Register-ScheduledTask : XML-код задачи содержит значение в неправильном формате или за пределами допустимого диапазона.
(8,42):Duration:P99999999DT23H59M59S
строка:6 знак:1
+ Register-ScheduledTask -TaskName «BlockRDPBruteForce_PS» -Trigger $Tr …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (PS_ScheduledTask:Root/Microsoft/…S_ScheduledTask) [Register-ScheduledTask], CimExcept
ion
+ FullyQualifiedErrorId : HRESULT 0x80041318,Register-ScheduledTask
Что это может значить? На Windows Server 2016 такого не было
В ручную создать задание получилось, но не понятно, почему на скрипт ошибка
Как будто проблема с форматом времени.
Добрый день.
А как можно добавить в скрипт исключения для определенных ip адресов, в том числе для диапазона?
Столкнулся со следующей проблемой:
К примеру пытаешься подключиться к серверу по шаре, он запрашивает логин и пароль, но в этот момент на сервере в журнале Безопасность уже появляется Аудиты отказа. В результате срабатывания скрипта, блокируется ip. Получается косяк. Хотелось бы свои статические адреса поставить в исключение.
Задайте дипазон разрешенных IP адресов:
$AllowIPrange = "192.168.1.0-192.168.1.15"
$AllowIPStart,$AllowIPEnd = $AllowIPrange.Split("-")
Потом проверяете входит ли $getip в этот диапазон:
if (($getip -ge $AllowIPStart) -AND ($getip -le $AllowIPEnd))
{
write-host "Данный IP в доверенных"
}
else{
Write-Host "Недоверенный IP"
.......# добавление IP в заблокированные в файерволе
}
Добрый день. Мне нужно дабить несколько адресов, а не Диапазон.
1) Ниже, я скопировал скрипт, как его можно изменить и добавить исключения?
2) Вопрос, в скрипте есть строки для проверки наличие Ip в списке блокировки, т.е. которые уже присутствуют в правиле, чтобы их не добавлять по новой. Но это почему-то не работает. Открываю правило «Block RDP Attack», а там есть адреса, которые задублированные.
$RDPRule = Get-NetFirewallRule -DisplayName «Block RDP Attack»
if ($RDPRule -eq $null) { New-NetFirewallRule -DisplayName «Block RDP Attack» –RemoteAddress 1.1.1.1 -Direction Inbound -Protocol TCP –LocalPort $RDPPort -Action Block }
$Last_n_Hours = [DateTime]::Now.AddHours(-2)
$Log = «C:\Windows\Block-RDP-Attack.log»
$OSLang = (Get-WmiObject Win32_OperatingSystem).OSLanguage
switch ($OSLang) {
1049 { $badRDPlogons = Get-EventLog -LogName ‘Security’ -after $Last_n_Hours -InstanceId 4625 | ? { $_.Message -match ‘Тип входа:\s+(3)\s’ } | Select-Object @{n = ‘IpAddress’; e = { $_.ReplacementStrings[-2] } } }
1033 { $badRDPlogons = Get-EventLog -LogName ‘Security’ -after $Last_n_Hours -InstanceId 4625 | ? { $_.Message -match ‘logon type:\s+(3)\s’ } | Select-Object @{n = ‘IpAddress’; e = { $_.ReplacementStrings[-2] } } }
}
$getip = $badRDPlogons | group-object -property IpAddress | where { $_.Count -gt 10 } | Select -property Name
$current_ips = (Get-NetFirewallRule -DisplayName «Block RDP Attack» | Get-NetFirewallAddressFilter ).RemoteAddress -split (‘,’)
$ip = $getip | where { $getip.Name.Length -gt 1 -and !($current_ips -contains $getip.Name) }
$ip | % {
$current_ips += $ip.name
(Get-Date).ToString() + ‘ ‘ + $ip.name + ‘ IP заблокирован за ‘ + ($badRDPlogons | where { $_.IpAddress -eq $ip.name }).count + ‘ попыток за 2 часа.’ >> $Log
}
Set-NetFirewallRule -DisplayName «Block RDP Attack» -RemoteAddress $current_ips
Вот это по ходу не работает…
# смотрим нет ли такого IP среди заблокированных
$ip = $getip | where { $getip.Name.Length -gt 1 -and !($current_ips -contains $getip.Name) }
Проверил в правиле Бренмауэра несколько адресов, некоторые аж по три раза повторяются
Странно, после добавления IP адреса в правило фильтрации, больше событий с этого IP быть не должно.
Win Server 2016 правило создалось, скрипт отработал, IP поместились в область в правиле, но почему то не срабатывает. Т.е в журнале продолжают регистрироваться атаки с IP которые уже есть в списке правила. Правило удалил, пересоздал, сработало, но уже через пару минут появились новые атакующие, прогоняю по ним скрипт, они добавляются, но продолжают атаковать.
На других серверах с 2019 проблем нет, и даже вроде с 2016 всё ок с лругим. Не могу понять почему брандмауэр не хочет исполнять правило, само оно включено, брандмауэр включен тоже
Разобрался, правило работает нормально, только вот атака предпринимается не на порт rdp, а совсем на другие порты из диапазона 3000+. В правиле поменял блокировку порта с 3389 на все порты. Не могу понять, как сервер может отвечать rdp на другой порт, отличный от настроенного, причем идёт то же событие 4625, и в логах брандамауэра этому пакету естественно ставится ALLOW т. к запрос идёт по другому порту…
Причём пытаюсь приконнектиться по этому порту с разных сетей сам, для проверки — не пускает…
Еще больше разобрался ) Атака шла на tcp 445, а не на rdp. Почему то он был открыт, я так понял что это на расшаренные папки порт используется и авторизоваться боты хотели через него…
Ну так то в интернет даже порт 3389 опасно открывать, не то что 445 🙂 У вас явно проблемы с архитектурой безопасности…
Самое интересное, что на серверах, которые сам ставил, там это всё не открыто и проблем нет. Эта проблема с серваком, который на хостинге купили, предустановленный, лень было смотреть изначально, думал всё по умолчанию, а оказалось хостер сам понастроил таких правил) Сейчас пришлось всё закрыть и подключать к нему только по белому списку, благо что немного пользователей
Это известный миф.
Да, открывать стандартные порты — это моветон. Но даже если открыть, например, порт 33389 и сделать маппинг на 3389 (RDP нужен, особенно сейчас) это защитит разве что от «пионЭров» со порт-сканерами которые «шарашат» по стандартным портам. А если сканировать весь range портов от 1 до 65535, то RDP отзовется, раньше или позже. А дальше «дело техники».
Ну хоть от пионЭров порт спасёт и то хорошо. Сервак когда на 3389 стоял открытой Ж. в инет туда ломятся на порядок (т.е в 10 раз!) больше, чем когда порт сменишь). Изучал логи на досуге)
Там, кстати, они не только брутфорсят, а возможно еще и DDOS атака, в логах в колонке размер по нескольку десятков, а то и сотен МБ, это и на 445 и на 3389 порты. Ломятся по нескольку раз за секунду, сейчас брандмауэр их исправно дропает, что не может не радовать.
Исправляю, т.к. здесь не удалить сообщение, это не размер оказался а tcpsyn колонку спутал, логи в текстовом документе у брандмауэра, что не шибко удобно. По идее же не может размер пакета 1500 байт превышать ) Ну да ладно, но частота перебора паролей была угрожающей, за сутки 100 000 + попыток…
Добавлю свой работающий, взял отсюда, доработал под себя) Универсальный, сам создает правило, не привязан к русской/анг локализации. Работает чуть с другим журналом событий, так как у меня не на всех компах в 4625 был ip- ‘Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational’;ID=’140′
2012R2, 2016, 10 Pro -работает
Что нужно — правте под себя. У меня количество попыток 30шт, так надо..)
if($null -eq (Get-NetFirewallRule -DisplayName BlockRDP -ErrorAction SilentlyContinue)){New-NetFirewallRule -DisplayName "BlockRDP" –RemoteAddress 1.1.1.1 -Direction Inbound -Protocol TCP –LocalPort 3389 -Action Block}
#за сколько времени
$Hours = 1
$Last_n_Hours = [DateTime]::Now.AddHours(-$Hours)
$badRDPlogons = Get-WinEvent -FilterHashTable @{LogName='Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational';ID='140';StartTime=$Last_n_Hours}
# берем 30 и больше неудачных входов
$getip = $badRDPlogons.Properties | group-object -property value | where {$_.Count -gt 30} | Select -property Name
$log = "C:\blocked_ip_rdp.txt" # лог файл
$current_ips = (Get-NetFirewallRule -DisplayName "BlockRDP" | Get-NetFirewallAddressFilter ).RemoteAddress -split(',')
for($i = 0; $i -lt @($getip).Count; $i++) {
$current_ips += $getip[$i].name.Trim()
(Get-Date -Format G) + ' ' + $getip[$i].name + ' IP заблокировано за ' + ($badRDPlogons.Properties | where {$_.Value -eq $getip[$i].name}).count + ' неудачных попыток за ' + $Hours + 'ч.'>> $log
}
Set-NetFirewallRule -DisplayName "BlockRDP" -RemoteAddress $current_ips
Но да, рдп зло, уходим где возможно за впн
парни, софт ipban же
https://github.com/DigitalRuby/IPBan
Поясни, плз, как этим пользоваться
Подниму вопрос:
Что если выделенная виртуалка с одним интерфесом. на которую открыты «все» стандартные порты.
и чтоб она отвечала на запросы предельно долго.
+ вела список кто к ней обращается и отсылала в abuseipdb.com или подобные.
Все это более-менее работает пока не попадаешь под настоящий «шторм подбора логинов и паролей». Загибается сама Windows 🙁 Недавно такое словили в одном из мелких офисов.
Полезное решение, спасибо.
Но разве эта задача решается не на маршрутизаторе/шлюзе? Ведь и в корпоративной сети, и для домашнего пользователя всегда есть шлюз интранет-интернет (редко когда хост напрямую подключен к сети провайдера интернет), на нем и пишутся правила доступа RDP в локальную сеть и ловушки/логирования для атакующих выделенный RDP порт. У меня сейчас длинный список заблокированных IP, хосты «стучатся» в маршрутизатор. А для легитимных RDP port knocking и привязка по IP.
Всё красиво. но долбежка то не прекращается … и надо «чистить» периодически список блокированных адресов
а почему если лениво или нет возможности настроить VPN оставить RDP + нестандартный порт + цифровой сертификат + двойную аутентификацию ( например, свою на основе гугла сваять или воспользоваться готовым сервисом типа duosecurity) ?
OpenVPN (транспорт udp+tap L2 уровень). На шлюзе поднято несколько экземпляров для различных нужд. Далее IPTables разруливает область применения. Обслуживает ~250 rdp подключений. Канал 100 Мбит. Никаких нареканий и или проблем. Вообще не знаю что такое подбор пароля по RDP.
Помогите !!! 50 000 долбежек за неделю.
Что делать с этим?
Компьютер попытался проверить учетные данные учетной записи.
Пакет проверки подлинности: MICROSOFT_AUTHENTICATION_PACKAGE_V1_0
Учетная запись входа: TENDER
Исходная рабочая станция:
Код ошибки: 0xC0000064
Компьютер попытался проверить учетные данные учетной записи.
Пакет проверки подлинности: MICROSOFT_AUTHENTICATION_PACKAGE_V1_0
Учетная запись входа: БОГДАН
Исходная рабочая станция:
Код ошибки: 0xC0000064
Компьютер попытался проверить учетные данные учетной записи.
Пакет проверки подлинности: MICROSOFT_AUTHENTICATION_PACKAGE_V1_0
Учетная запись входа: БУХ1
Исходная рабочая станция:
Код ошибки: 0xC0000064
и.т.д
гуглим cyberarms это аналог fail2ban только с человеческим интерфейсом.
Спасибо за данную тему и её обсуждения, очень полезно! Сам столкнулся с подобной ситуацией и счастье, что наткнулся на эту страничку.
Я не очень хорошо владею PowerShell, но прочитал комментарии и проанализировал предложенные коды, у меня получилось собрать новый универсальный скрипт из имеющихся здесь, он также не зависит от языка системы и кодировок, сохраняет логи, проверяет на повторяющиеся IP адреса и отсекает их. В общем, собрал всё лучшее из имеющихся вариантов, а также вынес некоторые настройки в начало скрипта и добавил больше пояснений (хотя сам далеко не всё понимаю).
$Attempts = 5 # За сколько попыток блокировать
$Hours = 1 # За какое время считать попытки
$RDPPort = "3389" # Блокируемый порт, стандартный - 3389
$NameRule = "BlockRDPBruteForce" # Название правила брандмауэра
$log = "blocked_ip_rdp.txt" # Лог-файл (можно указать вместе с путём к файлу)
# Проверяем наличие правила в брандмауэре и создаём его, если отсутствует
if($null -eq (Get-NetFirewallRule -DisplayName $NameRule -ErrorAction SilentlyContinue)){New-NetFirewallRule -DisplayName "$NameRule" –RemoteAddress 1.1.1.1 -Direction Inbound -Protocol TCP –LocalPort $RDPPort -Action Block}
# Получаем список системных сообщений с неудачными попытками за указанное время
$badRDPlogons = Get-WinEvent -FilterHashTable @{LogName='Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational';ID='140';StartTime=([DateTime]::Now.AddHours(-$Hours))}
# Получаем новые IP адреса с неудачными попытками авторизации за указанное время
$getip = $badRDPlogons.Properties | group-object -property value | where {$_.Count -gt $Attempts} | Select -property Name
# Получаем список IP из текущего правила брандмауэра
$current_ips = (Get-NetFirewallRule -DisplayName "$NameRule" | Get-NetFirewallAddressFilter ).RemoteAddress -split(',')
# Проверяем найденные IP среди уже заблокированных и формируем итоговый список IP
$ip = $getip | where { $getip.Name.Length -gt 1 -and !($current_ips -contains $getip.Name) }
$ip | % {
$current_ips += $ip.name
# Записываем информацию в лог-файл
'['+(Get-Date).ToString() + '] IP ' + $ip.name + ' blocked for ' + ($badRDPlogons | where { $_.IpAddress -eq $ip.name }).count + ' unsuccessful attempts in ' + $Hours + ' hour(s).' >> $Log}
# Обновляем правило брандмауэра
Set-NetFirewallRule -DisplayName "$NameRule" -RemoteAddress $current_ips
Также здесь дали очень верный совет, что время от времени надо очищать получившиеся правило брандмауэра и переносить блокируемые адреса в маршрутизатор, чтобы не засорялся брандмауэр, а блокировка происходила на уровне «железа».
Get-WinEvent : Не удается найти позиционный параметр, принимающий аргумент «$null».
Скрипт при каждом запуске создает дубликаты ip адресов в правиле брандмауера, текстовый лог и таблица адресов разрастаются лавинообразно.
Подскажите пожалуйста, что можно с этим сделать?
[29.12.2022 11:47:52] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:02] IP 143.244.41.203 181.214.206.191 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:02] IP 143.244.41.203 181.214.206.191 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:10] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:10] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:15] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:15] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:19] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:19] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:23] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:23] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:30] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:30] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:37] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:37] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:48] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:48] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:55] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:55] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:59] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:48:59] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:49:07] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:49:07] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:49:12] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
[29.12.2022 11:49:12] IP 181.214.206.191 143.244.41.203 blocked for 0 unsuccessful attempts in 5 hour(s).
Да, я тоже сталкивался с этой проблемой. Я позже доработал свой скрипт. Вот новая версия — https://raw.githubusercontent.com/BlackBulletBrony/BlackBullet/master/BlockRDPBruteForce.ps1
В ней исправлена эта проблема и некоторые другие менее заметные.
Только учтите, в этой новой версии скрипта теперь надо передавать скрипту аргумент – число, секунды, за которые скрипт не будет блокировать IP, но будет собирать статистику обращений с этого же IP. Это число не стоит ставить маленькое, т.к. тогда будет плохая эффективность, но и нельзя ставить большое, а то скрипт будет игнорировать большое число попыток брутфорса. Рекомендую ставить в пределах от 300 до 1800 (от 5 до 30 минут), я поставил 900 (15 минут). Выглядит это в планировщике так — https://raw.githubusercontent.com/BlackBulletBrony/BlackBullet/master/BlockRDPBruteForce.ps1%20%D0%B2%20%D0%BF%D0%BB%D0%B0%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D1%89%D0%B8%D0%BA%D0%B5.png
Т.е. просто число, через пробел после пути и имени файла скрипта
А почему не оставили этот аргумент внутри самого скрипта а вынесли в параметры запуска, создав еще одну сущность требующую контроля?
Наблюдал и у себя такую проблему с исходным вариантом. Сама запись счётчика 0 меня не обижала, дубликаты, конечно, добавляли проблем. Переделал логику по своему, у меня счётчик пишется в отдельный файл при отдельной папке (где имя папки — IP атакующего). Взять можно по ссылке от моего имени 29.12.22.
Ну и дубликатов не наблюдаю (в работе около 40 компьютеров)
Давно уже придумали RD Gateway.
можно по аналогии блочить IP, с которых идет подбор пароля к mssql:
_https://www.saotn.org/block-brute-force-attacks-on-sql-server-block-ip-addresses-in-windows-firewall-using-powershell/
Можете попробовать мой вариант (за основу взято решение отсюда). Он работает по триггерам, т.е. срабатывает быстрее, ведёт журнал атак с указанием логинов.
Кириллические URL без обработки порой пугают. )
А просто кирилицу в ОС добавить низя и на ней пароли стучать? ОС то по што трогать.
я так и не смог эти скрипты подружить. пришлось ставить бесплатный rdp-defender. от попыток перебора рдп он помогает, но вот от перебора НЕ-рдп — вообще не защищает. в логах винды раз в 2 секунды всякие алармы без указания айпи источника что «админ/вася пупкин/юзер 1с/ логин или пароль не подходят»
при скудности логов и крупицам то там то сям понимаю — что идёт попытка подключения к smb.
банально приходится или на час тушить проброс порта, или его быстро менять.
Проще использовать готовый IPBAN:
Установка:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/DigitalRuby/IPBan/master/IPBanCore/Windows/Scripts/install_latest.ps1'))
Программа будет добавлять в файервол правила блокирвоки для IP после 5 (по умолчанию) неудачных попыток входа программа
А не проще поставить RDG. И никто тогда не будет перебирать вам пароли. В целом RDP я бы выставлял на улицу только с доступом с определенных ИП.
Он работает только в домене
На самом деле, RDGW может работать и в рабочей группе.
Несколько раз реализовывал такое. Опишу это отдельно в статье https://winitpro.ru/index.php/2022/03/17/nastrojka-shlyuza-remote-desktop-gateway-windows-server/
Будет отдельная статья или я невнимательно посмотрел статью
Только что обновил статью по ссылке, пользуйтесь)
Здравствуйте!
$result = Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625; EndTime=(get-date).AddHours(-1)} | ForEach-Object { $eventXml = ([xml]$_.ToXml()).Event [PsCustomObject]@{ UserName = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
IpAddress = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'IpAddress' }).'#text' EventDate = [DateTime]$eventXml.System.TimeCreated.SystemTime } } $result
Пытаюсь выполнить первую часть.
выдаёт ошибки:
At line:1 char:159
+ ... bject { $eventXml = ([xml]$_.ToXml()).Event [PsCustomObject]@{ UserNa ...
+ ~~~~~~~~~~~~~~~~~
Unexpected token '[PsCustomObject]@' in expression or statement.
At line:4 char:91
+ ... | Where-Object { $_.Name -eq 'IpAddress' }).'#text' EventDate = [Date ...
+ ~~~~~~~~~
Unexpected token 'EventDate' in expression or statement.
At line:4 char:90
+ ... Data.Data | Where-Object { $_.Name -eq 'IpAddress' }).'#text' EventDa ...
+ ~
The hash literal was incomplete.
At line:4 char:155
+ ... tDate = [DateTime]$eventXml.System.TimeCreated.SystemTime } } $result
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
Не понимаю, в чём проблема. Подскажите пожалуйста.
Использую Windows Server 2019 Standard
Версия PowerShell 5.1.17763.5328
У движка сайта тут всплыла проблема с форматирование кода, поправил.