Практический пример того, как автоматизация процессов работы с исходным кодом и репозиториями (читать нужно: CI/CD) может легко и неожиданно “выйти боком”: токен с правами полного доступа к репозиториям Python и PyPI на GitHub долгое время находился в открытом доступе.

Разбор инцидента из первых рук позволяет понять, как так вышло: наружу отправился локальный файл .pyc, случайно оставшийся в локальной (общей для процесса сборки) директории, которая требовалась для работы приложения в Docker-контейнере; ну и не менее случайно – в этом .pyc-файле сохранился токен доступа.



Комментировать »

Кстати, очередная типовая академическая атака на процессоры: в этот раз – процессоры Intel и Indirect Branch Predictor (IBP) поверх Branch Target Buffer (BTB) – то есть, косвенное извлечение данных, относящихся к соседнему процессу на том же CPU, через подстановку фиктивных ветвлений и измерение состояний аппаратуры, пытающейся оптимизировать исполнение кода.

Такие дефекты, при современной архитектуре процессоров, в принципе неустранимы, поэтому статьи по теме, переоткрытой Spectre/Meltdown (о самом направлении именно в процессорах известно с 80-х годов прошлого века, если не раньше), сейчас идут одна за одной стройным потоком. Обратите внимание, что атаки этого типа требуют исполнения специального кода, в несколько тепличных условиях, на том же процессоре, где исполняется и процесс с “секретными данными” и известным внутренним устройством.

(Статья на Bleeping Computer.)



Комментировать »

Google убирает из Chrome доверие оконечным сертификатам, выпущенным Entrust/AffirmTrust, начиная с 1 ноября 2024 года.

Интересно, что, как написано, реализуется это всё по SCT-меткам в сертификатах: то есть, не важно, какие ещё параметры указаны в самом сертификате, учитываются только метки времени в SCT, выданных логами Certificate Transparency (такие метки от доверенных логов должны входить в состав сертификата, иначе он тоже будет считаться недоверенным). Очередная иллюстрация того, насколько процесс валидации серверного сертификата в браузере может отличаться от “обычной реализации”.



Комментировать »

Сообщают про неожиданную замену кода JS-библиотеки Polyfill.io после смены администратора домена или администратора веб-сервера, раздающего код (насколько можно понять). Библиотека используется в качестве внешнего ресурса на многих сайтах, а в результате изменения кода некоторые браузеры пользователей перенаправляются на сторонние сайты. Это происходит без ведома веб-мастера, понятно, который может ничего и не замечать, поскольку для него перенаправлений нет.

Я, например, в 2019 году (но, конечно, и многим раньше) писал про внешние библиотеки на сайтах буквально следующее:

На первый взгляд может показаться, что библиотека выполняет только те функции, ради которых её использовал веб-разработчик. Но это не так: программный код библиотеки может быть изменён владельцем узла, с которого библиотека загружается (либо третьей стороной на пути до клиента), после чего она сможет реализовать какой угодно набор функций, например, собрать пользовательские данные со страницы, изменить её содержание, сделать просмотр недоступным, перенаправить браузер на произвольный адрес и так далее, и тому подобное. В некоторых современных браузерах существует механизм базовой защиты от подмены исходного кода встраиваемых библиотек под названием Subresource Integrity (SRI), но на практике этот механизм ни на каких сайтах не используется.

[…]

Администратор узла, с которого загружается библиотека, волен как угодно вмешиваться в её код. Реально передаваемый клиентскому браузеру файл может выбираться индивидуально, другими словами, атака, связанная с подменой библиотеки, может быть точно настроена на:

конкретные IP-адреса (т.е. конкретных пользователей);
конкретные типы браузеров;
определённое время;
любую комбинацию этих настроек.

То есть даже если администратор исходного веб-ресурса, test.ru в нашем примере, пытается как-то отследить корректность работы узлов, на которых находятся используемые библиотеки, он не в состоянии этого сделать: для IP-адресов, с которых проводится проверка, всё может работать корректно, при этом для других посетителей сайта картина окажется совсем другой.

