Port knocking windows cmd

Время на прочтение9 мин

Количество просмотров11K

Мне довольно часто приходится настраивать «одинокие» терминальные сервера(и не только терминальные) в «Облаках», с «легким, быстрым» доступом к нему по 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

Copy to
C:\Install\Port-Knocking\

Set. All fields are required.
"C:\Install\Port-Knocking\settings.xml"
Telegramtoken - Telegram Bot Token. Use https://t.me/BotFather to register a bot and get Token.
Create a Group or Channel, add Bot there. Find the Group or Channel ID using postman or any other API utility. 
Remember Groups has -, channels doesn't
Change SafeIPs to the Ip you to whitelist. Without it it will not work.

Check that the settings are correct. If the ports are in use, an error is thrown.
C:\Install\Port-Knocking\Check-correct-settings.ps1

Run as admin
C:\Install\Port-Knocking\Port-Knocking-0-Install.ps1

If there are errors with permitions while runing scripts, use in Powershell before runing a command. 
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass


Paping is a free utility to ping server with needed port. You can downloand it here: 
https://code.google.com/archive/p/paping/downloads

Port knocking — настолько простой, насколько и эффективный способ защиты вашей локальной сети от несанкционированного доступа снаружи в случаях, когда вам необходимо использовать проброс портов. В этой статье я расскажу, как реализовать этот простой алгоритм авторизации на роутере MikroTik.

О том, что использовать обычный проброс портов не является правильным, я уже упомянул вскользь в статье «Проброс портов в MikroTik«. Но порой все же возникает необходимость давать доступ к удаленным рабочим столам некоторым сотрудникам (например, бухгалтерам в период сдачи отчетности — знакомо, да?).

При этом:

  1. вам неизвестен адрес, с которого человек будет подключаться и ограничиться правилом в фаерволе у вас не получится;
  2. использование VPN не представляется возможным в силу нескольких причин, начиная с некомпетентности сотрудника и заканчивая принципиальным запретом VPN на устройствах, через которые этот самый сотрудник будет пытаться подключиться (например, какой-нибудь бесплатный Wi-Fi в отеле на острове Пасхи).

Поможет в этом случае port knocking. Суть этого метода заключается в том, что пользователь, прежде чем получить доступ к чему-то, должен представиться. В классическом решении port knocking используются проколы TCP или UDP — пользователь «простукивает» определенную последовательность портов (обычно не менее трех), после чего его IP добавляется в список адресов с определенными привилегиями: в нашем случае к пробросу порта RDP на его рабочее место. Это как «постучи в дверь три раза, потом — два, потом — пять, чтобы я понял, что это ты». Знакомо, не правда ли?

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

Последовательность портов для простукивания и ее длина обусловлены только вашей фантазией. Но тут возникает небольшая проблема: если с простукиванием портов из Linux штатными средствами проблем никаких не наблюдается, то с Windows этот номер просто так не пройдет. Но у ваших бухгалтеров наверняка на ноутбуках стоит Windows, а слово Linux они вообще воспринимают, как ругательство.

Пример простукивания портов штатными средствами на Linux:

[root@server~]# nc -zu 1.1.1.1 35123

[root@server~]# nc -zu 1.1.1.1 18357

[root@server~]# nc -zu 1.1.1.1 43249

Здесь использовалась команда nc [параметры] [хост] [порт], где

  • z — говорит программе о том, что нужно просто «стукнуться», не посылая каки-либо дополнительных данных и не слушая ответ;
  • u — использование UDP вместо TCP.

К сожалению, данный пример не решает нашей задачи со штатными средствами Windows. А решение простое и лежит на поверхности: вместо UPD или TCP использовать ICMP ping. Принцип port knocking мы оставим, а последовательность портов заменим последовательностью разных размеров пакета.

Выглядеть «простукивание» из Windows будет так:

C:\>ping 1.1.1.1 f n 1 l 432

C:\>ping 1.1.1.1 f n 1 l 521

C:\>ping 1.1.1.1 f n 1 l 598

Простой ping с параметрами:

  • -4 — использовать IPv4
  • -f — запрет фрагментации пакета;
  • -n — количество запросов;
  • -l — буфер отправки (объем данных, которые мы отправляем «в нагрузку»).

