- PVSM.RU - https://www.pvsm.ru -
минибар для гостиниц встраиваемый

В свете последних новостей вокруг Telegram провела некоторые эксперименты с протоколом MTProxy.
Основная идея: сделать ПО, выглядящее для Telegram-клиента как MTProxy-сервер, и осуществляющее дальнейший обмен данными со сторонними MTProxy-серверами.
В идеале, эти сторониие серверы должны обнаруживаться автоматически, и переключение между ними тоже должно происходить автоматически.
Код пишется на Python. Как экспериментальный вариант для быстрой реализации сойдёт, а если ПО окажется востребованным, то можно будет переписать на Си.
От протокола MTProxy реализуется только та часть, которая относится к соединениям, имитирующим TLS (FakeTLS, ключ прокси начинается с “ee”). Другие виды соединений кажутся более уязвимыми к DPI-вредительству, и оттого не очень полезными.
Предполагается, что ПО запускается на компьютере. Проверка работоспособности осуществляется в клиентах Telegram Desktop и Unigram под Windows.
С точки зрения клиента ПО выглядит как обычный MTProxy-сервер, подключение осуществляется штатным способом. Приняв соединение от клиента, ПО тут же пытается установить соединение со сторонним MTProxy-сервером. Если это удалось, то далее ПО все приходящие от клиента данные пересылает на сторонний сервер и наоборот, все приходящие от стороннего сервера данные пересылает на клиент. При этом происходит перекодирование, так как протокол шифрованный.
Если установить соединение со сторонним сервером не удалось, либо если соединение прервалось, соединение с клиентом тут же закрывается. Ожидаем, что обнаружив это, клиент Telegram пробует пересоединиться с нашим ПО, и всё повторяется.
Сторонний MTProxy-сервер выбирается как один из списка. Этот список может быть либо задан заранее, либо скачиваться с заданного URL.
Для экспериментов был нужен заведомо работающий прокси. Самый надёжный вариант — развернуть его на своей же машине. Был взят mtg (https://github.com/9seconds/mtg [1]), который запускался через mtg run config.toml, а конфигурационный файл config.toml был копией example.config.toml с минимальными изменениями:
secret = "ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c65617069732e636f6d"
bind-to = "127.0.0.1:3128"
[network]
proxies = [
"socks5://127.0.0.1:9150"
]
[defense.blocklist]
enabled = false
В такой конфигурации mtg принимает соединения на порту 3128 по протоколу MTProxy и обеспечивает обмен с серверами Telegram через SOCKS5-прокси на порту 9150.
Висящий запущенным Tor Browser как раз поднимает SOCKS5-прокси на порту 9150, которое может использоваться и другими приложениями. В нашем случае он нужен для обеспечения надёжной связи с серверами Telegram в обстановке DPI-вредительства.
Ключи прокси бывают:
“простые” — 32 шестнадцатеричных цифры ключа (т.е. 16 байтов)
“dd” — сначала буквы “dd”, далее 32 шестнадцатеричных цифры ключа
“ee” — сначала буквы “ee”, далее 32 шестнадцатеричных цифры ключа, далее закодированное в шестнадцатеричном виде имитируемое доменное имя (Telegram Desktop хочет, чтобы в нём было не менее четырёх букв после раскодирования)
“странные” — формат не соответствует ни одному из вышеперечисленных
При соединении клиент выбирает используемый протокол в зависимости от вида ключа. Ключи “ee” соответствуют протоколу с использованием FakeTLS. Исключительно им мы и уделим внимание.
Остальные виды ключей соответствуют “голому” протоколу MTProxy, без обёртки в TLS. Формат “dd” предполагает обфускацию, но, говорят, сейчас это не очень работоспособно. Со “странными” форматами я не разбиралась, там бывает что-то похожее на Base64. Протокол, по-видимому, тоже “голый”.
Несмотря на сомнения, отметим, что, не-“ee” ключи довольно распространены. При парсинге одного из списков прокси из 125 записей обнаружилось: “простых” - 16, “dd” - 29, “ee” - 34, “странных” - 46. Наводит на мысли, что раз их делают, то какой-то смысл в них, возможно, есть.
Документация от разработчиков Telegram вызывает печаль, поэтому, возможно, этот параграф стоило бы развернуть в отдельную статью. Пока же кратко об основных принципах.
В варианте с FakeTLS протокол MTProxy мимикрирует под HTTPS (HTTP/2 через TLS 1.2).
Клиент посылает TLS-пакет Client Hello. По сути, важны там только поле Random и расширение server_name. Random используется для хранения дайджеста, вычисляемого на основе содержимого пакета, 16-байтного ключа прокси и текущего времени. Сервер проверяет его соответствие. server_name содержит имитируемое доменное имя, и сервер может сверить его соответствие тому, что указано в текстовом представлении ключа (хотя особого смысла в этой сверке нету).
Прокси-сервер посылает сразу три TLS-пакета: Server Hello, Change Cipher Spec, Application Data. Тут важно поле Random, используемое для хранения дайджеста, вычисляемого на основе содержимого всех трёх пакетов, а также дайджеста из пакета Client Hello. Не очень понятно, почему для вычисления используется не только Server Hello, а все три пакета. Также не ясно, всегда ли их обязано быть именно три и именно таких.
Далее клиент и сервер условно-бесконечно гоняют туда-сюда пакеты Application Data и Change Cipher Spec. В первый оборачиваются данные “голого” протокола MTProxy, второй, по-видимому, просто игнорируется.
Содержимое первого пакета Application Data (который приходит совместно с Server Hello) игнорируется. Во втором пакете Application Data первые 64 байта совместно с 16-байтным ключом прокси используются для генерации ключей, используемых для шифрования остатков второго пакета, а также содержимого всех последующих пакетов Application Data.
ПО выступает в роли посредника между клиентом Telegram и сторонним MTProxy-сервером. Таким образом, дя клиента оно выглядит как MTProxy-сервер, а для стороннего сервера — как клиент.
ПО ожидает входящие соединения от клиента. Для каждого принятого соединения:
от клиента принимается пакет Client Hello, осуществляется его валидация
в пакете заменяется поле расширения server_name, пересчитывается поле Random
устанавливается соединение со сторонним прокси-сервером (про принцип выбора из списка - см. ниже)
изменённый пакет Client Hello отправляется серверу
от сервера принимается пакет Server Hello (плюс ещё два - см. предыдущий параграф), осуществляется его валидация
в пакете пересчитывается поле Random
изменённый пакет Server Hello (плюс ещё два) отправляется клиенту
далее в цикле, в направлениях от клиента к серверу и от сервера к клиенту пересылаются пакеты Application Data и Change Cipher Spec - Change Cipher Spec напрямую, Application Data после расшифрования и последующего зашифрования нужным ключом
при обрыве соединения с сервером, либо при получении невалидных данных соединения с клиентом и с сервером разрываются; предполагается, что в этом случае клиент повторит попытку установки соединения
Простейший алгоритм выбора прокси-сервера из имеющегося списка - просто выбирать следующий по списку, а когда список закончится, возвращаться в начало. На практике это не очень хорошо работает, т.к. в публичных списках работающими оказываются лишь немногие прокси, и при разрыве соединения пройдёт значительное время, пока будет идти перебор серверов.
На данный момент реализован следующий алгоритм. При получении от сервера валидного пакета Server Hello увеличивается на 1 счётчик для данного сервера. Когда устанавливается новое соединение с клиентом и требуется выбрать прокси-сервер из списка, берётся какой-то из серверов, имеющих положительное значение счётчика, а счётчик уменьшается на 1. Если нету ни одного положительного счётчика, сервер выбирается по простейшему алгоритму.
Такой алгоритм позволяет при случайном разрыве соединения пытаться установить соединение в первую очередь с теми серверами, с которыми уже случались успешные соединения.
Про это уже много писали — статья на Хабре [2], pull request к официальному клиенту [3] и commit с исправлением [4]
Суть проблемы — в Client Hello хотели из клиента передавать расширение TLS encrypted_client_hello с кодом 0xfe0d, но из-за ошибки в коде передавали несуществующее 0xfe02, по которому злоумышленники и могли отследить, что это именно Telegram (см. выше на картинке среди обведённого).
В ПО добавила workaround для починки пакета. Однако, никакой разницы не обнаружила. Те серверы, которые блокировались по DPI (в логах это выглядит как разрыв соединения после отправки Client Hello на сервер), так и продолжили блокироваться. Видимо, в моём случае либо блокируется по IP, либо DPI реагирует на другие признаки. Тут можно продолжать эксперименты. Менять можно практически все поля, благо, для протокола MTProxy в Client Hello ничего, кроме поля Random, не важно.
При использовании сторонних прокси-серверов возможны проблемы:
ненадёжность (и непредсказуемость) соединения
низкая (и непредсказуемая) скорость
утечка метаданных к владельцу стороннего сервера (хотя для самих сообщений обещают шифрование)
у прокси-серверов есть возможность принудительно добавлять “спонсорский канал”, а при автоматическом переключении прокси это ещё и происходит внезапно (но, хотя бы, их не будет более одного, т.к. при отключении от прокси соответствующий канал пропадает)
ну и звонки в Telegram ходят мимо прокси, поэтому если поломаны, то не починятся
Репозиторий проекта тут: https://codeberg.org/bokurwa/mtjumper-py.git [5]
Нужен Python.
git clone https://codeberg.org/bokurwa/mtjumper-py.git
cd mtjumper-py
pip install pycryptodome
python mtjumper.py
Если заглянуть в исходники, то можно увидеть там такие строки, которые может оказаться полезным поменять:
OUR_CONFIG_URL = "tg://proxy?server=127.0.0.1&port=13128&type=mtproto&secret=ee0000000000000000000000000000000078787878"
TARGET_CONFIG_URLS = [
"tg://proxy?server=127.0.0.1&port=3128&type=mtproto&secret=ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c65617069732e636f6d",
"@ https://raw.githubusercontent.com/SoliSpirit/mtproto/refs/heads/master/all_proxies.txt’,
]
OUR_CONFIG_URL — ссылка, которую можно открыть в Telegram, чтобы не вводить руками. Тут можно поменять порт, если не устраивает 13128, и адрес на 0.0.0.0, чтобы к нашему прокси можно было обращаться с других машин в локальной сети.
TARGET_CONFIG_URLS — список ссылок на прокси-серверы. Если в начале стоит @, то это ссылка для скачивания списка прокси (в текущей версии список скачивается только один раз при старте). По умолчанию там забиты URL тестового стенда и URL одного из списков прокси.
Автор: Bobr-Kurwa
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/tls/452207
Ссылки в тексте:
[1] https://github.com/9seconds/mtg: https://github.com/9seconds/mtg
[2] статья на Хабре: https://habr.com/ru/articles/1019200/
[3] pull request к официальному клиенту: https://github.com/telegramdesktop/tdesktop/pull/30513
[4] commit с исправлением: https://github.com/telegramdesktop/tdesktop/commit/407bf196417b80c903f6ae65d4c3202be72286d5
[5] https://codeberg.org/bokurwa/mtjumper-py.git: https://codeberg.org/bokurwa/mtjumper-py.git
[6] Telegram научился маскироваться под HTTPS: https://habr.com/ru/articles/461171/
[7] Исходники прокси от автора статьи [1]: https://github.com/alexbers/mtprotoproxy
[8] RFC 5246 — The Transport Layer Security (TLS) Protocol. Version 1.2: https://datatracker.ietf.org/doc/html/rfc5246
[9] RFC 6066 — Transport Layer Security (TLS) Extensions: Extension Definitions: https://datatracker.ietf.org/doc/html/rfc6066
[10] RFC 9849 — TLS Encrypted Client Hello: https://datatracker.ietf.org/doc/html/rfc9849
[11] MTProto transports: https://core.telegram.org/mtproto/mtproto-transports
[12] Источник: https://habr.com/ru/articles/1039034/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1039034
Нажмите здесь для печати.