(Отмечу, в скобках, что хотя бы SRI сейчас начали иногда использовать, но внедрение SRI – всё равно редкий случай.)



Комментарии (2) »

Очередное подтверждение того, что “диагонализация” неустранима для сколь-нибудь сложного процессора: типовая манипуляция (вряд ли эту схему нужно считать уязвимостью или атакой) под названием TIKTAG, раскрывающая “соседние” метки указателей на процессорах ARM при помощи перебора, подкреплённого измерением состояния кеша. (Кстати, метод логически совпадает с некоторыми атаками из области TLS.) Я не так давно писал, что архитектура современных процессоров на самом базовом уровне гарантирует, что подобные манипуляции возможны:

Базовая логика таких атак – использование “оракулов”, сигналы которых пробивают границы, устанавливаемые (формально) аппаратной архитектурой процессора для фрагментов программного кода. Тут нужно учитывать, что границы эти только декларируются, а в реальности – сигналы через них проходят (иначе тут не было бы предмета), потому что процессору необходимо оптимизировать исполнение кода и доступ к памяти.



Комментировать »

В продолжение предыдущей записки, про имена и TLS на веб-серверах, – хороший практический пример. Веб-сервер Nginx использует, обычно, OpenSSL в качестве библиотеки, реализующей TLS. Из-за особенностей кода и библиотечных вызовов, данный веб-сервер не может применять ограничения по версиям TLS для виртуальных хостов, сконфигурированных по SNI в блоках server. Это буквально происходит потому, что не согласованы области видимости имён и статусы TLS-соединения. Другими словами: для того, чтобы начать сопоставлять описания TLS-конфигураций из блоков server, Nginx должен знать имя хоста, по которому выбирается блок. Данное имя передаётся в ClientHello (SNI). Однако к моменту, когда Nginx это имя получает через соответствующий (обратный) вызов функции, в OpenSSL уже создан контекст с поддерживаемой версией TLS – ведь эта версия и выбирается по ClientHello.

Что это означает? Например, означает, что с именами в TLS нужно тщательно всё проверить. Так, если TLS-клиент (браузер) приходит с указанием поддерживаемой версии TLS 1.3 и такая версия указана для сервера по умолчанию, то отключить эту версию директивами ssl_protocol для прочих виртуальных хостов не выйдет – будет согласовываться TLS 1.3, а если согласовать 1.3 не получится, то возникнет ошибка. При этом сама директива ssl_protocol допускается в блоке server, однако в документации её низкая избирательность и, таким образом, относительная бесполезность, тоже отражены: указывать ssl_protocol нужно только для сервера по умолчанию (default/default_server).

Предположим, что для сервера Nginx указана полезная опция ssl_reject_handshake в блоке виртуального хоста по умолчанию (default_server). Это предотвращает успешные TLS-подключения с неверными именами. Соответственно, если в такой конфигурации попытаться указать для прочих виртуальных хостов какие-то иные наборы допустимых версий TLS в ssl_protocol, то применяться они не будут: сервер всегда раньше упрётся в default_server, хоть для этого варианта и прямо указана отмена TLS-хендшейка, не указано никаких уникальных имён хостов и, предположим, даже, – как обычно, – не указана директива ssl_protocol, которая будет инициализирована значениями по умолчанию. Это, конечно, выглядит не слишком логично, но происходит потому, что данный веб-сервер и не пытается обрабатывать имена из контекста TLS-сессии, “выгружая” задачу в сторону TLS-библиотеки (OpenSSL – см. выше).

