Ошибка RDP: как разблокировать учётную запись Windows (PowerShell)

Опубликовано Обновлено 7 мин. чтения

Заблокированная учётная запись Windows при входе по RDP обычно означает автоматизированную атаку. Скрипт PowerShell снимает блокировку, показывает IP-адреса источников и настраивает политику блокировки.

Вход по удалённому рабочему столу внезапно перестаёт работать, и Windows сообщает примерно следующее: «В целях безопасности учётная запись пользователя заблокирована, так как было предпринято слишком много попыток входа или смены пароля.» Значит, сработала политика блокировки учётных записей Windows. Причина почти всегда одна и та же: кто-то или что-то забрасывает ваш RDP-доступ попытками входа из интернета.

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

Почему учётная запись Windows блокируется при входе по RDP?

Windows считает неудачные попытки входа и блокирует учётную запись, как только достигнут заданный порог. Сама по себе такая защита полезна, но превращается в проблему, как только порт RDP открыт в интернет: автоматические боты круглосуточно перебирают пароли и блокируют именно ту учётную запись, под которой вы собираетесь работать.

Поведение определяют три значения:

  • Порог блокировки: число неудачных попыток до блокировки
  • Длительность блокировки: минуты, в течение которых учётная запись остаётся заблокированной
  • Окно наблюдения: минуты, за которые суммируются неудачные попытки

Запуск PowerShell от имени администратора

Откройте Windows PowerShell от имени администратора. Для этого щёлкните в меню «Пуск» правой кнопкой мыши по пункту «Windows PowerShell» и выберите «Запуск от имени администратора». Без повышенных прав скрипт не сможет ни разблокировать учётную запись, ни изменить политику.

Скрипт: разблокировка учётной записи и поиск атакующих

В разделе «Настройки» укажите имя учётной записи и нужные значения, после чего вставьте скрипт в PowerShell:

#Requires -RunAsAdministrator

# KernelHost: разблокировка заблокированной учётной записи Windows RDP и поиск причины
# Выполнять в Windows PowerShell от имени администратора.

# ----------------------------------------------------------------------------
#  Настройки: измените их под своё окружение
# ----------------------------------------------------------------------------
$Username = 'Administrator'   # локальная учётная запись, которую нужно разблокировать

$ApplyPolicy      = $true     # $false, если политику блокировки менять не нужно
$LockoutThreshold = 0         # неудачных попыток до блокировки (0 = блокировка ОТКЛЮЧЕНА, см. текст)
$LockoutDuration  = 15        # минут, в течение которых запись остаётся заблокированной
$LockoutWindow    = 15        # минут, за которые считаются неудачные попытки
# ----------------------------------------------------------------------------

# 1) Показать текущую политику блокировки
Write-Host "`n=== 1) Текущая политика блокировки ===" -ForegroundColor Cyan
net accounts | Select-String 'Lockout|Sperr'

# 2) Разблокировать учётную запись
Write-Host "`n=== 2) Разблокировка учётной записи '$Username' ===" -ForegroundColor Cyan
try {
    $user = [ADSI]"WinNT://$env:COMPUTERNAME/$Username,user"
    if ($user.InvokeGet('IsAccountLocked')) {
        $user.InvokeSet('IsAccountLocked', $false)
        $user.SetInfo()
        Write-Host "  Учётная запись '$Username' была заблокирована и теперь РАЗБЛОКИРОВАНА." -ForegroundColor Green
    } else {
        Write-Host "  Учётная запись '$Username' не заблокирована." -ForegroundColor Yellow
    }
} catch {
    Write-Warning "  Не удалось разблокировать учётную запись '$Username': $($_.Exception.Message)"
}