Т.к. стандартный размер MTU — 1500, который к тому же может быть уменьшен всякими VLAN’ами и пр., а нам нужно, чтобы все влезло в один Ethernet фрейм, то рекомендую использовать буфер отправки в диапазоне 0-1000. Еще следует учесть, что размер самого пакета эхо-запроса ICMP «без нагрузки» (с L=0) — 28 байт, т.к. помимо данных там еще присутствует TCP-, ICMP-заголовки и .т.д. Можете погуглить, что из себя представляет ICMP-пакет. Таким образом, на роутере ловим пакеты размером равным [буфер отправки+28].

Теперь наш MikroTik должен распознать последовательность из трех пакетов с размерами 460, 549, 626. «На пальцах» алгоритм выглядит так:

  • если размер пакета 460 (432+28), добавить этот IP в список «первый уровень»;
  • если размер пакета 549 (521+28) и IP-адрес в списке «первый уровень», добавить этот IP в список «второй уровень».
  • если размер пакета 626 (598+28) и IP-адрес в списке «второй уровень», добавить этот IP в список «доступ к пробросу портов по RDP»

Сначала в картинках:

port knocking mikrotik рис.1

Рис. 1 Создадим свою цепочку portKnocking и направим туда входящий ICMP

port knocking mikrotik рис.2

Рис.2 Создадим правило, которое в случае нужного размера пакета будет добавлять IP-адрес в список checkLevelOne

port knocking mikrotik-рис. 3

Рис.3 Аналогично первому создадим второе правило за тем лишь исключением, что проверим присутствие в списке прошедших первую проверку checkLevelOne. Добавлять будем в список checkLevelTwo

port knocking mikrotik рис.4

Рис.4 Аналогично второму создадим третье правило, которое уже добавит наш IP в список, которому разрешен доступ к пробросу порта. Четвертое правило в списке — возврат из цепочки обратно, если ни одно из правил не сработало.

Правила проверки port knocking в фаерволе надо разместить вверху до разрешений related/established. Иначе вы не уйдете дальше первой проверки — будут срабатывать правила related/established.

port knocking mikrotik рис.5

Рис.5 Сначала проверим, не стучится ли кто, потом разрешим related и established. В противном случае в цепочке portKnocking дальше первого правила не уйдем.

В скриптах:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

#

#

/ip firewall filter

#направим входящий ICMP в свою цепочку portKnocking. Для удобства.

add action=jump chain=input comment=«port knocking check» dstaddress=1.1.1.1 jumptarget=portKnocking protocol=icmp

#первый пинг packet-size=460

add action=addsrctoaddresslist addresslist=checkLevelOne addresslisttimeout=5s chain=portKnocking comment=CheckLevelOne packetsize=460 protocol=icmp

#второй ping packet-size=549 и признак успешной проверки первого пинга src-address-list=checkLevelOne

add action=addsrctoaddresslist addresslist=checkLevelTwo addresslisttimeout=5s chain=portKnocking comment=CheckLevelTwo packetsize=549 protocol=icmp srcaddresslist=checkLevelOne

#третий пинг packet-size=626 и признак успешной проверки второго пинга src-address-list=checkLevelTwo

add action=addsrctoaddresslist addresslist=AllowRDP addresslisttimeout=30m chain=portKnocking comment=AllowRDP packetsize=626 protocol=icmp srcaddresslist=checkLevelTwo

#возврат из цепочки portKnocking

add action=return chain=portKnocking

#

#где-то в правилах, где у вас разрешения на INPUT

add chain=input comment=«Allow RDP from PortKnockin authorized» protocol=tcp dstport=4565,4355 srcaddresslist=AllowRDP

#

#проброс порта для адресов из списка AllowRDP

/ip firewall nat

# первому пользователю порт 4565 — > 192.168.33.129:3389

add action=dstnat chain=dstnat comment=test dstaddress=1.1.1.1 dstport=4565 ininterface=inetTest srcaddresslist=AllowRDP protocol=tcp toaddresses=192.168.33.129 toports=3389

# второму пользователю порт 4355 — > 192.168.33.130:3389

