Введение
Современные корпоративные системы фильтрации контента, от таких именитых производителей как Cisco, BlueCoat, FireEye имеют довольно много общего с более мощными их собратьями — DPI системами, которые усиленно внедряются на национальном уровне. Суть работы и тех и других в том, чтобы производить досмотр входящего и исходящего интернет трафика и, на основании черных/белых списков, принимать решение о запрете интернет-соединения. А так как и те, и другие в основах своей работы полагаются на схожие принципы, то и способы их обхода также будут иметь много общего.
Одной из технологий, позволяющей достаточно эффективно обходить как DPI, так и корпоративные системы, является технология домен-фронтинга. Ее суть состоит в том, что мы идем на заблокированный ресурс, прикрываясь другим, публичным доменом, с хорошей репутацией, который заведомо не будет блокирован ни одной системой, например google.com.
О данной технологии было написано уже достаточно много статей и приведено много примеров. Однако популярные и обсуждаемые в последнее время технологии DNS-over-HTTPS и encrypted-SNI, а также новая версия протокола TLS 1.3 дают возможность рассмотреть еще один вариант домен-фронтинга.
Разбираемся с технологией
Сначала немного определимся с основными понятиями, чтобы у всех было понимание who is who и зачем все это нужно. Мы упомянули механизм eSNI, работа которого будет рассмотрена дальше. Механизм eSNI (encrypted Server Name Indication) – защищенный вариант SNI, доступный только для протокола TLS 1.3. Основная суть – шифровать в том числе информацию о том, к какому домену отправляется запрос.
А теперь давайте рассмотрим работу механизма eSNI на практике.
Допустим, у нас есть интернет-ресурс, который блокируется современным DPI решением (возьмем к примеру, знаменитый торрент-трекер — rutracker.nl). При попытке захода на сайт торрент-трекера — мы видим стандартную заглушку провайдера о том, что ресурс блокируется:
На сайте РКН это домен действительно числится в стоп-листах:
При запросе whois — видно, что сам домен «спрятан» за облачным провайдером Cloudflare.
Но в отличие от «специалистов» из РКН, более технически подкованные сотрудники из билайна (или наученные горьким опытом нашего знаменитого регулятора) не стали тупо банить сайт по IP -адресу, а внесли в стоп-лист именно доменное имя. В этом легко убедиться, если посмотреть, какие еще домены прячутся за этим же IP-адресом, посетить один из них и увидеть, что доступ не заблокирован:
А как же так получается? Каким образом провайдерский DPI узнает, на какой из доменов идет мой браузер, ведь все коммуникации происходят по протоколу https, а подмены сертификатов https от билайна мы вроде пока не замечали? Уж не ясновидящий ли он или за мной идет слежка?
Попробуем ответить на это вопрос, взглянув на трафик через wireshark
На скриншоте видно, что сперва браузер получает IP-адрес сервера через DNS, потом происходит стандартное TCP-рукопожатие с сервером назначения, а затем браузер пытается установить ssl-соединение с сервером. Для этого он передает пакет SSL Client Hello, в котором присутствует имя исходного домена в открытом виде. Это поле необходимо фронтенд-серверу cloudflare для того, чтобы правильно маршрутизировать соединение. Вот тут-то нас и ловит провайдерский DPI, разрывая наше соединение. При этом мы не получаем никакой заглушки от провайдера, и видим стандартную ошибку браузера как будто сайт отключен или просто не работает:
Теперь давайте включим механизм eSNI в браузере, как это написано в инструкции для Firefox :
Для этого мы открываем страницу конфигурации Firefox about:config и активируем следующие настройки:
network.trr.mode = 2;
network.trr.uri = https://mozilla.cloudflare-dns.com/dns-query
network.security.esni.enabled = true
После этого мы проверим корректность работы настроек на сайте cloudflare по ссылке и попробуем фокус с нашим торрент-трекером еще раз.
Вуаля. Наш любимый трекер открылся, без каких-либо VPN и прокси-серверов. Давайте теперь посмотрим на дамп трафика в wireshark, что же произошло.
На сей раз пакет ssl client hello не содержит в явном виде домен назначения, а вместо этого в составе пакета появилось новое поле — encrypted_server_name — именно там и содержится значение rutracker.nl, и расшифровать это поле может только фронтенд сервер cloudflare. А раз так, то провайдерскому DPI не остается ничего кроме как умыть руки и разрешить такой трафик. А других вариантов с шифрованием и нет.
Итак, как работает технология в браузере — мы посмотрели. Теперь давайте попробуем применить ее для более специфичных и интересных вещей. И для начала мы научим тот же curl использовать eSNI для работы с TLS 1.3, а заодно посмотрим, как работает сам домен-фронтинг на основе eSNI.
Домен-фронтинг с eSNI
Ввиду того, что curl для подключения по протоколу https использует стандартную библиотеку openssl, прежде всего нам необходимо обеспечить поддержку eSNI именно там. В master-ветках openssl поддержки eSNI пока что нет, поэтому нам необходимо скачать специальную ветку openssl, скомпилировать и установить ее.
Клонируем репозиторий с гитхаба и компилируем как обычно:
$ git clone https://github.com/sftcd/openssl
$ cd openssl
$ ./config
$ make
$ cd esnistuff
$ make
Далее — клонируем репозиторий с curl и конфигурируем его компиляцию с использованием нашей собранной openssl библиотеки:
$ cd $HOME/code
$ git clone https://github.com/niallor/curl.git curl-esni
$ cd curl-esni
$ export LD_LIBRARY_PATH=/opt/openssl
$ ./buildconf
$ LDFLAGS="-L/opt/openssl" ./configure --with-ssl=/opt/openssl --enable-esni --enable-debug
Здесь важно правильно указать все каталоги, где находится openssl (в нашем случае — это /opt/openssl/) и проследить, чтобы процесс конфигурации прошел без ошибок.
В случае успешной конфигурации — мы увидим строку:
WARNING: esni ESNI enabled but marked EXPERIMENTAL. Use with caution!
$ make
После успешной сборки пакета мы воспользуемся специальным bash-файлом из состава openssl для настройки и запуска curl. Скопируем его в каталог с curl для удобства:
cp /opt/openssl/esnistuff/curl-esni
и выполним тестовый https-запрос на сервер cloudflare, одновременно записав DNS и TLS пакеты в Wireshark.
$ ESNI_COVER="www.hello-rkn.ru" ./curl-esni https://cloudflare.com/
В ответе сервера помимо множества отладочной-информации от openssl и curl мы получим HTTP-ответ с кодом 301 от cloudflare.
HTTP/1.1 301 Moved Permanently
< Date: Sun, 03 Nov 2019 13:12:55 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: max-age=3600
< Expires: Sun, 03 Nov 2019 14:12:55 GMT
< Location: https://www.cloudflare.com/
что свидетельствует о том, что наш запрос был успешно доставлен до сервера назначения, услышан и обработан.
Теперь давайте посмотрим на дамп трафика в wireshark, т.е. что увидел в данном случае провайдерский DPI.
Видно, что сначала curl обратился к DNS серверу за публичными eSNI ключом для сервера cloudflare — TXT DNS запрос на _esni.cloudflare.com (пакет №13). Затем, используя openssl-библиотеку, curl отправил TLS 1.3 запрос на сервер cloudflare в котором поле SNI было зашифровано публичным ключом, полученным на предыдущем этапе (пакет №22). Но, помимо поля eSNI, в составе SSL-hello пакета было вставлено еще и поле с обычным — открытым SNI, которое мы можем указать в произвольном порядке (в данном случае — www.hello-rkn.ru).
Данное поле открытого SNI никак не учитывалось при обработке серверами cloudflare и лишь являлось маскировочным для провайдерского DPI. Сервер cloudflare принял наш ssl-hello пакет, расшифровал eSNI, извлек оттуда оригинальный SNI и обработал его как ни в чем не бывало (сделал все именно так, как планировалось при разработке eSNI).
Единственное, за что в данном случае можно зацепиться с точки зрения DPI — первичный DNS запрос на _esni.cloudflare.com. Но мы сделали DNS запрос открытым лишь для того, чтобы показать, как данный механизм работает изнутри.
Чтобы окончательно выбить почву из-под ног DPI мы используем уже упомянутый механизм DNS-over-HTTPS. Небольшое пояснение – DOH – протокол, который позволяет защититься от атаки «человек посередине» за счет отправки DNS-запроса по протоколу HTTPS.
Выполним запрос повторно, но в это раз публичные eSNI ключи мы получим по протоколу https, а не DNS:
ESNI_COVER="www.hello-rkn.ru" DOH_URL=https://mozilla.cloudflare-dns.com/dns-query ./curl-esni https://cloudflare.com/
Дамп трафика запроса представлен на скриншоте ниже:
Видно, что сперва curl обращается к серверу mozilla.cloudflare-dns.com по протоколу DoH (https соединение на сервер 104.16.249.249), чтобы от них получить значения public ключей для шифрования SNI, а затем уже к серверу назначения, прикрываясь при этом доменом www.hello-rkn.ru.
Помимо указанного выше DoH резолвера mozilla.cloudflare-dns.com мы можем использовать и другие популярные сервисы DoH, например, от знаменитой корпорации зла.
Выполним такой запрос:
ESNI_COVER="www.kremlin.ru" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/
И получим ответ:
< HTTP/1.1 301 Moved Permanently
< Date: Sun, 03 Nov 2019 14:10:22 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=da0144d982437e77b0b37af7d00438b1a1572790222; expires=Mon, 02-Nov-20 14:10:22 GMT; path=/; domain=.rutracker.nl; HttpOnly; Secure
< Location: https://rutracker.nl/forum/index.php
< CF-Cache-Status: DYNAMIC
< Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
< Server: cloudflare
< CF-RAY: 52feee696f42d891-CPH
В данном случае мы обратились на заблокированный сервер rutracker.nl, использовав при этом DoH-резолвер dns.goolge (тут нет опечатки, теперь у знаменитой корпорации появился свой домен первого уровня) и прикрылись уже другим доменом, блокировать который строго-настрого запрещено всем DPI под страхом смертной казни. По полученному ответу можно понять, что наш запрос был удачно обработан.
В качестве дополнительной проверки того, что провайдерский DPI реагирует на открытый SNI, который мы передаем в качестве прикрытия — мы можем выполнить запрос к rutracker.nl прикрывшись каким-нибудь другим запрещенным ресурсом, например другим «хорошим» торрент-трекером:
$ ESNI_COVER="rutor.info" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/
Ответа от сервера мы не получим, т.к. наш запрос будет заблокирован DPI- системой.
Небольшое заключение к первой части
Итак, нам удалось показать работоспособность eSNI с помощью openssl и curl и проверить работу домен-фронтинга, основанного на eSNI. Таким же образом мы можем адаптировать наши любимые инструменты, использующие библиотеку openssl, для работы «под прикрытием» других доменов. Подробнее об этом — в наших следующих статьях.
Автор: karelovao