# 3) Необязательно: изменить или отключить политику блокировки
if ($ApplyPolicy) {
    Write-Host "`n=== 3) Установка политики блокировки ===" -ForegroundColor Cyan
    if ($LockoutThreshold -eq 0) {
        net accounts /lockoutthreshold:0 | Out-Null
        Write-Host "  Блокировка учётных записей ОТКЛЮЧЕНА (порог 0)." -ForegroundColor Yellow
        Write-Host "  Теперь ограничьте доступ по RDP на файрволе вашим собственным IP-адресом." -ForegroundColor Yellow
    } else {
        net accounts /lockoutthreshold:$LockoutThreshold /lockoutduration:$LockoutDuration /lockoutwindow:$LockoutWindow | Out-Null
        Write-Host "  Порог=$LockoutThreshold  Длительность=$LockoutDuration мин  Окно=$LockoutWindow мин" -ForegroundColor Green
    }
}

# 4) Кто вызывает блокировки? (источники RDP-атак)
Write-Host "`n=== 4a) Последние события блокировки (Security-ID 4740) ===" -ForegroundColor Cyan
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4740} -MaxEvents 10 -ErrorAction SilentlyContinue |
    ForEach-Object {
        $x = [xml]$_.ToXml()
        [pscustomobject]@{
            Время                 = $_.TimeCreated
            ЗаблокированнаяЗапись = ($x.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
            Источник              = ($x.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetDomainName' }).'#text'
        }
    } | Format-Table -AutoSize

Write-Host "=== 4b) Самые частые IP-адреса источников неудачных входов за последние 24 ч (Security-ID 4625) ===" -ForegroundColor Cyan
$since = (Get-Date).AddHours(-24)
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=$since} -ErrorAction SilentlyContinue |
    ForEach-Object {
        ([xml]$_.ToXml()).Event.EventData.Data |
            Where-Object { $_.Name -eq 'IpAddress' } | Select-Object -ExpandProperty '#text'
    } |
    Where-Object { $_ -and $_ -ne '-' } |
    Group-Object | Sort-Object Count -Descending | Select-Object -First 10 |
    Format-Table Count, @{N='IP-источника'; E={$_.Name}} -AutoSize

Что делает скрипт по шагам

  1. Через net accounts он показывает текущую политику блокировки учётных записей, то есть порог, длительность блокировки и окно наблюдения.
  2. Он разблокирует учётную запись, указанную в $Username, через поставщик каталога WinNT. Для локальных учётных записей это аналог Unlock-ADAccount.
  3. Он изменяет политику, если $ApplyPolicy имеет значение $true. Со значениями по умолчанию блокировка становится менее агрессивной, а с $LockoutThreshold = 0 вы отключаете её полностью.
  4. Он выводит последние события блокировки (код события 4740), а также самые частые IP-адреса источников неудачных входов за последние 24 часа (код события 4625). Именно с этих адресов атакуют ваш RDP-доступ.

Замечание о языке: на немецкоязычной Windows команда net accounts выводит значения под немецкими названиями, поэтому скрипт выше фильтрует и по «Lockout», и по «Sperr». В русской локализации подписи выглядят иначе (например, «Пороговое значение блокировки»), так что добавьте в фильтр ещё и «блокиров».

Локальная учётная запись или доменная?

Скрипт работает с локальной учётной записью, то есть с типичным случаем на отдельно стоящем VPS или root-сервере. Если речь идёт о доменной учётной записи или вы работаете на контроллере домена, снимайте блокировку иначе:

Unlock-ADAccount -Identity <имя-пользователя>

Изменение или отключение порога блокировки

Скрипт по умолчанию задаёт порог 0 и тем самым отключает блокировку учётных записей. Сначала это звучит неправильно, но для RDP-доступа, открытого в интернет, такой выбор лучше. Причина в том, что атакующему вовсе не нужно угадывать ваш пароль. Ему достаточно каждые несколько минут отправлять пару неудачных попыток, чтобы учётная запись оставалась заблокированной постоянно. Блокировка бьёт тогда не по нему, а исключительно по вам. Так защитная функция превращается в удобный инструмент, которым вас держат подальше от вашего же сервера.

Важно: отключение блокировки не заменяет защиту, оно убирает лишь неправильную. Защита от перебора паролей находится уровнем ниже, а именно на файрволе: если RDP доступен только с вашего собственного IP-адреса, ни один атакующий больше не доберётся до окна входа, и считать будет попросту нечего. Поэтому выполните следующий раздел до того, как отключите блокировку, а не после.

Если по рабочим причинам RDP приходится оставлять открытым для меняющихся адресов, задайте вместо нуля высокий порог с короткой длительностью блокировки, например $LockoutThreshold = 50 и $LockoutDuration = 5. Так сохраняется хоть какой-то сдерживающий эффект, но вы не окажетесь заблокированы при каждом сканировании. В домене с внутренним RDP по-прежнему действует классическая рекомендация низкого порога: там доступ в любом случае не открыт из интернета.

Устранение причины: постоянная защита RDP

Заблокированная учётная запись — это только симптом. Настоящая причина в том, что доступ по RDP открыт всему интернету. Следующие четыре меры устраняют проблему в корне.

Ограничение RDP собственным IP-адресом

Это самая действенная мера. Если RDP доступен только с вашего собственного адреса, все автоматизированные атаки уходят в никуда:

# Разрешить входящие RDP-подключения только с собственного IP-адреса
Set-NetFirewallRule -DisplayName 'Remote Desktop - User Mode (TCP-In)' -RemoteAddress '203.0.113.5'

Указанное отображаемое имя действует в англоязычной Windows. В локализованных версиях, в том числе в русской, оно выглядит иначе. Существующие правила и их точные названия выводит команда Get-NetFirewallRule -DisplayGroup 'Удаленный рабочий стол'.

Блокировка отдельного IP-адреса атакующего

Для адресов, которые выдаёт шаг 4b скрипта, создайте отдельное запрещающее правило:

New-NetFirewallRule -DisplayName 'Block RDP attacker 203.0.113.9' -Direction Inbound -Action Block -RemoteAddress '203.0.113.9'

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

Смена порта RDP

Если RDP больше не слушает стандартный порт 3389, обычные массовые сканирования вашу службу просто не найдут. Как сменить порт без перезагрузки сервера, показано в нашем руководстве Смена RDP-порта в Windows без перезагрузки сервера.

Надёжный пароль и проверка подлинности на уровне сети

Используйте длинный случайный пароль и оставьте включённой проверку подлинности на уровне сети (Network Level Authentication, NLA). NLA требует аутентификации ещё до того, как будет установлен сеанс, и таким образом заранее отсекает большую часть автоматизированных попыток.

Частые вопросы

Почему учётная запись Windows блокируется при входе по RDP?
Windows блокирует учётную запись, как только достигнуто заданное в политике число неудачных попыток входа. На сервере с открытым в интернет портом RDP такую блокировку почти всегда вызывают автоматизированные атаки.
Как долго учётная запись остаётся заблокированной?
Столько, сколько задано в длительности блокировки, чаще всего 15 или 30 минут. После этого вход снова возможен. Скриптом из этого руководства блокировку можно снять сразу.
Стоит ли полностью отключать блокировку учётных записей?
Для RDP-доступа, открытого в интернет, да. Атакующему не нужно угадывать ваш пароль: ему достаточно регулярно отправлять неудачные попытки и тем самым постоянно держать учётную запись заблокированной. Блокировка бьёт тогда только по вам. Отключите её, но заодно ограничьте доступ по RDP на файрволе вашим собственным IP-адресом, иначе вы меняете одну проблему на другую. Если RDP приходится оставлять открытым для меняющихся адресов, выберите вместо 0 высокий порог с короткой длительностью блокировки.
Как узнать, какие IP-адреса блокируют мою учётную запись?
Событие с кодом 4740 в журнале безопасности фиксирует сами блокировки, а событие 4625 — неудачные входы вместе с IP-адресом источника. Скрипт из этого руководства разбирает оба автоматически.
Скрипт не разблокирует мою учётную запись, в чём причина?
Скрипт работает с локальной учётной записью. Для доменной учётной записи или на контроллере домена используйте вместо него Unlock-ADAccount. Кроме того, проверьте, действительно ли PowerShell запущен от имени администратора.

Windows Server Windows RDP Удалённый рабочий стол PowerShell Блокировка учётной записи Brute-force Безопасность сервера