add action=dstnat chain=dstnat comment=test dstaddress=1.1.1.1 dstport=4355 ininterface=inetTest srcaddresslist=AllowRDP protocol=tcp toaddresses=192.168.33.130 toports=3389

Обратите внимание на параметр address-list-timeout в правилах, где IP добавляется в список адресов. Для этапов проверки я выставляю address-list-timeout=5s, т.к. считаю, что 5 секунд должно хватить для проверки следующего условия. Для завершающего правила, где адрес добавляется в разрешенные для подключения по RDP, address-list-timeout=30m — т.е. для подключения к удаленному рабочему столу человеку дается полчаса после успешного «простукивания» MikroTIk’а.

По истечении получаса адрес будет удален из списка AllowRDP, но сеанс не прервется, т.к. будут срабатывать правила allow related/established. Пользователю придется заново «представиться» в случае, если он сам прервет сеанс или за него это сделает плохая связь.

Для автоматизации процесса пишем пакетный файл (.bat или .cmd — кому как больше нравится) следующего содержания:

@echo off

rem раз

ping 1.1.1.1 f n 1 l 432 > NUL

rem подождем секунду, вдруг роутер притормаживает

timeout 1 > NUL

rem два

ping 1.1.1.1 f n 1 l 521 > NUL

rem подождем еще секунду

timeout 1 > NUL

rem три

ping 1.1.1.1 f n 1 l 598 > NUL

rem запустим клиента удаленного рабочего стола, указав адрес сервера и порт

mstsc.exe /v:1.1.1.1:4565

Теперь осталось только выслать каждому пользователю свой файл.

Как вы поняли, реализация алгоритма с простукиванием портов не только аналогична описанной выше, но даже проще — там не надо заморачиваться с размером пакета, а просто указать порт. Но для Windows нужны свои костыли…

Реклама:

Port knocking — это сетевой защитный механизм, действие которого основано на следующем принципе: сетевой порт является по-умолчанию закрытым, но до тех пор, пока на него не поступит заранее определённая последовательность пакетов данных, которая «заставит» порт открыться. Например, вы можете сделать «невидимым» для внешнего мира порт SSH, и открытым только для тех, кто знает нужную последовательность.

Настройка Сервера

Наиболее популярным ПО для организации port knocking является knockd. Работая в режиме демона совместно с iptables, knockd прослушивает сетевой интерфейс, ожидая корректной последовательности запросов на подключение. Как только knockd отлавливает корректную последовательность, он выполняет команду, определённую в конфигурационном файле knockd для данной последовательности — как правило, это вызов iptables, разрешающий соединение на определённый сетевой порт.

Например, у вас запущен демон SSH, ожидающий входящих подключений на 22 порту. Однако, правилом iptables входящие соединения на 22-й порт запрещены. Knockd, прослушивающий интерфейс eth0, ожидает последовательности из TCP SYN-пакетов на порты 9000, 6501 и 1234. Как только эта последовательность соединений будет обнаружена, knockd при помощи вызова iptables, изменит правило сетевого фильтра таким образом, чтобы разрешить подключение извне к 22-му TCP-порту, на котором уже ожидает SSH-демон.

Вы можете собрать knockd из исходных кодов, полученных на сайте (также, на сайте имеются ссылки на готовые пакеты для различных систем) или же установить, используя менеджер пакетов вашей системы. После установки knockd, его конфигурационный файл можно найти в /etc/knockd.conf.

В начале конфигурационного файла находится раздел [options], содержащий глобальные настройки демона. Например, строкой:

Interface = eth1

вы можете определить, какой интерфейс прослушивать в случае, если в вашей системе он не является единственным.

Далее, после раздела [options], идут описания последовательностей. По-умолчанию их две:

[openSSH]
sequence    = 7000,8000,9000
seq_timeout = 5
command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags    = syn

[closeSSH]
sequence    = 9000,8000,7000
seq_timeout = 5
command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags    = syn

Значение параметра sequence определяет последовательность. Числа являются номерами TCP-портов. Также, вы можете явно указать, TCP или UDP порт использовать, при помощи суффиксов :tcp и :udp. Например:

sequence = 3333:tcp,9999:udp,1010:udp,8675:tcp

Значение параметра seq_timeout задаёт максимальное время в секундах, которое отводится на совершение клиентом последовательности подключений. Если клиент не укладывается в это время — подключение будет отклонено.

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

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

tcpflags = syn,ack,urg

А для явного исключения отельных флагов нужно использовать восклицательный знак:

tcpflags = syn,!ack,urg

Другим интересным вариантом конфигурации knockd является использование параметров start_command, cmd_timeout и stop_command:

[opencloseSMTP]
one_time_sequences = /etc/knockd/smtp_sequences
seq_timeout        = 15
tcpflags           = fin,!ack
start_command      = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --dport 25 -j ACCEPT
cmd_timeout        = 5
stop_command       = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --dport 25 -j ACCEPT

Параметр start_command по смыслу идентичен параметру command. Значение параметра cmd_timeout определяет временной интервал в секундах, по истечении которого запустится команда, определённая значением параметра stop_command. Таким образом, вы можете открывать определённый порт лишь на некоторый промежуток времени.

Как правило, чтобы демон knockd запускался автоматически при старте системы, достаточно в файле /etc/default/knockd установить:

START_KNOCKD=1

Настройка Клиента

Протестировать соединение с вашим сервером вы можете обычным telnet-клиентом, последовательно подключившись к заданным портам.

При повседневном же использовании, естественно, не очень удобно запускать последовательные серии telnet-соединений перед тем, как вам необходимо подключиться к вашему SSH-серверу. В комплекте с демоном knockd поставляется утилита knock, которая и призвана осуществлять необходимые серии подключений. Например:

knock 192.168.1.100 3333:tcp 9999:udp 1010:udp 8675:tcp

Обратите внимание на формат описания номеров и типов портов. Он такой же, как и в файле /etc/knockd.conf.

Если придуманные вами последовательности основаны, в том числе и на TCP-флагах пакетов, то вам понадобятся более продвинутые средства, нежели knock. Например, SendIP или packit, умеющие формировать сетевые пакеты с произвольным содержимым.

Если вы используете port knocking повсеместно, то вам, вероятно, могут понадобиться knock-клиенты для мобильных платформ.

Для iPhone вы можете попробовать пару knockd-совместимых клиента — Port Knock Lite и KnockOnD, для Android — knock-android.

Port Knocking в PuTTY

Под Windows вы можете использовать русскую сборку PuTTY. Начиная с версии 0.63-RU-15, в ней появилась возможность осуществлять последовательность подключений к закрытым портам по технологии Port Knocking:

Port Knocking в PuTTY

Практические Моменты

Одна из причин, по которой не стоит использовать knock-клиенты, запоминающих секретную последовательность и воспроизводящих её без вашего участия — это очень «похожесть» на сохранение где-то пароля к вашей учётной записи в открытом виде. Секретная последовательность подключений к портам должна находиться лично у вас в памяти и больше нигде. Тогда метод port knocking’а будет на самом деле эффективным.

Также, port knocking критикуют за то, что всегда существует вероятность того, что ваш трафик перехватят и смогут вычленить из него последовательность, и, чем чаще вы используете port knocking, тем выше эта вероятность. Конечно, вы можете дополнять вашу последовательность псевдопоследовательностями для того, чтобы запутать злоумышленников, однако в первую очередь всегда заботьтесь о безопасности самого сервиса, открытый порт которого вы маскируете и рассматривайте port knocking как дополнение к безопасности сервиса, нежели как панацею.

Более сложный метод защиты от прослушивания port knocking состоит в использовании одноразовых секретных последовательностей. Для этого в knockd.conf нужно использовать параметр one_time_sequences, значением которого должен быть путь к файлу с определением последовательностей, по одной на строку. После использования каждой последовательности knockd комментирует строку с использованной последовательностью и переключается на следующую.

В том числе имейте ввиду некоторые недостатки использования knockd. Во-первых, если процесс knockd внезапно «упадёт», вы не сможете получить удалённый доступ к маскируемой службе. Во-вторых, помните, что IP-пакеты могут доставлять к вашему серверу разными путями и приходить вовсе не в той последовательности, в которой были отправлены. Именно поэтому не стоит использовать слишком маленькое значение параметра seq_timeout.

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

