Домен-фронтинг на базі TLS 1.3

Запровадження

Домен-фронтинг на базі TLS 1.3
Сучасні корпоративні системи фільтрації контенту, від таких іменитих виробників як 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). При спробі заходу на сайт торрент-трекера ми бачимо стандартну заглушку провайдера про те, що ресурс блокується:

Домен-фронтинг на базі TLS 1.3

На сайті РКН це домен дійсно значиться у стоп-листах:

Домен-фронтинг на базі TLS 1.3

При запиті whois видно, що сам домен «захований» за хмарним провайдером Cloudflare.

Домен-фронтинг на базі TLS 1.3

Але на відміну від «фахівців» з РКН, більш технічно підковані співробітники з білайна (або навчені гірким досвідом нашого знаменитого регулятора) не стали тупо банити сайт за IP-адресою, а внесли в стоп-лист саме доменне ім'я. У цьому легко переконатися, якщо подивитися, які ще домени ховаються за цією IP-адресою, відвідати один з них і побачити, що доступ не заблокований:

Домен-фронтинг на базі TLS 1.3

А як же так виходить? Яким чином провайдерський DPI дізнається, на який з доменів йде мій браузер, адже всі комунікації відбуваються за протоколом https, а заміни сертифікатів https від білайну ми поки не помічали? Чи не ясновидець він чи за мною йде стеження?

Спробуємо відповісти на це питання, поглянувши на трафік через wireshark

Домен-фронтинг на базі TLS 1.3

На скріншоті видно, що спочатку браузер отримує IP-адресу сервера через DNS, потім відбувається стандартне TCP-рукостискання із сервером призначення, а потім браузер намагається встановити ssl-з'єднання з сервером. Для цього він передає пакет SSL Client Hello, в якому є ім'я вихідного домену у відкритому вигляді. Це поле необхідно фронтенд-серверу cloudflare для того, щоб правильно маршрутизувати з'єднання. Ось тут нас і ловить провайдерський DPI, розриваючи наше з'єднання. При цьому ми не отримуємо ніякої заглушки від провайдера, і бачимо стандартну помилку браузера як сайт відключений або просто не працює:

Домен-фронтинг на базі TLS 1.3

Тепер давайте увімкнемо механізм eSNI у браузері, як це написано в інструкції для Firefox :
Для цього ми відкриваємо сторінку конфігурації Firefox про: конфігурації та активуємо наступні налаштування:

network.trr.mode = 2;
network.trr.uri = https://mozilla.cloudflare-dns.com/dns-query
network.security.esni.enabled = true

Після цього ми перевіримо коректність роботи налаштувань на сайті cloudflare за посиланням та спробуємо фокус із нашим торрент-трекером ще раз.

Домен-фронтинг на базі TLS 1.3

Вуаль. Наш улюблений трекер відкрився, без будь-яких VPN та проксі-серверів. Давайте тепер подивимося на дамп трафіку в wireshark, що ж сталося.

Домен-фронтинг на базі TLS 1.3

Цього разу пакет 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.

Домен-фронтинг на базі TLS 1.3

Видно, що спочатку 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/

Дамп трафіку запиту представлений на скріншоті нижче:

Домен-фронтинг на базі TLS 1.3

Спершу 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

Домен-фронтинг на базі TLS 1.3

У даному випадку ми звернулися на заблокований сервер rutracker.nl, використавши при цьому DoH-резолвер dns.google (тут немає друкарської помилки, тепер у знаменитої корпорації з'явився свій домен першого рівня) і прикрилися вже іншим доменом, блокувати який суворо заборонено всім 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, для роботи «під прикриттям» інших доменів. Докладніше про це у наших наступних статтях.

Джерело: habr.com

Додати коментар або відгук