Как стать автором
Обновить

Туннели и VPN, устойчивые к DPI

Время на прочтение 10 мин
Количество просмотров 154K
Мы живем в интересное время. Я бы даже сказал, в удивительное. По одну сторону мы видим неких лиц, которые очень хотят знать, о чем между собой разговаривают другие люди, и очень хотят указывать им, что можно читать, а что нельзя. С другой стороны граждане, которые хотят отстоять свои права тайны личной переписки и свободного получения информации, и не хотят, чтобы факты этой самой переписки и получения этой самой информации были использованы против них. Бонусом страдает огромное количество сторонних сайтов, сервисов и бизнесов, которых задевает «ковровыми блокировками».

Но нет, эта статья не об обществе, а о технологиях.

image

Техническая грамотность людей, благодаря всему происходящему, тоже растет. Если раньше слова «VPN» и «прокси» были знакомы только IT-специалистам, то теперь даже домохозяйки их знают, и более того — используют то, что эти слова означают.

Вообще, новости в последнее время приходят весьма занятные. Например, предоставление услуг VPN и аналогичных для шифрования трафика и обхода блокировок ныне наказуемо, а в Китае так за это вообще сажают в тюрьму. А не так давно РКН начал применять анализ пакетов для блокировки протокола MTProxy. Можно также обратиться к опыту стран-собратьев, которые наиболее преуспели в таких делах: Китая, Ирана, Казахстана, Венесуэлы. В Венесуэле, например, вполне конкретно блокируют прямые подключения к Tor и обфусцированный трафик к мостам. Исходя из всего этого, можно предположить, что будущее ждет нас тоже очень интересное, особенно, если «ответственные лица» перестанут устраивать тупые факапы раз за разом, а будут действовать умнее и изощреннее.

На Хабре неоднократно в комментариях озвучивали прогнозы как дальше может происходить борьба с технологиями шифрования для обычных граждан. Анализируя озвученные мысли и посмотрев на свидетельства из других стран, я попробовал предположить, в какую сторону могут дальше двинуться меры по ограничению связи. DistortNeo и shifttstas подкинули еще несколько интересных идей, и в итоге я пообещал el777 все-таки дописать эту статью.

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

Способы «определения» типа трафика у DPI можно разбить на две группы:

  • Сигнатурный анализ. А именно, разбирание пакета «по косточкам», сопоставляя заголовки и структуру с образцами, и таким образом определение его предназначения. Таким образом детектируются многие туннели, например OpenVPN, L2TP/IPSec, SOCKS, и др.
  • Предварительный анализ паттернов обмена трафиком, например, соотношения входящего/исходящего потока, периодичность запросов-ответов и другие критерии позволят отделить «настоящий трафик» какого-то протокола и туннель, лишь маскирующийся под него.

image

Можно разбить трафик на несколько групп и предположить, что будут делать с каждой из них.

  1. «Явные» VPN, туннели и прокси (OpenVPN, L2TP/IPSec, SOCKS, и др.) Обычные VPN и туннели вполне могут блокироваться автоматически, как, например, это происходит в Китае и Венесуэле. Если каким-то организациям или компаниям оно нужно для работы — пусть регистрируются и сертифицируются, о чем вполне конкретно говорит российский закон, упомянутый выше. С прокси все еще проще — что HTTP, что SOCKS передают адреса и содержимое в открытом виде, что вообще не создает никаких проблем для выборочного «резания» запросов и прослушки передаваемой информацией.
  2. Технологии «двойного назначения», например, SSH. Через небольшое время после установления сессии, скорость режется до черепашьей, так, что в консоли работать еще хоть как-то можно, а вот серфить и качать что-либо уже нет. То, что это создает проблемы при обычной работе, никого не волнует (что не раз нам демонстрировал РКН за недавнее время).
  3. Узкоспецифические протоколы, типа месседжеров, игровых клиентов, и т.д.
  4. Соединения, тип которых определить не удается.

