Модуль rdp-log нашей оригинальной системы защиты удаленного рабочего стола Windows состоит из трех файлов - двух основных скриптов для PowerShell rdp-log.ps1 и для PHP rdp-log.php (которые последовательно выполняют всю необходимую работу по вторичному выявлению и блокировке хакеров-рецидивистов и блоков вредоносных адресов) и дополнительного файла rdp-log.bat (который вызывается из Windows Task Scheduler каждый час и при этом запускает на выполнение основные файлы rdp-log.ps1 и rdp-log.php).
Файл rdp-log.bat имеет в нашей системе такой вид:
powershell.exe -File "C:\Scripts\rdp_log.ps1" 2>nul "C:\Program Files (x86)\PHP\php.exe" C:\Scripts\rdp_log.php 2>nul
Само собой понятно, что вы у себя должны здесь будете заменить "C:\Scripts" на тот адрес, по которому у вас расположена копия нашей системы, а также, в случае необходимости, подправить путь к файлу php.exe. Главный файл этого модуля rdp-log.ps1 имеет следующий вид:
# Подключаем общие переменные (пути к mysql, логин, пароль и т.д.)
. "$PSScriptRoot\common.ps1"
# 1. ОЧИСТКА СТАРЬЯ
foreach ($Key in $BanTypes.Keys) {
# 1. Настройка переменных для текущего типа
$FirewallPrefix = $FirewallPrefixes[$Key]
$BanType = $BanTypes[$Key]
$BanTime = $BanTimes[$Key]
$ExpirationDate = (Get-Date).AddDays(-$BanTime)
# 2. Поиск всех правил этого типа
$AllRules = Get-NetFirewallRule -DisplayName "$FirewallPrefix*" -ErrorAction SilentlyContinue
# 3. Отбор и удаление старых правил
$OldRules = $AllRules | Where-Object {
if ($_.DisplayName -match "(\d{4}-\d{2}-\d{2})") {
[DateTime]$Matches[1] -lt $ExpirationDate
} else { $false }
}
if ($OldRules) {
$OldRules | Remove-NetFirewallRule
}
}
# чистим логи
if ((Get-Date).Hour -lt 3) {
$db_max_days_size = 7
$Query = "delete from ban_stats where ban_date < CURDATE() - INTERVAL $db_max_days_size DAY;"
& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$Query" 2>$null
$db_max_days_size = 48
$Query = "delete from days_data where ban_date < CURDATE() - INTERVAL $db_max_days_size DAY;"
& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$Query" 2>$null
$db_max_days_size = $LongSlice
if ($NetSlice -gt $db_max_days_size) { $db_max_days_size = $NetSlice }
$db_max_days_size = $db_max_days_size * 2
$Query = "delete from ban_log where ban_time < CURDATE() - INTERVAL $db_max_days_size DAY;"
& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$Query" 2>$null
$db_max_days_size = $BotSlice * 2
$Query = "delete from net_log where ban_time < CURDATE() - INTERVAL $db_max_days_size DAY;"
& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$Query" 2>$null
}
# документируем количество банов каждой категории
foreach ($Key in $BanTypes.Keys) {
# 1. Получаем префикс и BanType для текущей итерации
$CurrentPrefix = $FirewallPrefixes[$Key]
$BanType = $BanTypes[$Key]
# 2. Считаем количество правил для конкретного типа
$RulesCount = @(Get-NetFirewallRule -DisplayName "$CurrentPrefix*" -ErrorAction SilentlyContinue).Count
# 3. Формируем SQL-запрос
$Query = "INSERT INTO ban_stats (ban_count, ban_type) VALUES ($RulesCount, $BanType);"
# 4. Выполняем
& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$Query" 2>$null
}
# на основе первичных банов формируем баны следующих уровней
$CurDate = Get-Date -Format "yyyy-MM-dd"
# Запрос на рецидивистов
$LongQuery = "SELECT INET_NTOA(ban_addr), COUNT(*) as cnt FROM ban_log WHERE ban_time > NOW() - INTERVAL $LongSlice DAY GROUP BY ban_addr HAVING cnt >= $LongLimit;"
$Recidivists = @(& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$LongQuery" --skip-column-names)
$FirewallPrefix = $FirewallPrefixes['long']
foreach ($Row in $Recidivists) {
$Columns = $Row -split "\t"
$IP = $Columns[0].Trim()
$TechnicalName = $FirewallPrefix + $IP.Replace('.', '_')
if (-not (Get-NetFirewallRule -Name $TechnicalName -ErrorAction SilentlyContinue)) {
$Description = "Type: recidive. Created: $(Get-Date)"
New-NetFirewallRule -Name $TechnicalName -DisplayName "$FirewallPrefix$CurDate`_$IP" -Direction Inbound -Action Block -RemoteAddress $IP -Description $Description | Out-Null
}
}
# Запрос на поиск враждебных сетей
$NetQuery = "SELECT INET_NTOA(ban_subnet), COUNT(DISTINCT ban_addr) as unique_ips FROM ban_log WHERE ban_time > NOW() - INTERVAL $NetSlice DAY GROUP BY ban_subnet HAVING unique_ips >= $NetLimit;"
$HostileNets = @(& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$NetQuery" --skip-column-names)
$FirewallPrefix = $FirewallPrefixes['net']
foreach ($Row in $HostileNets) {
$Subnet = ($Row -split "\t")[0].Trim()
$TechnicalName = $FirewallPrefix + $Subnet.Replace('.', '_')
if (-not (Get-NetFirewallRule -Name $TechnicalName -ErrorAction SilentlyContinue)) {
$Description = "Type: botnet. Created: $(Get-Date)"
$FullSubnet = "$Subnet/24"
New-NetFirewallRule -Name $TechnicalName -DisplayName "$FirewallPrefix$CurDate`_$Subnet" -Direction Inbound -Action Block -RemoteAddress $FullSubnet -Description $Description | Out-Null
# фиксируем событие в логе для поиска рецидивов
$LogQuery = "INSERT INTO net_log (net_addr) VALUES (INET_ATON('$Subnet'));"
& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$LogQuery" 2>$null
}
}
# Запрос на поиск сетей-рецидивистов (тех, что постоянно попадают в net_log)
$BotQuery = "SELECT INET_NTOA(net_addr), COUNT(*) as cnt FROM net_log WHERE ban_time > NOW() - INTERVAL $BotSlice DAY GROUP BY net_addr HAVING cnt >= $BotLimit;"
$BotNets = @(& $mysql_path --user=$mysql_user --password=$mysql_password --database=$mysql_dbName --execute="$BotQuery" --skip-column-names)
$FirewallPrefix = $FirewallPrefixes['bot']
foreach ($Row in $BotNets) {
$Columns = $Row -split "\t"
$Subnet = $Columns[0].Trim()
$TechnicalName = $FirewallPrefix + $Subnet.Replace('.', '_')
if (-not (Get-NetFirewallRule -Name $TechnicalName -ErrorAction SilentlyContinue)) {
$Description = "Type: hell. Created: $(Get-Date)"
$FullSubnet = "$Subnet/24"
New-NetFirewallRule -Name $TechnicalName -DisplayName "$FirewallPrefix$CurDate`_$Subnet" -Direction Inbound -Action Block -RemoteAddress $FullSubnet -Description $Description | Out-Null
}
}
Как видно из этого кода, данный скрипт использует общие настройки системы из файла common.ps1, а также документирует свою деятельность в таблице ban_log (это необходимо для работы других модулей, задачей которых является вторичный бан - рецидивисты, блоки адресов и т.п.).
Файл rdp-log.php имеет в нашей системе такой вид:
<?php
$dbUser = "*******";
$dbPassword = "*******";
$dbName = "rdp_ban";
$conn = mysqli_connect("localhost","$dbUser","$dbPassword", "$dbName");
$mysql_datetime = date("Y-m-d");
$ban_types['short'] = 1;
$ban_types['long'] = 2;
$ban_types['net'] = 3;
$ban_types['bot'] = 4;
foreach ($ban_types as $ban_type)
{
$step_result = mysqli_query($conn, "select AVG(ban_count) as ban_avg from ban_stats where ban_type = $ban_type and ban_date > '$mysql_datetime'");
$step_row = mysqli_fetch_assoc($step_result);
$ban_avg = intval($step_row['ban_avg']);
$step_result = mysqli_query($conn, "select count(*) as data_count from days_data where ban_type = $ban_type and ban_date='$mysql_datetime'");
$step_row = mysqli_fetch_assoc($step_result);
$data_count = $step_row['data_count'];
if ($data_count == 0)
{
mysqli_query($conn, "insert into days_data(ban_date, ban_count, ban_type) values('$mysql_datetime', $ban_avg, $ban_type)");
} else {
mysqli_query($conn, "update days_data set ban_count=$ban_avg where ban_type = $ban_type and ban_date='$mysql_datetime'");
}
}
?>
Естественно, в начале этого файла, вместо звездочек, вы должны поставить свой логин и пароль для доступа к базе данных.
| © Extra Systems, 2026 |
|