Продвинутый Port Knocking

Можно установить knockd на серверах, находящихся за «основным» сервером, создав целую цепочку knockd-серверов.

Некоторые проекты, реализующие port knocking, решают проблему «replay»-атак за счёт использования криптоалгоритмов аутентификации. К таким проектам относятся, например, cryptknock, COK, и tariq.

Конечно, более продвинутые механизмы port knocking’а не оставят вам возможности «просто помнить» последовательность номеров портов, однако присутствие массы полезных «фишек» с лихвой перекроет этот «недостаток».

Всем интересующимся технологией port knocking’а рекомендуется посетить страницу portknocking.org.

Итоги

Когда специалист по безопасности скажет вам что весь этот ваш port knocking — лишь ещё один тонкий слой безопасности — он будет прав. Всегда ответственно подходите к защите непосредственно сервисов, как таковых, и не рассматривайте port-knocking как панацею. Port knocking будет полезен, чтобы скрыть запущенные службы от «случайных прохожих» и, если вы регулярно меняете секретные последовательности вашего knock-демона, то, вероятно, и предотвратит bruteforce-атаки по словарю учётных записей SSH.

Достаточно часто системные администраторы сталкиваются с дилеммой: необходимо иметь возможность подключиться к собственным системам из любой точки мира, но при этом не выставлять открытыми наружу служебные порты. Отчасти это решается использованием VPN, но такая возможность присутствует не всегда, а в некоторых ситуациях единственной возможностью может оказаться только прямое подключение к системе. Но есть и другой способ, называемый Port Knocking, дословно обозначающий «постучать в порт», но не просто постучать, а особым образом, после чего вы сможете получить доступ, стучите — и вам откроют.

Онлайн-курс по MikroTik
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном курсе по администрированию MikroTik. Автор курса, сертифицированный тренер MikroTik Дмитрий Скоромнов, лично проверяет лабораторные работы и контролирует прогресс каждого своего студента. В три раза больше информации, чем в вендорской программе MTCNA, более 20 часов практики и доступ навсегда.

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

Если вы хотите закрыть таким образом, скажем, терминальный сервер со слабой политикой паролей или приложение, работающее по незащищенному протоколу — то это плохая идея. Лучше займитесь обеспечением безопасности основных сервисов.

Кроме того, стучащийся клиент может находиться в публичной сети, за VPN-сервером или прокси, да даже за NAT провайдера, в этом случае доступ к сервису, хоть и кратковременно, могут получить все пользователи, находящиеся с ним на одном IP-адресе.

Также трафик может быть перехвачен и проанализирован, что позволит вычислить правильную последовательность «стука» и чем чаще вы будете использовать Port Knocking, тем быстрее можно будет это сделать.

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

Port Knocking с использованием портов

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

При реализации данного метода следует соблюдать правильную последовательность правил в цепочке INPUT межсетевого экрана и основным правилом, вокруг которого будет строиться наша система будет разрешение уже установленных и связанных соединений (ESTABLISHED, RELATED) и если вы настраивали роутер по нашей инструкции, то данное правило будет стоять вторым в цепочке, после «правила-пустышки» разрешающего доступ из локальной сети.

В нашем примере для получения доступа мы выберем последовательное обращение к портам 7890 и 9870, данные значения выбраны исключительно из удобочитаемости, на практике желательно разносить порты подальше друг от друга, так как такое сочетание достаточно легко «простучать» любым сканером сети, но к этому мы вернемся позже.

А пока добавим новое правило. На закладке General укажем: Chain — input, Protocol — tcp, Dst. Port — 7890.

port-knocking-mikrotik-001.png

На закладке Action добавим действия: Action — add src to address list, Address List — KNOCK-1, Timeout — 00:00:30

port-knocking-mikrotik-002.png

Данное правило при обращении к порту 7890 добавит адрес источника в список KNOCK-1 на 30 секунд, в течении этого времени мы должны успеть обратиться к следующему порту, чтобы получить доступ. Поэтому не следует указывать слишком высокие значения, на наш взгляд 30 секунд вполне достаточно для выполнения нужных команд в терминале, в ряде случаев можно незначительно увеличить таймаут.

