Бэкдор в пакете XZ Utils для Linux был выпущен 24 февраля 2024 года и обнаружен 28 марта. Внедрялся в SSHD (Secure Shell Daemon) — часть OpenSSH, службу для Unix-подобных ОС, позволяющую удалённым пользователям выполнять команды консоли. «Отравленный» SSHD выполняет команды консоли от неизвестного центра, владеющего скрытым ключом. Бэкдор пассивен: центр сам должен пройти брандмауэр и подключиться к компьютеру. Угроза была обнаружена и остановлена ещё в нестабильных выпусках, до того, как был нанесён масштабный урон.

Предварительно откомпилированный вредоносный код для архитектуры x86-64 тайно встроен в динамическую библиотеку сжатия данных LibLZMA. Неизвестный хакер два года втирался в доверие, пытаясь взять на себя часть работы программиста-одиночки. Он глубоко знает архитектуру Linux, работу утилит сборки, имеет разнообразные навыки открытого разработчика вроде непрерывной интеграции, работы с сообществом и перевода. Только восемь правок за эти два года вредоносны, остальное напоминает обычную жизнь открытого проекта.

Бэкдор получил идентификатор CVE-2024-3094 и максимальный балл серьёзности 10,0.

Это классическая : вместо того, чтобы атаковать сам OpenSSH, атаковали менее защищённого поставщика. Как отмечает The Economist, «бэкдор в XZ Utils считается первой известной атакой на менее защищённые части критичной открытой программы, но это не значит, что атака была действительно первой — и вряд ли будет последней»A chilling near-miss shows how today’s digital infrastructure is vulnerable , The Economist, 4 April 2024.

Инцидент раскрыл множество слабых звеньев в открытом сообществе: организационных, технических проблем и просто ошибок. Некоторые уязвимости были устранены сразу, другие же требуют более сложного исправления.

Уязвимые версии Бэкдор рассчитывался на Linux для x86-64 и успел попасть в Fedora 40, мартовские сборки Arch Linux (где он оказался нерабочим) и в передовые нестабильные каналы обновления. Об атаке также сообщили Kali Linux и OpenSUSE.

Не были подвержены бэкдору: Другие ОС, не основанные на Unix и не на архитектуре x86-64; FreeBSD с консервативной политикой стабильности, другими методами сборки программ и другой стандартной библиотекой Си; Сборки, в которых SSHD не зависит от LibSystemd: Arch Linux, Gentoo и NixOS; Ubuntu с консервативной политикой стабильности: она не успела обновиться.

Чтобы избавиться от бэкдора, нужно откатить пакет xz-utils 5.6.0 или 5.6.1 до 5.4 — или обновить до следующей версии 5.6.2. Многие авторы дистрибутивов сделали пакеты-откаты: например, для OpenSUSE таковым является 5.6.1.revertto5.4.

История

Предпосылки

Сборка программы из человекоредактируемых исходных файлов — это всегда сложный процесс: она длится долго, различается для игр и библиотек, для Windows и Linux, на машине разработчика и на выпуск. Не зря  — отдельная специальность в разработке крупного ПО. Скрипты сборки не проходят такую ревизию, как исходные тексты: выходит действующая программа — и хорошо Understanding the Linux Backdoor: Implications for Open Source [When Penguins Cry] — YouTube. Хорошо сконфигурированный проект требует даже от администраторов собирать на сервере, что и дало свидетельства вмешательства.

Пакет XZ Utils, позволивший открытому ПО сжимать не хуже WinRAR, подходил как цель для атаки по нескольким причинам: Содержит немалое количество тестовых архивов, в том числе найденных у пользователей. Для таких файлов нет лучшего «исходника», чем сами файлы; Поддерживается одним человеком. В 2020 году веб-комикс xkcd написал, что вся инфраструктура современных IT где-то в глубине держится на программе, бескорыстно поддерживаемой парнем из Небраски. Прецеденты были — NPM left-pad incident, когда одна в сердцах отозванная несложная функция на несколько часов парализовала сверхпопулярный React; Сжатие данных всегда медленно, и оптимизации производительности с усложнением методики сборки не вызывают подозрения.

Цепочка зависимостей непрямая: разработчики дистрибутивов неофициально налаживали передачу в систему информации о работе службы SSHD через функцию libsystemd.sd_notify, но OpenSSH упорно не принимали зависимость от LibSystemd. Хоть часть задачи — автоматический перезапуск «упавшей» службы — попытались решить окольным путём в конце 2016, но отказались из-за ненадёжности. Совсем в других функциях LibSystemd полагается на LibLZMA (часть XZ) — то есть неофициальный SSHD загрузит библиотеку, но не вызовет ни одной функции сжатия. Но и тут нашёлся обходной путь.

Есть специфичное для проекта GNU расширение формата ELF под названием косвенная функция (IFUNC). У некоторых важных подпрограмм вроде memcpy есть несколько версий: скажем, общая и оптимизированная под набор команд SSE4. Загрузчик вызывает специальную функцию (resolver), та проверяет возможности процессора и возвращает ссылку на одну из версий, ещё до подстановки адресов в машинный код главной программы. Прикладной программе не нужна даже перекомпиляция. Этот resolver обычно маленький (вызов функции CPUID из библиотеки языка и анализ результатов), вызывается рано (при загрузке программы) и всегда (даже если ни одной функции главной программе не нужно).

Внедрение хакера в проект Осенью 2021 на GitHub появился пользователь с ником JiaT75, подписывавшийся как Jia Tan (Цзя Тань). Первое его изменение в библиотеке LibArchive было крайне подозрительным и могло дестабилизировать старые терминальные программы. Тогда же он вносит первые мелкие изменения (стилевые настройки, воспроизводимость результатов) в XZ Utils.

Весной 2022 Цзя вносит изменение в Java-версию XZ Utils. Сразу же появляются несколько «пользователей», желавших заполучить это изменение, и один из них в грубой форме требует, чтобы финн Лассе Коллин (Lasse Collin), единственный человек, поддерживавший проект, передал управление Цзя, если сам не справляется с потоком проблем. В ответ Лассе ссылается на депрессию.

С декабря 2022 Цзя берёт на себя организационные моменты: переезжает на GitHub, налаживает автосборку, берёт на себя работу с сообществом.

В июне 2023 Цзя включает первую косвенную функцию (IFUNC) — CRC64 для новых процессоров (Intel с 2010, AMD с 2013). Польза от такой оптимизации сомнительна, ведь быстрая (не криптографическая) контрольная сумма — не самое критичное место библиотеки сжатия.

В январе 2024 Цзя перемещает главный сайт на GitHub Pages — единственный ресурс, к которому имеет доступhttps://arxiv.org/pdf/2504.17473v1 // 2025 IEEE/ACM 22nd International Conference on Mining Software Repositories (MSR).

Атака 23 февраля 2024 года Цзя вносит несколько тестовых архивов, два из которых содержат бэкдор, и собирает версию 5.6.0. В зафиксированных исходных текстах в скрипте сборки оказываются 26 лишних строк по сравнению с Git. Сразу нашлось срабатывание Valgrindhttps://bugzilla.redhat.com/show_bug.cgi?id=2267598 (программы поиска ошибок доступа к памяти) у Red Hat прямо на функции, тайно собиравшей бэкдор в памяти.

За две недели, пока Цзя исправлял ошибку, бэкдор не обнаружили, и 9 марта он обновляет архивы с бэкдором, описав как «взяты постоянные настройки случайности», без указания, какие — это будет версия 5.6.1. Чтобы больше не менять эти архивы, он вносит поиск обновлений. Заодно он делает пустое изменение, якобы исправляющее Valgrindhttps://git.tukaani.org/?p=xz.git;a=commitdiff;h=82ecc538193b380a21622aea02b0ba078e7ade92.

Тем временем в LibSystemd появляется изменение: загружать функции сжатия динамически по надобности, чтобы уменьшить размер стартового виртуального «диска» (initrd, механизм начальной загрузки Linux, позволяющий разворачивать ПО, пока не загрузилась поддержка файловых систем). Это должно сломать бэкдор (LibLZMA выпадает из зависимостей SSHD), и хакер решает активно рекламировать пакет, чтобы попасть в стабильный канал обновлений раньше LibSystemd. В конце марта Ханс Янсен, участвовавший в создании косвенных функций, убедил Debian взять 5.6.1. 28 марта Цзя рекламирует 5.6.1 перед Ubuntu — но через несколько часов Debian откатывают, а на следующий день о бэкдоре узнают все.