Для пунктов 3 и 4 вполне возможны «белые списки» (в которые, например, заносятся подсети официальных игровых серверов или «правильных» месседжеров, и всего того, что владельцы серверов пожелают задекларировать и оформить как надо, чтобы их не трогали, по аналогии с теми, что уже сейчас есть у РКН для доменов и IP-адресов). А тех, кого в этих списках нет, ждет та же участь, что и п.1 или п.2, правда вполне возможна не тупая блокировка или обрезание скорости, а предварительно упомянутый выше анализ паттернов обмена в целях определения, является ли трафик «чистым» или «подозрительным».

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

Про разные ICMP и DNS туннели можно даже не вспоминать — большой объем трафика «куда не надо» по ним тоже автоматически вызывает подозрения.

5. TLS и SSL, HTTPS. Резать подчистую невозможно, поскольку это автоматически означает блокировку всего Интернета. Анализ паттернов не имеет смысла, поскольку веб-серфинг — как раз-таки и есть основное предназначение использование HTTPS. Из всего вышеперечисленного, SSL/TLS на 443 порту выглядит самым «не подозрительным» и надежным вариантом. Следовательно, давайте и попробуем замаскироваться под него.

image

Маскируемся


Для рассмотрения было решено выбрать решения Streisand и SoftEther.

Streisand — целый набор различных сервисов: OpenConnect/AnyConnect, OpenVPN, stunnel, Shadowsocks, WireGuard. Все это ставится в автоматическом или полуавтоматическом режиме «под ключ», и на выходе пользователь получает сконфигурированный сервер, а также файлы и подробную документацию по настройке клиентов.

SoftEther — VPN-сервер, который может поднимать L2TP/IPsec, OpenVPN, SSTP, и другие протоколы, а также имеет свой собственный протокол «SSL-VPN», который, по заявлениям авторов, неотличим от обычного HTTPS-трафика.

Итак…

OpenConnect/AnyConnect. Опенсорсная реализация протокола AnyConnect SSL от Cisco. При установлении соединения видны не только пакеты TLS (TCP), но и DTLS (UDP). DTLS в принципе тоже много где используется «в мирных целях», но это уже совсем не похоже на «обычный HTTPS». Впрочем, если порезать UDP-трафик на фаерволе, то AnyConnect сразу переключается обратно на TCP и со стороны выглядит, опять же, целиком и полностью как обычный TLS, и даже аутентификация внутри зашифрованного тоннеля проходит почти как в HTTP.

Shadowsocks. Шифрованный SOCKS-прокси. Судя по всему, при желании может быть детектирован, однако существуют плагины, маскирующие его под «чистый HTTPS». Так же есть плагин для работы через websockets, но об этом чуть позже.

WireGuard. Судя по описанию, имеет хорошо закрученное шифрование и механизм установки сессии, но весь обмен происходит по UDP. Wireshark определяет тип пакетов как нечто совсем невнятное, а какое мнение обо всем происходящем сложится у стороннего DPI — очень и очень большой вопрос. Upd: Новые версии определяют Wireguard однозначно как Wireguard, так что ответ на вопрос очевиден.

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

SoftEther. Выглядит как HTTPS, но с одним подвохом. Кроме непосредственно TLS over TCP активно шлет пачками UDP-пакеты. Как удалось выяснить в документации, UDP может использоваться для ускорения передачи данных в том случае, когда он не зарезан на фаерволе. Данный функционал отключается в конфигурации, и после его отключения все становится как надо.

SSTP. VPN-прокотол от компании Microsoft. Нативно поддерживается в Windows, вспомогательным софтом в GNU/Linux. Со стороны выглядит как HTTPS, и Wireshark это вполне подтверждает.

Но это еще не все


Предположим, вы установили на хост VPN-сервер или конец туннеля и сконфигурировали, чтобы он слушал 443 порт. Казалось бы, все прекрасно, но есть одно НО: если мы маскируемся под HTTPS, проверить, что по факту висит на 443 порту можно просто попробовав уткнуться в этот порт простым браузером или CURL'ом, или еще каким угодно способом. В некоторых статьях подобный метод называется «опережающим подключением», и, как упоминается, уже вполне используется в Китае.

Следовательно, нам необходимо чтобы по 443 порту у нас отвечал самый обычный и порядочный веб-сервер. И вот тут встает интересная проблема.

