Мне довольно часто приходится настраивать "одинокие" терминальные сервера(и не только терминальные) в "Облаках", с "легким, быстрым" доступом к нему по RDP.

Все объяснения для пользователей\заказчиков, что такие сервера должны быть доступны только с доверенных IP или через VPN или с 2FA, воспринимаются "в штыки" и тогда приходится рисковать...

Конечно сервер защищается от Bruteforce(а), используются парольная политика, нестандартный порт, но все равно сервер постоянно под угрозой, в месяц можно увидеть по 15000 попыток подобрать пароль.

Такое обстоятельство дел заставило меня подумать о простом и действенном способе защиты сервера и в то же время этот способ не должен усложнить пользователям подключение к серверу.

Первое что пришло в голову - Port Knocking, использую его на RouterOS, но беглое гугление показало что для Windows не существует подобного штатного функционала, поиск сторонних средств которые могли бы помочь организовать задуманное не дал результата,  больше покопавшись нашел только странные и страшные поделки на Java не внушавшие доверия.

Тогда решил сделать свой PortKnocking для Windows. Написать его решил на PowerShell, чтоб не пришлось устанавливать на сервер дополнительно Java или Python.

Т.к. есть опыт c телеграм ботами(@SuperMon_Bot), решил добавить и информирование о работе PortKnocking через телеграм.

Определился что вся задумка должна состоять из нескольких скриптов:

  • Подготовка и настройка всего необходимого, создание правил фаервола, создание задач в планировщике, деактивация старых правил RDP.

  • Главный скрипт который слушает порты и добавляет адреса в правила фаервола.

  • Скрипт который обнуляет список адресов из правила фаервола.

  • Позже коллега уговорил меня добавить скрипт который проверят корректность выбранных портов и возможность их использовать.

Решил что постучится на два разных порта от большего к меньшему, с небольшой разницей во времени будет достаточно.

Например, постучаться на порт 65000 и в течении 3-х секунд постучаться на порт 1025.

Все настройки решил вынести в отдельный файл XML,  для удобства, чтоб не преходилось менять эти данные в нескольких разных скриптах.

0. settings.xml

Hidden text
<config>
	<system>
		<Telegramtoken>XXXXXXX</Telegramtoken >
		<Telegramchatid>YYYYY</Telegramchatid>
		<port1>zzzz</port1>
        		<port2>zzzz</port2>
        <RDPport>63389</RDPport>
        <SafeIPs>z.z.z.z</SafeIPs>
	</system>
	<tasks>
	</tasks>
</config> 

Пояснение XML:

Telegramtoken - вставляем токен телеграм бота. Как регистрировать ботов описывать не буду, подобной информации достаточно в интернете.

Telegramchatid - вставляем ID пользователя или чата, куда будут отправляться информация о работе приложения.

port1 - порт на котором будет ожидаться первый стук.

port2 - порт на котором будет ожидаться второй стук.

SafeIPs - доверенные адреса с которых должен остаться доступ даже без стука.

1. Далее пишу главный скрипт который будет слушать порты и добавлять постучавших в разрешённые IP:

Port-Knocking-2-main.ps1

Hidden text
#Вычитиваем данные из XML

[xml]$xmlConfig = Get-Content -Path ("C:\Install\Port-Knocking\settings.xml")
$Telegramtoken  = $xmlConfig.config.system.Telegramtoken
$Telegramchatid = (($xmlConfig.config.system.Telegramchatid).Split(",")).Trim()
$port1 = $xmlConfig.config.system.port1
$port2 = $xmlConfig.config.system.port2

#Добавляем функцию отправки сообщений в телеграм

Function Send-Telegram {
    Param([Parameter(Mandatory=$true)][String]$Message)
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    $Response = Invoke-RestMethod -Uri "https://api.telegram.org/bot$($Telegramtoken)/sendMessage?chat_id=$($Telegramchatid)&text=$($Message)"
}


#Основная часть срипта
#Вечный цикл
While ($True) {
    $Listener1 = [System.Net.Sockets.TcpListener][int]$port1; #Слушаем первый порт
    $Listener1.Start();

    While($true){

        $client1 = $Listener1.AcceptTcpClient();
        $IP1 = $client1.client.RemoteEndPoint.Address.IPAddressToString
        $Client1.Close();
        break

    } 
    #Слушаем второй порт 4 секунды
    $Listener1.Stop()

        $IP2 = Start-Job -Name port2 {
        [xml]$xmlConfig = Get-Content -Path ("C:\Install\Port-Knocking\settings.xml")
		$port2 = $xmlConfig.config.system.port2
        $Listener2 = [System.Net.Sockets.TcpListener][int]$port2;
        $Listener2.Start();
        $Client2 = $Listener2.AcceptTcpClient();
        $IP2 = $client2.client.RemoteEndPoint.Address.IPAddressToString
        $Client2.Close();
        $Listener2.Stop()
        return $IP2
        } | Wait-Job -Timeout 4 | Receive-Job
    Stop-Job -Name port2
    Remove-Job -Name port2 
	
#Сравниваем IP	
    if ($IP1 -eq $IP2){
        $CurrentIPs = (Get-NetFirewallRule -DisplayName "!RDP-for-port-knocking" | Get-NetFirewallAddressFilter ).RemoteAddress
        $CurrentIPs += $IP2
        Set-NetFirewallRule -DisplayName "!RDP-for-port-knocking" -RemoteAddress  $CurrentIPs 
		Send-Telegram -Message "$env:COMPUTERNAME added IP - $IP1" #Если IP совпали, добавляем в правило фаервола и отправляем сообщение в телегу
    }	
	else {
		Send-Telegram -Message "$env:COMPUTERNAME was scanned from  $IP1" #Если не совпали, отправляем собщение что нас сканировали
	}
    # Обнуляем IP		
    $IP1 = $null
    $IP2 = $null
	
}

2. Далее приступил к скрипту который в конце суток удаляет все добавленные IP, кроме тех что в списке SafeIPs

Port-Knocking-3-ZeroTime.ps1

Hidden text

[xml]$xmlConfig = Get-Content -Path ("C:\Install\Port-Knocking\settings.xml")
$Telegramtoken  = $xmlConfig.config.system.Telegramtoken
$Telegramchatid = (($xmlConfig.config.system.Telegramchatid).Split(",")).Trim()
$SafeIPs = (($xmlConfig.config.system.SafeIPs).Split(",")).Trim()

Set-NetFirewallRule -DisplayName "!RDP-for-port-knocking" -RemoteAddress $SafeIPs

Function Send-Telegram {
    Param([Parameter(Mandatory=$true)][String]$Message)
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    $Response = Invoke-RestMethod -Uri "https://api.telegram.org/bot$($Telegramtoken)/sendMessage?chat_id=$($Telegramchatid)&text=$($Message)"
}

Send-Telegram -Message "$env:COMPUTERNAME cleared IPs"

3. Далее приступил к скрипту который по сути "подготавливает почву" для работы главного скрипта:

Port-Knocking-0-Install.ps1

Hidden text
#Start-Transcript -Path C:\Install\Port-Knocking\log01.txt -Append -Force

[xml]$xmlConfig = Get-Content -Path ("C:\Install\Port-Knocking\settings.xml")
$port1 = $xmlConfig.config.system.port1
$port2 = $xmlConfig.config.system.port2
$RDPport = $xmlConfig.config.system.RDPport
$PortsListener = $port1, $port2
$SafeIPs = (($xmlConfig.config.system.SafeIPs).Split(", ")).Trim()

#Создаем павило для RDP для подстраховки, чтоб не потерять управление сервером. 
New-NetFirewallRule -DisplayName '!RDP-for-SafeIPs' -Direction Inbound -LocalPort $RDPport -Protocol TCP -Action Allow –RemoteAddress $SafeIPs  -Enabled True  -Verbose 