Теперь добавим еще одно правило. Закладка General: Chain — input, Protocol — tcp, Dst. Port — 9870. Закладка Advanced: Src. Address List — KNOCK-1.

port-knocking-mikrotik-003.png

Закладка Action: Action — add src to address list, Address List — KNOCK-ACCEPT, Timeout — 00:01:00.

Данное правило добавит в лист KNOCK-ACCEPT адрес того источника, который обратится к порту 9870 и при этом находится в списке KNOCK-1, время жизни записи в новом листе — 1 минута, за это время мы должны будем установить соединение с устройством.

Тоже самое в терминале:

/ip firewall filter
add action=add-src-to-address-list address-list=KNOCK-1 address-list-timeout=30s chain=input dst-port=7890 protocol=tcp
add action=add-src-to-address-list address-list=KNOCK-ACCEPT address-list-timeout=1m chain=input dst-port=9870 protocol=tcp src-address-list=KNOCK-1

Оба этих правила следует расположить выше правила, разрешающего уже установленные соединения. Ниже этого правила добавим разрешающее для подключения к целевому порту, в нашем случае это будет порт Winbox — 8291.

На закладке General укажем: Chain — input, Protocol — tcp, Dst. Port — 8291, на Advanced: Src. Address List — KNOCK-ACCEPT, вкладку Action не трогаем, так как accept действие по умолчанию.

port-knocking-mikrotik-004.png

В терминале для этого выполните:

/ip firewall filter
add action=accept chain=input dst-port=8291 protocol=tcp src-address-list=KNOCK-ACCEPT

Данное правило следует расположить ниже разрешающего установленные и связанные подключения.

port-knocking-mikrotik-005.png

Теперь пару слов о том, как это работает. Первые два правила заполняют листы с адресом источника, чтобы попасть в последний — KNOCK-ACCEPT — нам нужно в течении 30 секунд обратиться к последовательно к портам 7890 и 9870. Затем в течении минуты мы должны подключиться к целевому порту, в нашем случае это Winbox. После чего все пакеты этого соединения пойдут по правилу, разрешающему уже установленные соединения. Таким образом по истечении минуты новых соединений установить не удастся, а уже установленные будут продолжать работать до отключения.

Что же, правила есть, теперь попробуем постучаться. В Linux для этого можно использовать команду netcatnc, для того чтобы постучаться на TCP-порт используйте:

nc -zw 1 XXX.XXX.XXX.XXX 7890
nc -zw 1 XXX.XXX.XXX.XXX 9870

Где XXX.XXX.XXX.XXX — IP-адрес вашего роутера. Ключ -z указывает сканировать порт без посылки данных, ключ -w задает таймаут в 1 секунду.

Для UDP-портов используйте:

nc -zu XXX.XXX.XXX.XXX 7890
nc -zu XXX.XXX.XXX.XXX 9870

port-knocking-mikrotik-006.png

В Windows постучаться немного сложнее, из стандартных средств можно использовать PowerShell:

Test-NetConnection XXX.XXX.XXX.XXX -Port 7890
Test-NetConnection XXX.XXX.XXX.XXX -Port 9870

Но данная команда будет ожидать ответа от узла в течении таймаута около 20 секунд и указанного нами времени для обращения ко второму порту может не хватить, в этом случае имеет смысл увеличить время ожидания. Также таким образом можно постучать только на TCP-порт.

port-knocking-mikrotik-006.png

Другой вариант — использование утилиты tcping, которая проще и удобнее в использовании, но позволяет опять таки стучать только в TCP-порты:

tcping -n 1 XXX.XXX.XXX.XXX 7890
tcping -n 1 XXX.XXX.XXX.XXX 9870

Ключ -n указывает количество посылаемых пакетов, в нашем случае один.

port-knocking-mikrotik-007.png

Также существуют специальные утилиты, позволяющие автоматизировать этот процесс, например, PortKnock, которая умеет работать как с TCP, так и с UDP портами и может обращаться последовательно к 4 портам.

port-knocking-mikrotik-008.png

Подведем небольшие итоги, Port Knocking с использованием портов достаточно прост в реализации, позволяет строить цепочки с нужным количеством портов и времени обращения к ним, но также имеет ряд недостатков. Прежде всего это ограниченность возможностей Windows, а ситуации бывают разные и не всегда есть время и возможности искать дополнительное ПО и качать его. Также близко расположенные порты без особых проблем можно простучать сканером.

Мы провели небольшой эксперимент, простая утилита Advanced Port Scanner без проблем простучала последовательности 7890-9870 и более сложную 7890-9870-8790, но не смог справиться с 17890-9870. Поэтому не используйте близко расположенные порты и устанавливайте минимальное время действия адресов в списках.

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

Port Knocking с использованием ICMP

Данный вариант отличается от классического тем, что вместо определенных портов мы будем использовать ICMP-пакеты различного размера. Это проще сделать стандартными средствами ОС и труднее поддается анализу при перехвате трафика, так как не столь бросается в глаза.

Несмотря на стандартный размер MTU в 1500 байт, это значение может быть уменьшено при использовании VLAN, VPN и т.д., поэтому мы не советуем использовать пакеты размером более 1000 байт, также учтите размер заголовков ICMP-пакета в 28 байт.

Просто выберите два (или более) произвольных числа до 1000, которые и будут вашими ключами для Port Knocking, в нашем случае это будут 250 и 209. Точно также, как и в предыдущем способе правила будут строиться относительно разрешения для уже установленных соединений.

Нам снова понадобится создать два правила для добавления адреса источника в соответствующие листы. В первом правиле укажем на General: Chain — input, Protocol — icmp, а на Advanced: Packet Size — 278 (250 + 28) — размер нашего первого пакета, на Action: Action — add src to address list, Address List — KNOCK-1, Timeout — 00:00:30.

port-knocking-mikrotik-009.png

Во втором зададим следующие значения: General: Chain — input, Protocol — icmp, Advanced: Src. Address List — KNOCK-1, Packet Size — 237 (209 + 28) — размер второго пакета, на Action: Action — add src to address list, Address List — KNOCK-ACCEPT, Timeout — 00:01:00.

Либо выполним в терминале:

/ip firewall filter
add action=add-src-to-address-list address-list=KNOCK-1 address-list-timeout=30s chain=input packet-size=278 protocol=icmp
add action=add-src-to-address-list address-list=KNOCK-ACCEPT address-list-timeout=1m chain=input packet-size=237 protocol=icmp src-address-list=KNOCK-1

Данные правила следует расположить выше правила разрешающего установленные и сопутствующие соединения. Остальные настройки полностью повторяют предыдущий способ.

Чтобы постучаться таким образом из Linux выполним:

ping XXX.XXX.XXX.XXX -s 250 -c 1
ping XXX.XXX.XXX.XXX -s 209 -c 1

Где ключ -s задает размер пакета (без учета заголовка), а ключ количество посылаемых пакетов, в нашем случае один.

В Windows синтаксис будет немного иной:

ping XXX.XXX.XXX.XXX -l 250 -n 1
ping XXX.XXX.XXX.XXX -l 209 -n 1

Здесь за размер пакета отвечает ключ -l, а за количество пакетов -n.

Принцип работы не отличается от предыдущего метода, получив ICMP-пакет размером в 250 байт адрес источника будет занесен в первый список. Затем в течении 30 секунд мы должны прислать второй пакет размером в 209 байт, в этом случае адрес будет занесен в список KNOCK-ACCEPT и в течении минуты с устройством можно будет установить соединение.

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

Онлайн-курс по MikroTik
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном курсе по администрированию MikroTik. Автор курса, сертифицированный тренер MikroTik Дмитрий Скоромнов, лично проверяет лабораторные работы и контролирует прогресс каждого своего студента. В три раза больше информации, чем в вендорской программе MTCNA, более 20 часов практики и доступ навсегда.

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • В чем плюсы windows 10 pro
  • Windows раскладка клавиатуры реестр
  • Как на windows 10 поставить драйвер на принтер
  • Подходят ли драйвера от windows vista к windows 7
  • Windows 7 какого года программа