Обнаружение 28 марта 2024 года программист из Microsoft Андрес Фройнд (Andres Freund) предупреждает о бэкдоре производителей Linux, 29 марта — всех.

Он испытывал PostgreSQL на производительность на новейшем нестабильном выпуске Debian Linux и обнаружил замедление: подключение по SSH занимало не 0,3, а 0,8 секундыA stealth attack came close to compromising the world’s computers , The Economist, Apr 2nd 2024. Андрес пришёл к выводу, что виноват пакет XZ Utils версий 5.6.0 и 5.6.1, вспомнил срабатывание Valgrind месяц назад и отследил почти все факты: это наверняка бэкдор; какая функция виновата, где спрятана и как попадает в скомпилированный пакет; при каких условиях срабатывает; кто хакер — по его мнению, Цзя именно хакер под прикрытием, а не взломанный разработчик.

Что делает функция и как она встала на место OpenSSL, ему понять не удалось.

После обнаружения Лассе Коллин, руководитель проекта, сделал периодически обновляемый пресс-релиз, содержащий только сухие факты.

GitHub закрыл проект и все его зеркала, и забанил обоих пользователей. Лассе вернул домашнюю страницу на личный сервер, и там же развернул Git-репозиторий проекта. Лассе разбанили 2 апреля, а 9 апреля проект снова переехал на GitHub. GitHub закрыл все запросы на изменения (pull requests), как будто их закрыл Лассе, а когда Лассе стал снова их открывать, чтобы проверить и внести — снова автоматически закрывал.

Авторы дистрибутивов откатили XZ до 5.4 и исключили Цзя из доверенных сборщиков.

Провели более глубокий аудит изменений Цзя и откатили многие его изменения, включая LibArchive.

В OpenSSH написали автономную функцию sd_notify, чтобы авторы дистрибутивов не делали патчи с посторонними зависимостями. Проблема стояла с 2016 года, но занялись ею только после бэкдора. Несколько позже LibSystemd написала свой вариант автономной sd_notify — для всех, кому библиотека нужна только ради этой функции.

Ubuntu отложила на неделю апрельскую бета-версию и своими силами пересобрала все пакеты.

CMake и Autoconf исправили ошибки, по-видимому, задействованные в бэкдоре.

Новая чистая версия XZ, вышедшая 29 мая, получила номер 5.6.2. Отдельные изменения: Выброшены косвенные функции (IFUNC) — выигрыш от них действительно был настолько мал, что не сто́ит усложнения проекта; Запуск тестов перенесён в отдельный скрипт CMake, чтобы сборка работала и без тестов; Для всех тестов прописана методика их воссоздания. Выброшены старые тесты, которые являются сами себе исходниками,— два объектных файла неизвестного происхождения. Документация в формате PDF также воссоздаётся из формата man, а не хранится в репозитории; Убрана эмблема, нарисованная Цзя, — она стала эмблемой бэкдора, а не проекта в целом.

Проект оказался в центре внимания, и добровольцы помогли сделать версию 5.6.3, направленную на совместимость с Windows: длинные пути, поддержка Юникода и прочее.

Принцип действия Бэкдор устроен очень сложно. Окольными путями решаются три вопроса: как протащить вредоносный код в открытый проект; как его подключить к SSHD, который LZMA вообще не вызывает, даже в тех дистрибутивах, где есть зависимость SSHD ← LibSystemd ← LibLZMA; как подключить нужный для работы OpenSSL, не требуя его явно.

Сборка вредоносного LibLZMA Скрипт сборки, лежащий на старом сайте Коллина (не на GitHub), находит пример плохого архива tests/files/bad-3-corrupt_lzma2.xz (без явного указания этого имени), расшифровывает и разжимает более старым скомпилированным XZ. На выходе получается командный файл; Этот файл распаковывает и расшифровывает второй пример, на сей раз хорошего архива — tests/files/good-large_compressed.lzma. В результате получается второй командный файл, который и прислал Фройнд;