#Создаем правило RDP для Port Knocking
New-NetFirewallRule -DisplayName '!RDP-for-port-knocking' -Direction Inbound -LocalPort $RDPport -Protocol TCP -Action Allow –RemoteAddress $SafeIPs -Enabled True -Verbose

#Создаем правило для портов на которые будем ожидать стук
New-NetFirewallRule -DisplayName '!For-port-knocking-Listener' -Direction Inbound -LocalPort $PortsListener -Protocol TCP -Action Allow   -Enabled True  -Verbose

#Отключаем “старое” правило для RDP
Get-NetFirewallPortFilter | Where-Object LocalPort -eq $RDPport |  Get-NetFirewallRule | Where-Object {($_.DisplayName -ne '!RDP-for-port-knocking') -and (($_.DisplayName -ne '!RDP-for-SafeIPs'))} | Disable-NetFirewallRule

#Создаем задачу в планировщике для запуска основного скрипта
Register-ScheduledTask  -TaskName 'Port-Knocking-2-main-task' -Xml (Get-Content 'C:\Install\Port-Knocking\Tasks\Port-Knocking-2-main-task.xml'  | Out-String) -Force

#Создаем задачу в планировщике для запуска “обнуления” адресов
Register-ScheduledTask  -TaskName 'Port-Knocking-3-ZeroTime' -Xml (Get-Content 'C:\Install\Port-Knocking\Tasks\Port-Knocking-3-ZeroTime.xml'  | Out-String) -Force

#Запускаем задачу прослушивания портов
Start-ScheduledTask -TaskName 'Port-Knocking-2-main-task'

Задачи в планировщике решил для упрощения создать с помощью экспорта из XML.

Сами задачи ниже:

Port-Knocking-2-main-task.xml

Hidden text
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2022-10-13T16:40:50.3934022</Date>
    <Author>Admin</Author>
    <URI>\Port-Knocking-2-main-task</URI>
  </RegistrationInfo>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <RestartOnFailure>
      <Count>20</Count>
      <Interval>PT5M</Interval>
    </RestartOnFailure>
    <StartWhenAvailable>true</StartWhenAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
  </Settings>
  <Triggers>
    <BootTrigger>
      <ExecutionTimeLimit>P1D</ExecutionTimeLimit>
      <Delay>PT5M</Delay>
      <Repetition>
        <Interval>PT2M</Interval>
        <Duration>P1D</Duration>
      </Repetition>
    </BootTrigger>
  </Triggers>
  <Actions Context="Author">
    <Exec>
      <Command>Powershell.exe</Command>
      <Arguments>-ExecutionPolicy Bypass  -File "C:\Install\Port-Knocking\Port-Knocking-2-main.ps1"</Arguments>
    </Exec>
  </Actions>
</Task>

Создается задача Port-Knocking-2-main-task с такими параметрами:

Запуск -  при старте системы 

Запуск программы - Powershell.exe -ExecutionPolicy Bypass  -File "C:\Install\Port-Knocking\Port-Knocking-2-main.ps1"

Немедленно запускать задачу если пропущен плановый запуск

При сбое выполнения перезапускать через 5 минут

Если задача уже выполняется - не запускать новый екземпляр.

Port-Knocking-3-ZeroTime.xml

Hidden text
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2022-10-13T18:14:46.5186083</Date>
    <Author>Admin</Author>
    <URI>\Port-Knocking-3-ZeroTime</URI>
  </RegistrationInfo>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
  </Settings>
  <Triggers>
    <CalendarTrigger>
      <StartBoundary>2022-10-13T23:59:00</StartBoundary>
      <ExecutionTimeLimit>PT30M</ExecutionTimeLimit>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
  </Triggers>
  <Actions Context="Author">
    <Exec>
      <Command>Powershell.exe</Command>
      <Arguments>-ExecutionPolicy Bypass  -File  "C:\Install\Port-Knocking\Port-Knocking-3-ZeroTime.ps1"</Arguments>
    </Exec>
  </Actions>