Вернёмся к конкретной версии TLS – к 1.3. Если при наличии default_server с ssl_reject_handshake в конфигурации присутствуют виртуальные хосты, для которых поддержка 1.3 невозможна (например, с ГОСТ-TLS без совместимых шифронаборов), то, даже если в блоке server для этих имён прямо указаны только версии ниже 1.3, всё равно возникнет довольно занимательная проблема: некоторые клиенты-браузеры смогут подключаться к серверу по проблемному имени хоста, а некоторые – нет. Потому что с клиентом, который заявляет в ClientHello поддержку 1.3, сервер всё равно будет пытаться установить соединение 1.3 и, определив недоступность этой версии, возвратит ошибку (Alert в терминах TLS). А с клиентом, который 1.3 не заявляет, соединение будет успешно и без всяких проблем устанавливаться по версии 1.2 (например). Всё по причине игнорирования блока ssl_protocol веб-сервером. Решением является отключение 1.3 для сервера по умолчанию, то есть – для всех имён хостов сразу.



Комментировать »

В TLS для веба важны имена. Например, при подключении по TLS для HTTPS серверу нужно отправить клиенту TLS-сертификат сервера. Если серверных сертификатов несколько, то сервер должен как-то выбрать подходящий по имени. Тут речь не про промежуточные сертификаты, которые добавляются в набор (bundle), а именно про оконечные сертификаты. Если TLS-cертификат не соответствует имени, которое ожидает клиент-браузер, то сессия не будет корректной на стороне клиента. Данный момент, вместе с желанием держать много виртуальных хостов на одном IP-адресе и под одним веб-сервером, является постоянным источником ошибок администрирования.

Посмотрим, что вообще происходит в ходе обработки HTTPS-сеанса и как сервер может определить соответствие имён. В начале TLS-сессии клиент (браузер) обычно передаёт имя сервера в специальном блоке данных – SNI (Server Name Indication). Сервер видит это имя и может использовать его для поиска нужного сертификата и нужного виртуального хоста. Однако клиент определяет имя из своих собственных соображений.

Типовой вариант: в контекст TLS-сессии имя узла SNI приходит из запроса пользователя через DNS. Почему “через DNS”? Потому что браузер должен был найти IP-адрес, к которому он подключается по TCP. При прочих равных, браузер получил IP-адрес из DNS по имени хоста из URL, заданного пользователем. Это действительно важный момент, который, почему-то, инженеры DevOps регулярно выкидывают из области рассмотрения, посчитав “элементарным”. Однако, во-первых, если пользователь ввёл имя, которое не удалось “разрезолвить” в IP-адрес, то и штатного TLS-соединения не случится, хоть бы такое имя и было указано в сертификате (такое вполне возможно). Это, предположим, “элементарная часть”, которая, тем не менее, никак не отменяет возможности указания в SNI имени без DNS-адреса, то есть, без A-, AAAA-записей. Во-вторых, кто угодно может настроить какое угодно допустимое DNS-имя так, чтобы оно показывало на заданный IP-адрес сервера, а потом отправить ссылки с этими именем хоста ничего не подозревающим пользователям. В этом случае, пользователь, штатно набрав это самое “какое угодно” имя хоста, успешно направит браузер на заданный сервер, но браузер обратится туда с “неожиданным” именем в SNI. Если это имя вдруг совпадёт с указанным в предоставленном по умолчанию валидном TLS-сертификате с успешным подтверждением, то браузер даже не выдаст предупреждения, а в сертификате может быть очень много разных имён. (Но, во многих случаях, можно смело считать валидный серверный TLS-сертификат с верным именем достаточной мерой защиты от “ложных” хостов для HTTPS. Особенно, если веб-сервер основного имени хоста доступен по выделенному IP-адресу.)

Основной вывод предыдущего абзаца такой: сервер ориентируется на SNI, но нельзя считать, что SNI, присланное клиентом, как-то привязано к серверным настройкам, соответствует DNS, “защищено сертификатом” и вообще укладывается в формат и ожидания, отражённые в конфигурационном файле веб-сервера. И SNI вообще может отсутствовать. (Кроме того, тут не рассматривается случай, когда данные SNI скрываются от третьей стороны – метод ECH и пр.) На стороне веб-сервера бывает возможность отклонить TLS-соединение, использующее “неожиданное” имя хоста.