Ни у одного из вышеперечисленных сервисов в основной документации не нашлось описания рабочего механизма port sharing'а. Вариант с SSLH не подходит, хотя бы потому, что sslh не способен разделить трафик между HTTPS и вышеуказанными сервисами. Как минимум, потому что если тип трафика без полной расшифровки смог отличить sslh — то сможет и DPI.

Большинство манов, наподобие этого, предлагают использовать Server Name Indication (SNI) — расширение TLS, позволяющее указывать имя хоста, и потом с помощью HAProxy, sniproxy и других тулов раскидывать подключения по сервисам. Проблема в том, что в современных реализациях TLS указанное при использовании SNI имя хоста передается plain text'ом, то есть в незашифрованном виде, и, следовательно, тоже может быть подсмотрено и использовано в дальнейшем.

Поэтому, будем импровизировать, и тут мне на ум пришли два варианта.

Port knocking


image

Port knocking как раз предназначен для активации «скрытых сервисов» на сервере. Например, подобным образом часто закрывают «наружу» порт, на котором висит SSH-демон, чтобы избежать брутфорса и использования 0-day уязвимостей. В классическом варианте (см. например реализацию демона knockd) под нокингом обычно понимают попытки установки соединения или посылку пакетов на определенные порты хоста в определенной последовательности, в результате чего демон вас «опознает» как своего, и активирует правило фаерволла, открывающее доступ на определенный порт только с вашего IP.

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

Для этого есть нокер с романтичным названием Labean.

Дано: наш сервер, на котором на 443 порту крутится Nginx c корректно настроенными сертификатами и выдает какой-нибудь вполне безобидный контент, например, GIF'ки с котиками, ISO-образы дистрибутивов GNU/Linux, или зеркало Википедии и библиотеки Мошкова.

При этом в конфиге Nginx затаились строки вида

 location ~ ^/somesecret/(.*) {
    auth_basic      "Administrator Login";
    auth_basic_user_file  /var/www/.htpasswd;
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_pass http://127.0.0.1:8080/$1;
  }

Когда мы хотим подключиться к скрытому сервису, мы переходим браузером или делаем запрос CURL'ом по адресу вида
https://ourserver.org/somesecret/vpn/on
проходим стандартную авторизацию, после чего нокер, получив и обработав наш запрос, выполнит команду на открытие доступа к скрытому сервису для нашего IP-адреса, например что-то вроде
iptables -t nat -A PREROUTING -p tcp -s {clientIP} --dport 443 -j REDIRECT --to-port 4443
после чего мы поднимаем туннель.

Далее через N секунд (да, поддерживается автоматический таймаут) выполняется команда, отменяющая вышеуказанное правило фаервола, и таким образом наше установленное подключение остается висеть, но подключиться к сервису снова даже с нашего IP без повторного дерганья нокера уже не выйдет.

Либо можно не использовать автоматический таймаут, а вручную деактивировать сервис, запросив URL наподобие указанного выше, только с /off в конце.

Таким образом можно сконфигурировать даже несколько разных сервисов, в том числе используя IPv6 (v6-адреса в заголовке типа X-Real-IP также поддерживаются).

Нокер написан на Go, не требует внешних зависимостей, прост как топор, и вполне себе работает. Исходники, подробное описание и примеры конфига nginx и init-скриптов можно найти на Github:
https://github.com/uprt/labean

Websockets


image

Вторая идея озарила еще более неожиданно: лучшее средство замаскировать туннель внутри HTTPS — использовать общепринятые стандартные инструменты. Современные Web-технологии давно уже содержат решение для установления связи поверх TCP между браузером и сервером, и имя ему Websocket (RFC 6455). Клиент формирует особый HTTP-запрос, на который сервер отвечает определенным образом, и после небольшого хендшейка мы можем начинать передачу данных по этому же TCP-соединению. Со стороны, соответственно, все выглядит в точности как обычный HTTPS и не требуется установки никаких дополнительных соединений.