</Task>

Создается задача Port-Knocking-2-main-task с такими параметрами:

Запуск -  Ежедевно в 23:59

Запуск программы - Powershell.exe -ExecutionPolicy Bypass  -File C:\Install\Port-Knocking\Port-Knocking-3-ZeroTime.ps1"

Останавливать задачу выполняемую дольше 1ч.

4. Позже, по просьбе коллеги как говорил выше написал скрипт проверки возможности использования выбранных портов. Хотя по моему мнению это лишнее, настоящий администратор знает что происходит на сервере или как это проверить вручную)))

Check-correct-settings.ps1

Hidden text
$ErrorActionPreference  =  'SilentlyContinue'

[xml]$xmlConfig = Get-Content -Path ("C:\Install\Port-Knocking\settings.xml")
$port1 = $xmlConfig.config.system.port1
$port2 = $xmlConfig.config.system.port2
$RDPport = $xmlConfig.config.system.RDPport

$RDPport0 =  (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name "PortNumber").PortNumber
$RDPportState = Get-NetTCPConnection -LocalPort $RDPport0 -State Listen

if (($RDPport -eq $RDPport0) -and ($RDPportState)){
    Write-Host "RDP port - $RDPport0 and port is OK" -ForegroundColor Green
}
else{
    Write-Host "RDP port  is not $RDPport0 or  port in not liten, check please..." -ForegroundColor Red
     
}

$port1State = Get-NetTCPConnection -LocalPort $port1 -State Listen
$port2State = Get-NetTCPConnection -LocalPort $port2 -State Listen

if (($port1State -eq $null)  -and ($port2State -eq $null)){
     Write-Host "This ports($port1, $port2) can be use for Port-Knocning" -ForegroundColor Green
   
}
else{
    Write-Host "This ports($port1, $port2) can not be use for Port-Knocning" -ForegroundColor Red
   
}

Результат работы скрипта если RDP порт выбран неправильно.

5. Далее встал вопрос как пользователям стучаться. Для админа это совсем не вопрос есть telnet, Test-NetConnection, есть даже готовые клиенты.

Но для пользователей подготовил папку в которой лежит маленький exe(paping.exe) и CMD файл с таким содержимым:

paping.exe X.X.X.X -p zzz  -c 2

sleep 1

paping.exe X.X.X.X -p zzz  -c 2

6. Протестировав данную поделку в течении пары недель остался доволен, пользователи сильно не бурчали, попытки подобрать пароль к серверу свелись практически к нулю.

Как это работает на практике:

Администратор копирует папку, запускает от имени адмнистратора скрипт Port-Knocking-0-Install.ps1

Готово к использованию.

Пользователь при первом подключении в день запускает файл

Пользователь ждет 3 секунды

Пользователь подключается к серверу как обычно по RDP.

Больше в эти сутки запускать Knocker не нужно, только на следующие сутки.

Примеры сообщений которые получает администратор

При добавлении IP.

Если сервер был просканирован то получаем сообщение.

В 23:59 Администратор получает сообщение.

Естественно сообщения можно и не получать :-)

Все на усмотрение всемогущего Администртора :-)

Мне и моим коллегам данная поделка пригодилась, надесь будет полезно и другим.

Ссылка на Github

Комментарии (32)


  1. BugM
    04.11.2022 21:11
    +2

    Обычные сертификаты все еще работают и они все еще гораздо лучше и надежнее всех этих странных велосипедов.


    1. capt_Rimmer
      04.11.2022 21:15

      Есть большой минус у "обычных сертификатов" - уровень пользователей должен быть соответсвующим.


      1. BugM
        04.11.2022 21:21

        Зачем? Выдать настроенный ноут и все из коробки само будет работать.


        1. capt_Rimmer
          04.11.2022 21:33

          Боже, да вам надо дать ноутбук с линуксом и понаблюдать как вы будете настраивать из коробки.


          1. BugM
            04.11.2022 21:40
            +1

            Линукс ноуты + Вин сервера по RDP это странная конфигурация. Но в общем почему бы и нет? Когда такую конфигурацию принимали за стандарт отдел занимающийся наливкой ноутов и их выдачей пользователям должен был озаботится стандартными конфигурациями, так чтобы все работало из коробки само. Можно считать что эта проблема у них решена.

            На более типовой конфигурации Вин ноут + Вин сервер по RDP все настраивается легко и без страданий.


            1. capt_Rimmer
              04.11.2022 21:54

              Вы рассматриваете какой то корпоратив корпоративный, где ноуты, как горячие пирожки выдают настроенные с блэкджэком и куртизанками. В реальности есть куча ситуаций, когда люди используют личные устройства (домашний ноут с WinXP живым на борту, макбук на который свежий RDP клиент просто не встаёт), а им работать надо. Удаленно подключиться, сделать бухгалтерские документы и 100500 ещё других дел. Да, это не по RFC и не суперсекьюрно (если трафик слушать будут и анализировать), но для компании из 10-20 человек это не важно. Важна доступнусть с любого места: в случае моего велосипеда ниже не нужно ничего пользователю настраивать - имя пользователя и пароль они сами знают, а адрес сервера и ссылку для открытия порта можно хоть продиктовать, хоть написать...любой RDP клиент подойдёт. Страданий нет - полчаса на сервере и 2 минуты на клиенте любого уровня отбитости.


              1. BugM
                04.11.2022 22:24
                +2

                Я рассматриваю любую контору которая хотя бы немного дорожит своими данными и хотя бы немного заботится о безопасности.

                Наливать единичные вин ноуты с сертификатами в ручном режиме справится типичный аникейшик. Тот же кто принтеры чинит. Один раз все сделать и написать понятную ему инструкцию может любая внешняя консалтерская контора. И даже возьмет за это не очень много денег.

                Наливать десятки-сотни вин ноутов с сертификатами сможет любой нормальный вин админ. Он при таком парке технике все равно нужен.

                Для исключительных случаев когда кому-то с правами администратора надо срочно залогиниться с чужого железа ему можно держать сертификат файликом где-то. В виде исключения (небезопасно но в общем бывает). Можно считать что этот человек справится. Если не справится значит ему не надо. Пусть ждёт пока новый рабочий ноут до него доедет.

                А вот контора позволяющая коннектится к своим серверам с домашних компов с WinXP может смело ставить пароль 123456 на сервера. Хуже все равно не будет.

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


                1. capt_Rimmer
                  04.11.2022 22:49

                  Мне искренне жаль, что вы стали жертвой маркетологов. Распишете, пожалуста, на пальцах чем подход "Подключиться с сретификатом под Win11" особо "безопасней и лучше" варианта, описанного мной ниже (открытие порта через веб и подключение с самоподписанным сертификатом)?


                  1. BugM
                    05.11.2022 13:58

                    Я про обычный сертификат. Его невозможно подобрать, злоумышленнику можно разрешить слушать весь трафик, если немного озаботится то этот сертификат даже украсть с клиента невозможно. Максимально возможная надежность, которую человечество придумало. Максимальные гарантии и при этом удобно пользоваться.

                    А вы вместо этого предлагаете какой-то костыль который не защищает ни от чего. Защиту от скрипт кидди мы же не считаем важной?

                    При чем тут веб я не понял. Обычный сертификат и обычный ключ. Если нужна повышенная безопасность, то ключ неэкспортируемый на специальной железке у клиента.


                    1. capt_Rimmer
                      07.11.2022 16:04

                      Да, а от прилетевшего трафика по попытке перебора паролей сертификаты не спасают и как итог в вашей схеме - тормоза в сессиях у удалёнщиков либо вовсе отказ в обслуживании. В вашу связку нужно одно звено минимум добавить, которое будет "отсекать плохих", если уж корпоративно так всё. Сертификаты вы тоже попробуйте настроить в односерверной конфигурации - то ещё развлечение. Велосипеды могут сколько угодно быть странными и небезопасными, но они работают и на них ездят иначе они были бы не востребованы.


                      1. BugM
                        07.11.2022 16:40

                        Вы уже считали сколько ддоса такого надо чтобы затормозить типичный сервер? Уже делали простейшую защиту от него? Ну там rps limiter какой по вкусу.

                        Велосипеды работают ровно до тех пока не сломаются. Стандартные решения работают всегда. Любой новый человек в стандартном решении разберется путём Гугла ключевых слов. А вот в велосипеде вероятно даже разбираться не станет, а просто его выключит или переделает на что-то.

                        Вы как будто никогда не закапывали велосипеды в пользу стандартных подходов. Это много боли и непонятных проблем.


                      1. capt_Rimmer
                        07.11.2022 17:22

                        Закапывал, и не один, но ровно тогда, когда бюджет соответствовал. О чём, собственно я вам и пишу... Использовать корпоративную инфраструктуру для обеспечения безопасности в маленькой компании не получится - это реальность.


    1. avelor
      05.11.2022 03:11
      +1

      Насколько помню, нативно авторизации по клиентским сертификатам нет в rdp, даже с rds gateway. Есть разве что смарткарты, а нативно реализована валидация серта сервера. Можно изобразить, если использовать html5 клиенты например. Если что-то изменилось, был бы признателен за ссылку на документацию


      1. BugM
        05.11.2022 14:03

        https://learn.microsoft.com/en-us/answers/questions/907833/is-it-possible-to-login-to-windows-with-yubikey.html

        https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn781533(v=ws.11)

        Энтерпрайз без ключей в 2022 году? Зря вы считаете что МС вообще ничего в безопасности не понимает.


        1. avelor
          05.11.2022 14:37

          по первой ссылке - это смарткарта. работа через смарткарты реализована давно, тут вопросов нет.
          по второй ссылке - описана валидация серта сервера, тоже вопросов нет.
          Using certificates for authentication prevents possible man-in-the-middle attacks. When a communication channel is set up between the client and the server, the authority that generates the certificates vouches that the server is authentic. As long as the client trusts the server it is communicating with, the data being sent to and from the server is considered secure

          >Зря вы считаете что МС вообще ничего в безопасности не понимает.
          не надо мне приписывать то, чего я не говорил :)


          1. BugM
            05.11.2022 14:46

            не надо мне приписывать то, чего я не говорил :)

            Считать что логин по сертификатам не работает, это оно и есть.

            Давайте вот так:

            https://learn.microsoft.com/en-us/windows/security/identity-protection/hello-for-business/hello-deployment-rdp-certs

            RDP Sign-in with Windows Hello for Business Certificate Authentication

            After adding the certificate using an approach from any of the previous sections, you should be able to RDP to any Windows device or server in the same Forest as the user’s on-premises Active Directory account, provided the PKI certificate chain for the issuing certificate authority is deployed to that target server.

            Open the Remote Desktop Client (%windir%\system32\mstsc.exe) on the Hybrid Azure Active Directory-Joined client where the authentication certificate has been deployed.
            Attempt an RDP session to a target server.
            Use the certificate credential protected by your Windows Hello for Business gesture.


            1. avelor
              05.11.2022 16:08

              c натяжкой (требуется win hello, azure ad и подключение к нему клиентских устройств) но считается, спасибо :) попозже почитаю внимательнее, что там используется "под капотом", мб просто выдаёт керберос-токен и дальше прозрачный rdp (но доступ к кейтабам проверяется winhello), или ещё что.

              заметьте, я не не был уверен в правоте - поскольку несколько лет не занимался безопасностью терминальных ферм и серверов:)

              PS судя по всему, там да, под капотом эмуляция смарт-карты - https://learn.microsoft.com/en-us/windows/security/identity-protection/hello-for-business/hello-feature-remote-desktop?source=recommendations ну и помимо сертов, можно использовать и биометрию


  1. capt_Rimmer
    04.11.2022 21:28

    Я делал велосипед чуть проще.. Поднял apache веб сервер с PHP на нестандартном 32888, запилил скрип аля "если get['abrvalg']==777 определяй ip клиента, добавляй в файл ips.txt и запускай скрипт powershell", а скрипт powershellа просто читал ips.txt и добавлял в нужное правило. Пользователь если не может достучаться до сервера просто проходит по ссылке http://123.456.78.9:32888/noconf.php?abrvalg=777 после чего сразу логинится. Из подводных камней - только настройка прав вебсервера.


    1. romeo_82 Автор
      04.11.2022 22:15
      +1

      Тоже неплохой вариант. Но апач поставить нужно, права настроить нужно и и чем больше ПО, тем больеше потенциально уязвимости.


      1. capt_Rimmer
        04.11.2022 23:19

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


  1. aik
    04.11.2022 22:14
    -2

    А в чем проблема просто банить тех, кто пароли подбирает? 5 неверных попыток - и до свидания. Ну и нормальные пароли, закрытые порты кроме нужных и обновления вовремя. У меня пока ни один из серверов не сломали.

    Просто заставить пользователя запускать что-то, кроме rdp-клиента - без шансов. Даже впн не всегда могут. Молчу уж про самописные костыли.


    1. romeo_82 Автор
      04.11.2022 22:25

      И юзеры сами себя блочат и добавляют головной боли админам.

      • различные fail2ban всегда требуют больше ресурсов, т.к. парсинг логов у сервера где мало ресурсов и много попыток подобрать пароль особенно ботнетом, модет нехило нагрузить сервак.

      • всегда есть вероятность что пользователь установил пароль который отвечает требованиям сложности, но есть во всех словарях, пример - Qwerty123!. Тогда первая попытка брутфорса может быть удачной.


      1. aik
        04.11.2022 22:34
        -1

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

        У сервера терминалов ресурсов обычно достаточно для того, чтобы от ботов отбиваться.

        Нельзя доверять пользователям ставить пароль. 16 случайных символов вполне устойчивы. Ну и не только ведь пароль подобрать надо, но и логин. Который тоже можно pwgen'ом сгенерить. Ну или как минимум - никаких стандартных админов и главбухов.


        1. romeo_82 Автор
          04.11.2022 22:38
          +1

          Да был у меня случаи когда 8 юзеров в командировке приезжают в отель, а один тупит с паролем, блочит IP отеля, страдают все 8, переезжают все 8 и ситуация повторяется, а добавлять постоянно IP и геморно и не вариант...


    1. capt_Rimmer
      04.11.2022 22:35

      Ссылку открыть через браузер перед RDP - очень сложно? 5 неверных попыток и до свидания - куда до свидания? На уровне фаервола вы забанить сможете только через самописные костыли. При работе ботнета подбор производится с сотен ip и в большинстве случаев быстрее происходит замедление аутентификации лигитимных подключений или таймауты AD, в случае разгильдяйства откровенного могут и пароль подобрать. То, что у вас ни один из серверов - ошибка выжившего, не более.


  1. avelor
    05.11.2022 03:14
    +2

    Fail2ban + rds gateway + требования к паролям (включая проверку по словарям, благо такие решения есть) кмк более юзер-френдли. Ну и если что-то кликать населению перед началом работы - то уж лучше впн-клиент, это как-то поприятнее. Хотя бы ssh в туннельном режиме:)

    Но ваш способ тоже интересный, спасибо что поделились:)


    1. romeo_82 Автор
      05.11.2022 10:18
      +1

      rds gateway + проверка по словарям, это уже не standalone сервер, а несколько серверов + active directory.


      1. avelor
        05.11.2022 12:01

        Технически можно ужаться в один. Да, к слову - а виртуализацию не используете принципиально? Можно тот же терминальник (даже без ad), но рядом routeros chr. Или линукс гипервизором, и реализовать port knocking на нём


  1. Busla
    05.11.2022 11:21
    +1

    Port Knocking, использую его на RouterOS, <…> для Windows не существует подобного штатного функционала

    насколько я помню, на RouterOS он такой же «штатный», как на Windows — можно заскриптовать штатными средствами

    Прочитал ваш скрипт:

    1. послушать первый порт и запомнить ip первого подключившегося клиента

    2. послушать второй порт и запомнить ip первого подключившегося клиента

    3. если эти ip совпадают — пустить по rdp

    А теперь вернёмся к вводным — вас регулярно сканируют: если очерёдность сканирования совпадает — ваша поделка открывает доступ. (вы настроили как в примере: 65000, 9999; сканер идёт от бОльших к меньшим и благополучно стучится сначала в 65000, потом в 9999, а потом попадает на открытый rdp 3389).

    Второй момент — если легитимный пользователь стучится во время сканирования, он с большой вероятностью не достучится.

    Именно поэтому Port Knocking реализуется совсем иначе, через аналитику firewall’а и бан тех ip, с которых после обращения к первому порту полезли не на второй.


    1. romeo_82 Автор
      05.11.2022 11:48
      +1

      1. Где Вы увидели в тексте утверждение что Port Knocking на RouterOS "штатный"? Было только утверждение что я его использую на RouterOS.

      2. Большинство сканеров не сканируют все порты, это долго. Сканируют обычно по возрастанию. Проверял Nmap-м, OpenVas-м, Nessus-м. Можно по желанию слушать 3 порта, например 65000, 9999, 65003 и это уменьшит вероятность, попасть сканеру в правило. Если уж совсем заморочится, то можно миксовать TCP с UDP и ICMP, да еще и с разными длинами пакетов.

      3. Вероятность что именно в тот самый момент когда пользователь хочет подключиться, сканируют именно один из двух портов, ничтожно мала. В крайнем случае пользователь еще раз постучится. На момент публикации статьи PortKnocer работал на нескольких серверах на протяжении 3-х недель и не возникло проблем.

      4. Банить те IP которые постучались на первый, но не постучались на второй, так можно и своих забанить, вдруг пользователь прервал работу Knocker-а. Но идея имеет право на жизнь, обдумаю ее детальней.

      5. За Port-Knocker у меня остались fail2ban-ы, НО т.к. событий в журнале Security стало на порядок меньше, он работает быстрее и меньше нагружает систему. Более точная информация: а) Cyberarms intrusion detection, до PortKnocking - cpu 5%, ram - 21mb. б) PortKnocking - cpu 0%, ram - 3mb. в) Cyberarms intrusion detection, после PortKnocking - cpu < 1%, ram - 21mb.


  1. andrettv
    05.11.2022 11:55
    +2

    Развитие идеи port knocking - это single packet authorization, когда сеть открывается только после стука по нескольким портам одним пакетом, причём последовательность портов уникальна и каждый раз генерируется с помощью HOTP, например, 23076 64251 33198 50071. Это не заменяет аутентификации по сертификатам, но решает проблему сканирования. (источник).


  1. edst_land_ru
    05.11.2022 19:29

    Тоже раньше обдумывал различные способы авторизации пользователя на открытом RDP сервере, но потом плюнул, настроил на роутере (кинетик) Wireguard VPN и горя не знаю. Удивлялся масштабам хакерских атак - открытый в инет RDP долбят тысячи раз в секунду. Один раз удалось как-то продолбить и зашифровали все файлы на сервере шифровальщиком )))