На начальном этапе соединения, до получения HTTP-запроса, сервер видит только имя из сеанса TLS. Но это не означает, что и сами HTTP-запросы будут адресованы этому же имени хоста – в HTTP-запрос тоже можно вписать что угодно, TLS никак семантику HTTP не фиксирует. Конечно, ситуация не является типичной для браузеров, но она вполне возможна. Это тоже нужно учитывать при обработке разных внутренних переменных на серверной стороне: контекст TLS, контекст HTTP – разные контексты.



Комментировать »

Как ни странно, но продолжает развиваться тестовый сервер TLS 1.3 – добавил поддержку ещё пары гибридных криптосистем с постквантовой стойкостью: P256Kyber768 и P384Kyber768. До этого сервер поддерживал только X25519Kyber768, которая есть в Chrome/Chromium (и на веб-серверах Google, например). Два новых варианта – совсем редкие.

Удивительно, но P384Kyber768, тем не менее, заявлена в свежих версиях браузера Microsoft Edge под Windows, где включение данной криптосистемы спрятано за флаг (chrome://flags). Да, Edge построен на базе Chrome/Chromium, однако в TLS-стеке там есть дополнительная постквантовая криптосистема. При этом, у P384Kyber768 пока нет индекса в реестре IANA, а у ещё более редкой, в плане поддержки, P256Kyber768 (то же самое, но кривая P-256) – индекс (0x639A) уже имеется.

Вообще, гибридные P256Kyber768 и P384Kyber768 устроены аналогично X25519Kyber768: тут часть Kyber768 вообще совпадает, а в качестве присоединяемого протокола Диффи-Хеллмана (DH) выступают, вместо X25519, ECDH/P-256 и ECDH/P-384.

На сервере я попутно исправил старую ошибку с обработкой точек кривой P-521, из-за которой поддержка DH на этой кривой была давно выключена (это не связано с постквантовыми криптосистемами). Теперь она снова включена – такую версию ECDH использует Firefox.

Изменена обработка TLS-записей, составляющих ответ. Теперь веб-страница с сервера, в большинстве случаев, приходит в нескольких TLS-записях. Это довольно занятный момент: из-за использования постквантовых криптосистем, HTML-ответ, в котором перечисляются ключи и сообщения, теперь может быть довольно большим. Представьте, что клиент приходит с заявленной поддержкой X25519Kyber768 и P384Kyber768, при этом сразу присылает ключи в X25519Kyber768 (1216 байтов). Однако сервер предлагает перейти к P384Kyber768, отправляя HelloRetryRequest, после чего клиент присылает уже ключи P384Kyber768 (ещё 1249 байтов). Всё это должно отразиться в результатах на странице. Чтобы, так сказать, выровнять результаты с постквантовыми криптосистемами и без них – я уменьшил максимальную используемую длину TLS-записи.

Сомневаюсь, что можно найти типовой популярный браузер с большим разнообразием поддерживаемых постквантовых “гибридов”, но вот рабочую сборку curl в контейнере – найти нетрудно (там же, кстати, есть и пара специальных сборок браузеров).



Комментировать »

Docker Hub заблокировал доступ с российских IP-адресов. Последовало множество насмешливых инструкций в стиле “простейшего перехода на зеркала и прокси”. Проблема тут, впрочем, привычная: в практике Docker, в сопутствующих скриптовых обвязках (всякий CI/CD), и так не всё хорошо с аутентификацией источников сборок и самих “контейнеров”. Методы, типа DCT (Docker Content Trust), конечно, есть, это известно. Вопрос в их эффективности и использовании на практике. А прокси и “разбегание” зеркал – тут только добавляют ненадёжных слоёв. Кстати, целевые манипуляции часто удобнее проводить именно с точками выхода прокси и точками входа зеркал (вспомните, как работает разное перемешивание и, скажем, onion routing – тут ситуация обратная).

(Update, 09/06/24: доступ вернули через несколько дней.)



Комментарии (2) »

Кстати, интересуются примером того, как, более или менее конкретно, может что-то сломать сообщение TLS ClientHello от браузера, если в этом сообщении добавлены параметры Kyber768.

Вообще, нетрудно представить следующую ситуацию. Предположим, есть некоторый диспетчер соединений, работающий в паре с пакетным фильтром. Этот фильтр анализирует пакет данных (то есть, последовательность байтов, имеющую конкретную длину) по заданным правилам на уровне значений байтов внутри пакета и расстояний между байтами с заданными значениями. Например, определяет, что пакет представляет собой начало TLS-соединения с некоторыми свойствами и – перенаправляет этот пакет, как и всю сессию, на какой-то заданный входной узел. Этот узел – уже может быть элементом балансировщика трафика, или входить в состав какого-то механизма DPI, предназначенного для борьбы с возможными атаками, или играть какую-то ещё роль. Базовые правила для фильтра позволяют узнавать заявленные версии TLS (это значения полей в сообщении), определять предлагаемые клиентом криптосистемы – всё по значениям байтов на определённых позициях. Скажем, таким способом можно детектировать начало TLS-сеанса с поддержкой ГОСТ-TLS, со стороны клиента, чтобы на стороне сервиса перенаправить соответствующие сессии на сервер, настроенный конкретно для ГОСТ.

Реализация фильтра не только не проводит разбора сессии, но даже не анализирует пакет с ClientHello как содержащий TLS-сообщение ClientHello – фильтр работает только с байтами и их примитивными индексами. Более того, так как фильтр пакетный, то правила индексирования в нём написаны от значения длины пакета, которое взято из каких-то “максимально обобщённых” соображений. Эти соображения, определяющие длину, не учитывают формата ClientHello и возможного увеличения размеров этого сообщения сразу на несколько сотен байтов. В результате – ожидаемые индексы сдвигаются за допустимые границы, даже в следующий пакет, фильтр перестаёт срабатывать так, как срабатывал раньше, но начинает новые сообщения от браузера Chrome считать дефектными, сбрасывая соответствующее TCP-соединение.



Комментировать »

Один из интересных аспектов GPS-спуфинга состоит в том, что для определения результата действия подменного сигнала нужно учитывать возможную коррекцию, выполняемую тем аппаратом, система управления которого попала под спуфинг. Простейший пример: предположим, некоторый летающий дрон, согласно команде, должен висеть на одном месте; точка фиксируется по сигналу GNSS (GPS), но такое зависание подразумевает непрерывную подстройку и аэродинамическую коррекцию – необходимо, как минимум, компенсировать снос ветром; тогда, если спуфинг-сигнал уводит координаты, получаемые приёмником GPS, то система управления начнёт компенсировать возникающее ложное отклонение – аппарат придёт в движение, несмотря на то, что система будет полагать, что таким образом сохраняет координаты и “висит” на месте.

Движение будет соответствовать спуфинг-сигналу, но, так сказать,с точностью до знаков: если ложный сигнал уводит координаты на восток, то аппарат полетит на запад. Понятно, что “фиксированная помеха” с простой, не изменяющейся, подменой координат, тоже приведёт к похожим результатам. Однако с помощью динамической помехи – можно плавно управлять аппаратом. Конечно, постановка подобной уводящей помехи – сложная задача, и отчасти тут всё равно могла бы помочь инерциальная система (в случае “фиксированной помехи” – инерциальная система оказывается куда более эффективной в роли элемента противодействия). Тем не менее, если верить сообщениям в СМИ, схожая ситуация недавно сложилась с тракторами, управляемыми по сигналам GPS, уже только под воздействием обычных помех, а не динамического спуфинга.

О принципах, на которых работает GPS-спуфинг (или GNSS-спуфинг) – я довольно подробно писал почти восемь лет назад.



Комментировать »