Еще одним существенным преимуществом варианта с WS является то, что веб-сокеты — стандартная и распространенная технология, и они поддерживаются многими CDN, например, Cloudflare даже на бесплатном тарифе. Таким образом, это дает нам возможность повысить надежность нашей схемы: при блокировке по IP вашего CDN/proxy сервера вы сможете все равно подключиться к нему через CDN, либо же наоборот по умолчанию работать с этим вашим VPN/proxy сервером через CDN, скрывая его реальный адрес от сторонних наблюдателей.

Реализаций WS-туннелей существует несколько (есть даже вариант на Haskell), я для теста взял wstunnel, сделанный на nodejs и не прогадал, все завелось легко и с первого раза.

Лишь один нюанс был не прояснен в документации. Для запуска клиента предлагается указывать просто wss://-адрес, типа

wstunnel -t 33 wss://server:443

В нашем же случае, необходимо «отделить» ws-подключения к серверу туннелирования от запросов «обычного» сайта. Изучив исходники wstunnel, я пришел к выводу, что ничего не помешает удлинить URI после имени хоста каким-нибудь уникальным идентификатором:

wstunnel -t 33 wss://ourserver.org:443/hiddenws/

и оказался прав: все заработало с первого раза

Снова рассмотрим наш сервер, на котором на 443 порту запущен Nginx c каким-нибудь безобидным сайтом.

В конфиг нужно добавить proxy-проброс для нашего Websockets-туннеля:

location /hiddenws {
    proxy_pass http://127.0.0.1:8081;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
  }

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

Про selinux
Если у вас RHEL подобный дистрибутив, и включен SELinux, и в логах nginx видны ошибки типа
2018/07/05 13:28:03 [crit] 7724#0: *11 connect() to 127.0.0.1:8081 failed (13: Permission denied) while connecting to upstream, client: IP_ADDRES, server: _, request: «GET /hiddenws/?dst=localhost:22 HTTP/1.1», upstream: «127.0.0.1:8081/hiddenws/?dst=localhost:22»,

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

semanage port -a -t http_port_t -p tcp 22
semanage port -m -t http_port_t -p tcp 22
semanage port -a -t http_port_t -p tcp 8081


Спасибо Renatk за то что обратил внимание и предложил решение.


Единственный минус такого подхода — кроме непосредственно SOCKS- или VPN-клиента на устройстве также нужно иметь клиент wstunnel, что может быть сложным в случае использования смартфона или другого «недесктопного» устройства.

Кроме того, существует плагин v2ray для shadowcocks, позволяющий использовать websockets как транспорт для shadowsocks. Найти его можно здесь: https://github.com/shadowsocks/v2ray-plugin

Несколько советов


— Установите на VPN-сервере какое-нибудь стандартное значение MTU, например 1400;
— Назначьте вашему VPN-серверу 2 IP-адреса. На один он будет принимать подключения к VPN/прокси, а с другого будет уходить исходящий трафик;
— Для «выходного» IP-адреса закройте все порты, отключите ответ на ICMP ping;
— Пропишите для вашего сервера какое-нибудь безобидное reverse DNS имя, похожее на пул доступа интернет-провайдера, например, gateway-001.somehomeisp.net;
— Для резолва доменов клиентами вашего VPN/прокси используйте DNS-сервера проекта OpenNIC;
Все эти меры помогут пресечь выявление туннелей недобросовестными ресурсами (подробнее здесь).

Вместо заключения


image

Как на самом деле будет развиваться социально-техническое противостояние, мы знать не можем — только предполагать. Воплотятся ли в жизнь предположения, изложенные в статье, не воплотятся — узнаем со временем, как и о том, что будет дальше. Да, маскировка под HTTPS тоже не панацея от всего — например, делать это может быть опасно, если будут введены какие-либо реальные наказания за «использование несертифицированных средств шифрования»/ознакомление с заблокированными ресурсами/etc., или бесполезно, если всех обяжут устанавливать некий «сертификат безопасности», как это некоторое время назад хотели сделать в Казахстане.

Пока еще, к счастью, ни до того, ни до другого не дошло ни в одном из известных нам государств, и если оно случится — это знак, что пора эвакуироваться, причем не из страны, а с планеты.
Берегите себя.
Теги:
Хабы:
+96
Комментарии 175
Комментарии Комментарии 175

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн