У многих из нас есть родственники и друзья, которые не очень хорошо разбираются в компьютерах и периодически просят помочь настроить то или иное программное обеспечение. В таких случаях помогать можно подключившись к компьютеру пользователя через программу удаленного администрирования. Давайте рассмотрим вариант подключения к удаленным компьютерам без использования проприетарного ПО.
Для подключения к компьютерам других пользователей можно воспользоваться такими программами, как TeamViewer, AnyDesk, Ammyy и т.п. Но использование проприетарных решений всегда ставит нас в зависимость от вендора, и иногда это вызывает непредвиденные проблемы. Например, пользователи могут столкнуться с внезапным появлением сообщения «Обнаружено коммерческое использование», после которого программа прекращает нормально функционировать в бесплатном режиме. Для предприятия логичным шагом будет покупка лицензии, но если среди наших пользователей только родственники и друзья, то покупка лицензии представляется не всегда лучшим выбором. Существует программное обеспечение, распространяющееся под свободными лицензиями и позволяющее решить нашу задачу без дополнительных затрат. Исторически программы для удаленного администрирования предназначены для работы в локальной сети, и главным ограничением для их использования является отсутствие прямой связи с компьютером пользователя.
Для предлагаемого мной решения обязательным условием является наличие публичного IP-адреса, через который будет подниматься SSH-туннель. Варианты организации SSH-туннелей хорошо описаны в сети, например, можно почитать тут. Условно будем называть администратором человека, оказывающего помощь, а пользователем — человека, к компьютеру которого требуется подключиться. Рассматривать будем вариант, когда администратор имеет публичный IP-адрес. Для однократных подключений этот вариант выглядит наиболее удобным, потому что не требует постоянно включенного ПО ни на сервере, ни на клиенте.
Предположим, что администратор работает на компьютере PC1, а подключиться требуется к пользовательскому компьютеру PC2. Оба компьютера под управлением ОС Windows.
![](https://habrastorage.org/getpro/habr/upload_files/4a8/0a3/911/4a80a3911a55ace19d36bf9b164c7cd8.png)
IP-адреса указаны для примера, и в скриптах их надо заменять на свои. В случае использования внешнего SSH-сервера (например, VPS/VDS, которые сейчас зачастую можно найти дешевле стоимости публичного IP у некоторых провайдеров) изменения потребуются в организации SSH-туннеля, что не должно представлять особой сложности и в статье не описывается.
Суть предлагаемой схемы работы:
На публичном IP открывается порт для входящих соединений и пробрасывается на администраторский компьютер PC1, на котором на этом порте запускается SSH-сервер.
На пользовательском компьютере PC2 запускается SSH-клиент, который подключается к SSH-серверу PC1 и пробрасывает на него локальный порт.
На PC2 запускается VNC-сервер, ожидающий соединения на локальном порте PC2.
На PC1 запускается VNC-клиент, который подключается к локальному порту PC1, проброшенному по SSH с PC2.
То есть компьютер PC1 будет выступать одновременно в роли SSH-сервера и VNC-клиента, а пользовательский компьютер PC2 — SSH-клиента и VNC-сервера.
Требования к функциональности:
Удаленный доступ должен работать только тогда, когда это ожидается администратором и пользователем.
Не должно быть возможности подключиться к сеансу третьему лицу или перехватить передаваемые данные (предполагаем, что используемое ПО не содержит уязвимостей, а используемые компьютеры не содержат вредоносного ПО).
Пользователь не должен испытывать существенных затруднений при развертывании ПО на своей стороне.
Дистрибутивы для разных пользователей должны быть независимы, механизм создания дистрибутива для нового пользователя должен быть максимально упрощен.
Для реализации будем использовать:
TightVNC я выбрал из-за наличия актуальной сборки VNC-сервера под Windows под лицензией GNU GPL, и возможности передавать файлы между сервером и клиентом. Из дистрибутивов потребуются файлы: libcrypto.dll, ssh.exe, ssh-keygen.exe, sshd.exe, tvnserver.exe и tvnviewer.exe. Решение проверялось на Windows 7 и Windows 10 (разных версий), но должно работать на любых ОС, где можно запустить SSH и VNC.
В Windows 10 SSH-клиент предустановлен (как минимум, начиная с версии 1809) по пути "%SystemRoot%\System32\OpenSSH\ssh.exe", но для универсальности SSH-клиент включен в архив.
Для каждого пользователя будет создаваться отдельный независимый дистрибутив. Все действия выполняются запуском bat-файлов.
Администраторская часть дистрибутива
Для начала рассмотрим состав файлов на стороне администратора PC1 (SSH-сервер и VNC-клиент):
authorized_keys — содержит открытый ключ SSH-клиента, необходим для подключения клиента к нашему серверу;
ssh_host_rsa_key — закрытый ключ SSH-сервера;
sshd_config — минимально необходимый конфиг SSH-сервера;
run_sshd.bat — скрипт запуска SSH-сервера;
ssh_host_rsa_key.pub — открытый ключ SSH-сервера (вообще говоря, для запуска сервера не нужен, используется на клиенте);
libcrypto.dll, sshd.exe и tvnviewer.exe — ранее распакованные бинарники.
Запуск сервера осуществляется запуском файла run_sshd.bat.
set ssh_bin=%~dp0
"%ssh_bin%sshd.exe" -f "%~dp0sshd_config" -h "%~dp0ssh_host_rsa_key" -E "%~dp0sshd.log"
Используемые параметры:
%~dp0
— путь к каталогу запускаемого скрипта;-f config_file
— путь к файлу конфигурации;-h host_key_file
— путь к закрытому ключу сервера;-E log_file
— путь к log-файлу (опционально).
Бинарники не обязательно держать в том же каталоге, можно разместить их в общем каталоге для всех клиентов и указать путь через переменную ssh_bin
.
У используемого sshd версии 8.1.0.0p1-Beta есть особенности: для запуска обязательно надо указывать полный путь к sshd.exe, а authorized_keys должен находиться по пути "%USERPROFILE%.ssh\authorized_keys". То есть перед запуском сервера открытый ключ клиента обязательно должен быть добавлен в "%USERPROFILE%.ssh\authorized_keys". Либо при запуске sshd можно использовать опцию -o AuthorizedKeysFile=<...>
.
Содержимое sshd_config:
PubkeyAuthentication yes
PasswordAuthentication no
SyslogFacility LOCAL0
Port 11111
Описание опций:
PubkeyAuthentication
— разрешает аутентификацию на основе открытого ключа;PasswordAuthentication
— запрещает аутентификацию с использованием пароля;SyslogFacility
— категория журналирования для сохранения лога в файл;Port
— номер порта, который слушает сервер.
Если в логах sshd.log возникает ошибка "WARNING: UNPROTECTED PRIVATE KEY FILE!", то надо поправить права на файле:
icacls.exe "ssh_host_rsa_key" /remove "%COMPUTERNAME%\%USERNAME%"
icacls.exe "ssh_host_rsa_key" /inheritance:r
icacls.exe "ssh_host_rsa_key" /grant "%COMPUTERNAME%\%USERNAME%:(R)"
В некоторых случаях (если sshd видит проблему с правами на файле с ключами) на SSH-клиенте возникает ошибка: "Permission denied (publickey,keyboard-interactive)". При этом в логах SSH-сервера при включенной отладке (опция -d
) можно увидеть: "Bad permissions. Try removing permissions for user: ..." В этом случае надо поправить права на файле authorized_keys, изменить их можно тем же способом, что и для файла ssh_host_rsa_key выше.
Пользовательская часть дистрибутива
На стороне пользователя PC2 (SSH-клиент и VNC-сервер) нам потребуются следующие файлы:
id_rsa — закрытый ключ клиента;
id_rsa.pub — открытый ключ клиента (для запуска на клиенте не требуется - используется на сервере);
known_hosts — содержит публичный IP-адрес SSH-сервера и его открытый ключ;
tightvnc.reg — настройки tightVNC-сервера;
prepare.bat — скрипт подготовки (запускается на клиенте однократно);
run.bat — скрипт запуска SSH-клиента и VNC-сервера;
libcrypto.dll, ssh.exe, tvnserver.exe — ранее распакованные бинарники.
Перед запуском на стороне пользователя необходимо произвести настройки, которые объединены в файле prepare.bat. Этот скрипт выполняется однократно при первичной настройке компьютера пользователя и делает следующее:
1. Настраивает права доступа к закрытому ключу (иначе SSH-клиент не запускается).
icacls.exe "%~dp0id_rsa" /remove "%COMPUTERNAME%\%USERNAME%"
icacls.exe "%~dp0id_rsa" /inheritance:r
icacls.exe "%~dp0id_rsa" /grant "%COMPUTERNAME%\%USERNAME%:(R)"
2. Настраивает VNC-сервер. Здесь возможны два варианта. Если прав локального администратора у пользователя нет, то настройки VNC надо импортировать в ветку HKEY_CURRENT_USER и запускать tvnserver.exe от имени пользователя.
reg.exe import tightvnc.reg
Но это ограничит возможности удаленного помощника: нельзя будет управлять приложениями, требующими повышения привилегий. Если пользователь готов дать удаленному помощнику права локального администратора, то настройки надо экспортировать в ветку HKEY_LOCAL_MACHINE и запускать tvnserver.exe как сервис. Для установки tvnserver как сервиса надо запустить (от имени администратора):
regedit /s "%~dp0tightvnc.reg"
"%~dp0tvnserver.exe" -install
sc config tvnserver start= demand
Последняя строка нужна для того, чтобы наш сервис запускался по требованию (только когда это нужно пользователю).
Запуск на стороне пользователя выполняется с помощью файла run.bat. Вариант без прав локального администратора:
start tvnserver.exe
"%~dp0ssh.exe" -fN -n -R 55555:127.0.0.1:33333 username@1.2.3.4 -p 11111 -i "%~dp0id_rsa" -o "UserKnownHostsFile=""%~dp0known_hosts""" -E "%~dp0ssh.log"
tvnserver.exe -controlapp -shutdown
Вариант с правами локального администратора:
"%~dp0tvnserver.exe" -start
"%~dp0ssh.exe" -fN -n -R 55555:127.0.0.1:33333 username@1.2.3.4 -p 11111 -i "%~dp0id_rsa" -o "UserKnownHostsFile=""%~dp0known_hosts""" -E "%~dp0ssh.log"
"%~dp0tvnserver.exe" -stop
В скрипте сначала запускается VNC-сервер, потом устанавливается соединение с SSH-сервером. Консольное окно c SSH-клиентом будет висеть до конца сеанса. По нему, кстати, можно диагностировать проблемы: если окно пропало, значит что-то пошло не так и надо смотреть в ssh.log. Расширенное журналирование можно включить опцией -vvvv
.
Важно! Порядок запуска сервера и клиента имеет значение: запускать SSH-клиент имеет смысл только при работающем SSH-сервере.
Параметры запуска SSH-клиента:
-fN
— фоновый режим;-n
— предотвращает чтение из stdin (используется в фоновом режиме);-R
— определяет реверсный туннель, перенаправляющий трафик с порта 55555 компьютера PC1 на порт 33333 компьютера PC2;username@ip
— %USERNAME% пользователя, под которым запущен sshd на PC1, и публичный IP SSH-сервера;-p
— публичный порт SSH-сервера (для простоты считаем, что порт прокидывается через NAT без изменения номера);-i
— путь к закрытому ключу клиента;-o UserKnownHostsFile
— путь к файлу с публичным ключом сервера;-E
— путь к log-файлу.
Подготовка tightvnc.reg
Для подготовки конфига TightVNC надо запустить VNC-сервер (например, на виртуальной машине), настроить порт для соединений (в нашем случае 33333) и ограничить доступ к удаленному управлению. Остальные настройки на усмотрение администратора. Предлагаю доступ ограничить следующим образом: разрешить только Loopback Connections — установить флаги "Allow loopback connections" и "Allow only loopback connections". Еще можно настроить правила подключения.
![](https://habrastorage.org/getpro/habr/upload_files/1da/4cd/0c3/1da4cd0c322b12bfcd0a352fb18158f4.png)
После настроек надо выгрузить ветку из реестра: HKEY_LOCAL_MACHINE\Software\TightVNC\Server
(или HKEY_CURRENT_USER\Software\TightVNC\Server
, если VNC-сервер запускался без расширенных привилегий). Также для исключения ситуации, когда у пользователя были в реестре неподходящие настройки VNC-сервера, можно добавить в начало reg-файла строки [-HKEY_LOCAL_MACHINE\Software\TightVNC\Server]
и/или [-HKEY_CURRENT_USER\Software\TightVNC\Server]
.
После запуска run_sshd.bat на сервере и run.bat на клиенте администратор может подключиться к компьютеру пользователя командой
tvnviewer.exe 127.0.0.1:55555
Генератор дистрибутива
Для упрощения создания дистрибутива для нового пользователя предлагается сделать простой генератор, который представляет собой обычный bat-файл. Текст максимально простой; единственное, на что можно обратить внимание, это формирование файла known_hosts. В нём перед отрытым ключом должен находиться IP-адрес SSH-сервера. Для этого IP-адрес записывается во временный файл (без перевода строки), а после объединения IP и ключа временный файл удаляется. IP-адрес и номера портов надо указывать свои, для примера использовались следующие:
1.2.3.4
— публичный IP-адрес администратора;11111
— открытый порт на публичном IP-адресе, который пробрасывается на открытый порт 11111 на PC1 (требуется корректно настроить firewall на всех узлах);33333
— порт на PC2, на котором VNC-сервер ожидает соединение;55555
— порт на PC1, к которому подключается VNC-клиент (на PC1).
В качестве имени пользователя
username
надо указать имя аккаунта администратора, под которым запускается SSH-сервер. Тестировались только варианты с именем латинскими буквами без пробелов. Как поведет себя система, если имя будет кириллицей или содержать пробелы, не проверялось. Также для читабельности убраны разные проверки на ошибки, потому что в bat это выглядит несколько монструозно. Для демонстрации рабочей концепции обработка ошибок не обязательна.
Основной скрипт генерации:
set ssh_srv_ip=1.2.3.4
set ssh_srv_user=%USERNAME%
set ssh_srv_port=11111
set vnc_host_port=33333
set vnc_local_port=55555
mkdir ssh_cli-vnc_srv\
mkdir ssh_srv-vnc_cli\
@rem ключи пользователя
ssh-keygen -t rsa -b 4096 -f ./id_rsa -C "" -q -N ""
copy id_rsa.pub ssh_srv-vnc_cli\authorized_keys
move id_rsa ssh_cli-vnc_srv\
move id_rsa.pub ssh_cli-vnc_srv\
echo @rem "%%~dp0tvnserver.exe" -start>ssh_cli-vnc_srv\run.bat
echo start tvnserver.exe>>ssh_cli-vnc_srv\run.bat
echo "%%~dp0ssh.exe" -fN -n -R %vnc_local_port%:127.0.0.1:%vnc_host_port% %ssh_srv_user%@%ssh_srv_ip% -p %ssh_srv_port% -i "%%~dp0id_rsa" -o "UserKnownHostsFile=""%%~dp0known_hosts""" -E "%%~dp0ssh.log">>ssh_cli-vnc_srv\run.bat
echo tvnserver.exe -controlapp -shutdown>>ssh_cli-vnc_srv\run.bat
echo @rem "%%~dp0tvnserver.exe" -stop>>ssh_cli-vnc_srv\run.bat
@rem ключи администратора
ssh-keygen -t rsa -b 4096 -f ./ssh_host_rsa_key -C "" -q -N ""
<nul set /p dummy=%ssh_srv_ip% >tmp
copy /b tmp+ssh_host_rsa_key.pub ssh_cli-vnc_srv\known_hosts
del tmp
move ssh_host_rsa_key ssh_srv-vnc_cli\
move ssh_host_rsa_key.pub ssh_srv-vnc_cli\
Генератор формирует ключи и bat-файлы, которые отличаются для каждого клиента, остальные файлы можно просто скопировать в нужные каталоги.
copy libcrypto.dll ssh_cli-vnc_srv\
copy ssh.exe ssh_cli-vnc_srv\
copy tvnserver.exe ssh_cli-vnc_srv\
copy tightvnc.reg ssh_cli-vnc_srv\
copy prepare.bat ssh_cli-vnc_srv\
copy run_sshd.bat ssh_srv-vnc_cli\
copy sshd_config ssh_srv-vnc_cli\
copy libcrypto.dll ssh_srv-vnc_cli\
copy sshd.exe ssh_srv-vnc_cli\
copy tvnviewer.exe ssh_srv-vnc_cli\
Резюме
В качестве итога перечислю всё, что нужно сделать.
Первичная настройка на стороне администратора:
Открыть порт для SSH-сервера, настроить firewall.
Сгенерировать дистрибутив, скорректировать bat при необходимости (например, для работы с повышенными привилегиями в системе пользователя).
Разместить authorized_keys по пути "%USERPROFILE%.ssh\authorized_keys" (добавить в файл строку с новым ключом). Ограничить права доступа к файлам с ключами.
Упаковать пользовательскую часть в архив и передать его пользователю любым доступным способом (например, временно запустив web-сервер на компьютере администратора).
Первичная настройка на стороне пользователя:
Пользователь должен получить архив со своей частью файлов. Если для распаковки используются встроенные средства Windows, то сначала надо убрать у скачанного файла поток Zone.Identifier (в свойствах файла нажать кнопку «разблокировать»).
После распаковки архива пользователю требуется запустить файл prepare.bat. В зависимости от того, что приготовил администратор, может потребоваться запуск с повышенными привилегиями.
Порядок установки соединения:
Администратор запускает run_sshd.bat на PC1 (SSH-сервер).
Пользователь запускает run.bat на PC2 (SSH-клиент и VNC-сервер, в зависимости от настроек может потребоваться подтверждение повышения привилегий).
Администратор запускает VNC-клиент: tvnviewer.exe 127.0.0.1:55555
Если всё настроено корректно, то теперь администратор может управлять компьютером пользователя.