Аудит RDP-подключений к Windows Server: кто, когда и откуда

RDP — это подарок для атакующих. Порт 3389 сканируют круглосуточно, брутфорс идёт непрерывно, а сотрудники иногда заходят на серверы в три часа ночи — и поди разберись, зачем. Мы в своей практике разбирали инциденты, где взлом обнаруживался спустя недели после того, как он случился. SIEM решает проблему, но это отдельный бюджет, отдельное внедрение и отдельная головная боль.
В этой статье покажем, как закрыть базовые задачи аудита RDP-подключений без сторонних инструментов — только штатный журнал событий Windows и PowerShell. Кто заходил на сервер? С какого IP? В половину третьего ночи или в рабочее время? Сколько раз промахнулся паролем? Ответы на все эти вопросы можно получить за несколько минут.
Какие события фиксирует Windows при RDP-сессии
Windows пишет всё. Security Event Log фиксирует каждое RDP-соединение в виде цепочки событий с конкретными Event ID. Если знаешь, какие именно идентификаторы за что отвечают, — читать этот журнал не сложнее, чем лог nginx.
- Event ID 4624 — успешный вход в систему. Для RDP тип входа (Logon Type) равен
10(RemoteInteractive). - Event ID 4625 — неудачная попытка входа. Содержит имя пользователя и IP-адрес атакующего.
- Event ID 4634 / 4647 — завершение сессии. Event 4647 фиксируется, когда пользователь сам инициировал выход.
- Event ID 4778 — переподключение к существующей сессии (reconnect).
- Event ID 4779 — отключение от сессии без завершения (disconnect).
- Event ID 4648 — явный вход с указанием конкретных учётных данных. На практике этот ID часто всплывает при pass-the-hash атаках — если видите его там, где не ожидали, это повод копать глубже.
Включение аудита входов в систему
Вот с чем мы регулярно сталкиваемся у клиентов: расширенный аудит входов оказывается частично отключён — прямо из коробки. Прежде чем писать запросы к журналу, проверьте, что нужные политики вообще активны.
Текущие настройки аудита смотрим командой:
auditpol /get /subcategory:"Logon"
auditpol /get /subcategory:"Logoff"
Если в столбце Inclusion Setting не стоит Success and Failure — включите аудит вручную:
# Включить аудит успешных и неудачных входов
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Logoff" /success:enable /failure:enable
В доменной среде это удобнее делать через GPO: Computer Configuration → Windows Settings → Security Settings → Advanced Audit Policy Configuration → Logon/Logoff. Один раз настроили — разъехалось на все машины.
Быстрая проверка: кто заходил по RDP сегодня
Самый ходовой запрос — список всех успешных RDP-входов за последние 24 часа. Запускаем PowerShell от имени администратора:
$StartTime = (Get-Date).AddHours(-24)
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4624
StartTime = $StartTime
} | Where-Object {
$_.Properties[8].Value -eq 10
} | Select-Object TimeCreated,
@{Name='User'; Expression={$_.Properties[5].Value}},
@{Name='Domain'; Expression={$_.Properties[6].Value}},
@{Name='SourceIP';Expression={$_.Properties[18].Value}},
@{Name='LogonType';Expression={$_.Properties[8].Value}} |
Sort-Object TimeCreated -Descending |
Format-Table -AutoSize
На выходе получите таблицу: время входа, имя пользователя, домен, IP-адрес источника. Хотите покликать мышкой — замените Format-Table на Out-GridView, откроется графическое окно с фильтрацией.
Анализ неудачных попыток входа (брутфорс)
Event ID 4625 — это то, что первым делом смотришь при подозрении на брутфорс. Один IP, 400 попыток за три минуты — картина знакомая. Видели такое даже на серверах клиентов с нестандартным портом RDP: боты находят и их.
# Топ IP-адресов по числу неудачных попыток за последние 7 дней
$StartTime = (Get-Date).AddDays(-7)
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = $StartTime
} | Select-Object @{
Name = 'SourceIP'
Expression = {$_.Properties[19].Value}
}, @{
Name = 'User'
Expression = {$_.Properties[5].Value}
} | Group-Object SourceIP |
Select-Object Name, Count |
Sort-Object Count -Descending |
Select-Object -First 20 |
Format-Table -AutoSize
IP из Нигерии, Бразилии или Сингапура на сервере московской бухгалтерии — уже достаточный повод для блокировки, не дожидаясь разбора полётов. Логины несуществующих пользователей — туда же. Баним на брандмауэре сразу.
Get-WinEvent есть ограничение: при очень большом журнале запрос может занять несколько минут. Используйте параметр -MaxEvents для ограничения выборки при первичной диагностике.
Полная история сессий с продолжительностью
Для расследования инцидентов «кто и сколько просидел в системе» одного события входа мало. Сопоставляем 4624 и 4634/4647 по LogonID — и видим реальную продолжительность каждой сессии:
# Сбор входов RDP
$logons = Get-WinEvent -FilterHashtable @{
LogName = 'Security'; Id = 4624
} | Where-Object {
$_.Properties[8].Value -eq 10
} | Select-Object TimeCreated,
@{Name='LogonID'; Expression={$_.Properties[7].Value}},
@{Name='User'; Expression={$_.Properties[5].Value}},
@{Name='SourceIP'; Expression={$_.Properties[18].Value}}
# Сбор выходов
$logoffs = Get-WinEvent -FilterHashtable @{
LogName = 'Security'; Id = @(4634, 4647)
} | Select-Object TimeCreated,
@{Name='LogonID';Expression={$_.Properties[3].Value}}
# Сопоставление по LogonID
$result = foreach ($logon in $logons) {
$logoff = $logoffs | Where-Object {
$_.LogonID -eq $logon.LogonID
} | Select-Object -First 1
[PSCustomObject]@{
User = $logon.User
SourceIP = $logon.SourceIP
LogonTime = $logon.TimeCreated
LogoffTime= if ($logoff) {$logoff.TimeCreated} else {'Сессия активна'}
Duration = if ($logoff) {
($logoff.TimeCreated - $logon.TimeCreated).ToString('hh\:mm\:ss')
} else {'—'}
}
}
$result | Sort-Object LogonTime -Descending | Format-Table -AutoSize
Мониторинг подозрительных входов в реальном времени
PowerShell умеет подписываться на новые события журнала безопасности и реагировать на них в реальном времени. Скрипт ниже выводит оповещение в консоль при каждом новом RDP-входе — удобно гонять на мониторинговой машине:
# Мониторинг новых RDP-входов в реальном времени
$query = @"
"@
$watcher = New-Object System.Diagnostics.Eventing.Reader.EventLogWatcher(
(New-Object System.Diagnostics.Eventing.Reader.EventLogQuery(
"Security",
[System.Diagnostics.Eventing.Reader.PathType]::LogName,
$query
))
)
$watcher.add_EventRecordWritten({
param($sender, $e)
$ev = $e.EventRecord
$user = $ev.Properties[5].Value
$ip = $ev.Properties[18].Value
$time = $ev.TimeCreated
Write-Host "[$time] НОВЫЙ RDP-ВХОД: $user с IP $ip" -ForegroundColor Red
})
$watcher.Enabled = $true
Write-Host "Мониторинг запущен. Нажмите Ctrl+C для остановки."
while ($true) { Start-Sleep -Seconds 5 }
Send-MailMessage или HTTP-хук в Telegram.
Отправка отчёта по RDP-входам на email
На практике удобнее всего — автоматический отчёт на почту каждое утро. Пишем скрипт, кидаем в Планировщик задач, забываем. Утром в ящике уже лежит сводка за прошедшие сутки:
# Параметры почты
$SmtpServer = "smtp.yourcompany.ru"
$SmtpPort = 587
$From = "monitoring@yourcompany.ru"
$To = "admin@yourcompany.ru"
$Credential = Get-Credential # или задайте PSCredential вручную
# Формируем отчёт за прошедшие сутки
$StartTime = (Get-Date).Date.AddDays(-1)
$EndTime = (Get-Date).Date
$events = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4624
StartTime = $StartTime
EndTime = $EndTime
} | Where-Object { $_.Properties[8].Value -eq 10 } |
Select-Object TimeCreated,
@{Name='User'; Expression={$_.Properties[5].Value}},
@{Name='SourceIP'; Expression={$_.Properties[18].Value}}
$failed = (Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = $StartTime
EndTime = $EndTime
} -ErrorAction SilentlyContinue).Count
$body = "RDP-отчёт за $(Get-Date $StartTime -Format 'dd.MM.yyyy')`n`n"
$body += "Успешных входов: $($events.Count)`n"
$body += "Неудачных попыток: $failed`n`n"
$body += ($events | Format-Table -AutoSize | Out-String)
Send-MailMessage -SmtpServer $SmtpServer -Port $SmtpPort `
-From $From -To $To `
-Subject "RDP-аудит $(hostname) — $(Get-Date -Format 'dd.MM.yyyy')" `
-Body $body -Encoding UTF8 -Credential $Credential -UseSsl
Добавление скрипта в Планировщик задач
Чтобы отчёт уходил без участия человека, регистрируем PowerShell-скрипт как задачу Windows:
# Создание задачи планировщика — запуск каждый день в 08:00
$Action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -ExecutionPolicy Bypass -File C:\Scripts\rdp-report.ps1"
$Trigger = New-ScheduledTaskTrigger -Daily -At "08:00"
$Settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit (New-TimeSpan -Minutes 10) `
-RunOnlyIfNetworkAvailable
Register-ScheduledTask -TaskName "RDP Daily Report" `
-Action $Action -Trigger $Trigger -Settings $Settings `
-RunLevel Highest -User "SYSTEM"
SYSTEM или выделенный сервисный аккаунт с правами на чтение Security Event Log. Обычному пользователю читать этот журнал запрещено.
Автоматическая блокировка атакующих IP через Windows Firewall
Если с одного IP прилетело больше N неудачных попыток — блокируем автоматически, не ждём, пока кто-то это заметит вручную. Скрипт запускаем по расписанию, например каждые 15 минут:
# Пороговое значение — количество неудачных попыток за час
$Threshold = 15
$StartTime = (Get-Date).AddHours(-1)
# Получаем IP-адреса превысившие порог
$attackers = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = $StartTime
} | Select-Object @{
Name = 'SourceIP'; Expression = {$_.Properties[19].Value}
} | Group-Object SourceIP |
Where-Object { $_.Count -ge $Threshold } |
Select-Object -ExpandProperty Name |
Where-Object { $_ -notmatch '^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.)' }
foreach ($ip in $attackers) {
$ruleName = "Block-RDP-Bruteforce-$ip"
if (-not (Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue)) {
New-NetFirewallRule -DisplayName $ruleName `
-Direction Inbound -Protocol TCP -RemoteAddress $ip `
-Action Block -Profile Any
Write-Host "Заблокирован IP: $ip (попыток: $($attackers.Count))" -ForegroundColor Yellow
}
}
Регулярное выражение в условии Where-Object исключает из блокировки локальные адреса (RFC 1918) — без этого есть шанс случайно заблокировать собственных пользователей внутри сети, что мы однажды и сделали в тестовой среде.
Просмотр журнала через Event Viewer: ручной способ
PowerShell недоступен или просто нужно быстро глянуть пару событий? Обычный Просмотр событий тоже справится:
- Откройте eventvwr.msc (Win+R).
- Перейдите в Журналы Windows → Безопасность.
- Нажмите Фильтровать текущий журнал (правая панель).
- В поле Идентификаторы событий введите:
4624,4625,4634,4647,4778,4779. - Нажмите OK — журнал отфильтруется по нужным событиям.
Нужно посмотреть журнал на удалённой машине — не надо никуда идти. Прямо из Event Viewer: Действие → Подключиться к другому компьютеру. Работает, пока открыт нужный порт и есть права.
Экспорт журнала в CSV для долгосрочного хранения
Журнал событий Windows хранит не так много, как хотелось бы. По умолчанию размер ограничен, старые записи перезаписываются новыми — и вот вы уже потеряли данные за прошлый месяц. Если в вашей компании есть требования ИБ или нужно хранить историю RDP-доступа дольше пары недель, экспортируйте события в CSV-файлы:
# Экспорт всех RDP-событий за месяц в CSV
$MonthStart = (Get-Date -Day 1).Date
$ExportPath = "C:\Logs\RDP-Audit-$(Get-Date -Format 'yyyy-MM').csv"
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = @(4624, 4625, 4634, 4647, 4778, 4779)
StartTime = $MonthStart
} | Select-Object TimeCreated, Id,
@{Name='User'; Expression={$_.Properties[5].Value}},
@{Name='Domain'; Expression={$_.Properties[6].Value}},
@{Name='SourceIP'; Expression={
if ($_.Id -eq 4625) {$_.Properties[19].Value}
else {$_.Properties[18].Value}
}},
@{Name='LogonType';Expression={$_.Properties[8].Value}},
Message |
Export-Csv -Path $ExportPath -Encoding UTF8 -NoTypeInformation
Write-Host "Экспортировано в: $ExportPath"
Этот скрипт мы добавляем в планировщик с запуском первого числа каждого месяца. Ротацию настраиваем так, чтобы на диске лежало не больше 12 архивов — то есть ровно год истории. Места занимает немного, зато при разборе инцидентов не придётся кусать локти.
Итог: минимальный набор инструментов для RDP-аудита
Если коротко — без SIEM и сторонних агентов вы вполне получаете полноценный аудит RDP-доступа. Только встроенные возможности Windows, ничего лишнего:
- Включить аудит входов/выходов через
auditpolили GPO. - Запрашивать Event ID 4624 (тип 10) для успешных RDP-входов.
- Анализировать Event ID 4625 — именно здесь видно брутфорс, часто уже в первые минуты атаки.
- Сопоставлять 4624 и 4634/4647 для расчёта продолжительности сессий.
- Автоматически блокировать атакующие IP через
New-NetFirewallRule. - Настроить ежедневный email-отчёт через Планировщик задач — утром открыл почту, за минуту понял, что происходит на серверах.
- Экспортировать события в CSV для долгосрочного хранения.
Все скрипты легко адаптируются под вашу среду. Поменяли пороговые значения, список серверов, реквизиты почтового сервера — и готово. Если серверов уже десятки, я бы посмотрел в сторону централизованного сбора событий через Windows Event Forwarding (WEF). Когда же инфраструктура продолжает расти — стоит попробовать лёгкий SIEM. Wazuh, например, разворачивается куда проще, чем принято думать.
Официальная документация: Microsoft Learn — Windows Server, Microsoft Learn — PowerShell
Часто задаваемые вопросы
Что такое Аудит RDP-подключений к Windows Server: кто, когда и откуда?
Аудит RDP-подключений к Windows Server: кто, когда и откуда — это важный аспект системного администрирования, который позволяет настроить и оптимизировать работу IT-инфраструктуры. В данной статье подробно рассматриваются все ключевые моменты.
Как правильно настроить Аудит RDP-подключений к Windows Server: кто, когда и откуда?
Для корректной настройки Аудит RDP-подключений к Windows Server: кто, когда и откуда необходимо следовать пошаговой инструкции, представленной в статье выше. Важно учитывать особенности вашей инфраструктуры и требования безопасности.
Какие типичные ошибки возникают при работе с Аудит RDP-подключений к Windows Server: кто, когда и откуда?
Наиболее частые ошибки при работе с Аудит RDP-подключений к Windows Server: кто, когда и откуда: некорректная конфигурация, недостаточные права доступа и несовместимость версий. Рекомендуем обратиться к специалистам ITFresh для профессиональной настройки.
ООО «АйТи Фреш» возьмёт это на себя
Не хватает времени или своих специалистов — мы настроим, оптимизируем и возьмём вашу IT-инфраструктуру на постоянное сопровождение. Работаем с юридическими лицами в Москве и регионах. Собственный дата-центр, команда из 8 серверов Dell Xeon Platinum 8280 на базе МТС.
Комментарии