CVE-2026-41651 — PackageKit TOCTOU локальное повышение привилегий
Классификация: Артефакт оценки Purple Team
Только для авторизованного использования. Этот документ и прилагаемый тестовый скрипт предназначены исключительно для внутренней проверки безопасности на системах, где получено письменное разрешение.
Доказательство эксплуатации

Содержание
- Обзор уязвимости
- Технический анализ
- Описание тестового скрипта
- Индикаторы компрометации
- Логика обнаружения
- Затронутые системы и версии
- Устранение
- Ссылки
Обзор уязвимости
PackageKit — это уровень абстракции D-Bus для системного управления пакетами, присутствующий по умолчанию на GNOME-десктопах в Debian, Ubuntu, Fedora, RHEL, SUSE и Arch Linux. Поскольку он опосредует привилегированные операции с пакетами от имени непривилегированных пользователей, ошибка в его потоке авторизации имеет системное воздействие уровня root.
Технический анализ
Корневая причина
pk-transaction.c (до версии 1.3.5) не обеспечивал защиту состояния при повторном вызове методов действий. Клиент D-Bus мог вызывать InstallFiles (или другие методы действий) несколько раз на одном и том же объекте транзакции после того, как он уже перешёл из состояния PK_TRANSACTION_STATE_NEW.
Цепочка атаки
Атакующий (непривилегированный)
│
├─① CreateTransaction() → PackageKit возвращает путь объекта транзакции (tid)
│
├─② InstallFiles(tid, FLAG_SIMULATE=4, [dummy.pkg])
│ PackageKit ставит в очередь проверку авторизации polkit для dummy.pkg.
│ Установка ещё не происходит — SIMULATE означает только пробный запуск.
│
├─③ InstallFiles(tid, FLAG_NONE=0, [payload.pkg]) ← окно TOCTOU
│ Повторный вызов на том же tid до разрешения авторизации.
│ Уязвимые версии перезаписывают поставленные в очередь параметры на payload.pkg.
│
└─④ polkit предоставляет авторизацию (пользователь одобрил или авто-авторизация)
packagekitd устанавливает payload.pkg от имени root.
postinst/post-скрипт payload: install -m 4755 /bin/bash /tmp/.suid_bash
Атакующий выполняет /tmp/.suid_bash -p → root-оболочка.
Почему гонка выигрывается
Шаги ② и ③ отправляются как неблокирующие асинхронные вызовы D-Bus по одному соединению и сбрасываются одним записывающим вызовом. Два сообщения достигают packagekitd до того, как он сможет обработать ② и продвинуть конечный автомат, оставляя окно TOCTOU открытым. Исправление в 1.3.5 добавляет явную проверку состояния, которая возвращает PK_TRANSACTION_ERROR_INVALID_STATE при любом повторном вызове после PK_TRANSACTION_STATE_NEW.
Описание тестового скрипта
Файл: cve-2026-41651-purpleteam.py
Язык: Python 3
Зависимости: python3-gi (интроспекция GObject / привязки GLib/Gio)
Назначение
Демонстрирует эксплуатируемость CVE-2026-41651 на подготовленной тестовой системе с целью:
- Проверки, уязвима ли установленная версия PackageKit
- Генерации реалистичной телеметрии IOC для настройки SIEM/EDR
- Тестирования покрытия обнаружения до и после установки исправления
Поведение
Поддержка усиленных сред
Системы с усиленной защитой по умолчанию могут блокировать эксплойт в двух независимых точках. Скрипт обрабатывает обе автоматически.
1. Ограничительный umask (027 / 077)
Унаследованный от процесса umask 027 или 077 приводит к тому, что mkdir() создаёт каталоги с правами 750 или 700. И dpkg-deb, и rpmbuild должны пройти по всему дереву сборки — если какой-либо каталог недоступен для чтения, сборка молча завершается неудачей.
Применяемое исправление: os.umask(0o022) вызывается при запуске до создания любых файлов или каталогов. Кроме того, каждый каталог и файл в дереве сборки получает явный chmod сразу после создания (0o755 для каталогов и скриптов, 0o644 для файлов данных), поэтому правильные права гарантированы независимо от унаследованного umask.
2. Флаги монтирования nosuid / noexec на /tmp
| Флаг | Влияние на эксплойт |
|---|
nosuid | Ядро молча снимает бит SUID с любого файла, хранящегося на этой файловой системе — скопированный bash никогда не становится root |
noexec | SUID-бинарник вообще не может быть выполнен |
Применяемое исправление: При запуске _find_suid_dir() читает /proc/mounts и проверяет каталоги-кандидаты в порядке предпочтения, пока не найдёт файловую систему без обоих флагов. Разрешённый путь затем встраивается в пост-установочный скрипт полезной нагрузки и используется для опроса и выполнения.
Если все кандидаты заблокированы, скрипт завершается с понятной ошибкой, а не молча терпит неудачу.
Совместимость
| Семейство дистрибутивов | Инструмент пакетов | Протестировано |
|---|
| Debian / Ubuntu | dpkg-deb | ✓ |
Индикаторы компрометации
IOC перечислены от общих/инфраструктурных до специфичных для скрипта артефактов. Обнаружения, построенные на общих индикаторах, поймают эту CVE независимо от того, какой вариант PoC используется.
Файловая система
Процессы и выполнение
Активность D-Bus
Паттерны журналов аудита
Включите с помощью: auditctl -a always,exit -F arch=b64 -S all -F path=/usr/bin/packagekitd
Или используйте правила ниже в /etc/audit/rules.d/:
# Обнаружение создания SUID-файлов во всех каталогах-кандидатах сброса
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/tmp -k suid_drop
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/var/tmp -k suid_drop
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/dev/shm -k suid_drop
# Обнаружение dpkg-deb / rpmbuild не-root
-w /usr/bin/dpkg-deb -p x -k pkg_build_nonroot
-w /usr/bin/rpmbuild -p x -k pkg_build_nonroot
# Обнаружение выполнения SUID bash из любого каталога-кандидата сброса
-a always,exit -F arch=b64 -S execve -F dir=/tmp -F uid!=0 -F euid=0 -k priv_esc_drop
-a always,exit -F arch=b64 -S execve -F dir=/var/tmp -F uid!=0 -F euid=0 -k priv_esc_drop
-a always,exit -F arch=b64 -S execve -F dir=/dev/shm -F uid!=0 -F euid=0 -k priv_esc_drop
Артефакты менеджера пакетов
Артефакты повышения привилегий
Логика обнаружения
Псевдоправило SIEM (общее — покрывает все варианты CVE-2026-41651)
(
event.category == "process"
AND process.name IN ("dpkg-deb", "rpmbuild")
AND process.user.id != "0"
AND NOT process.parent.name IN ("apt", "apt-get", "dpkg", "rpm", "dnf", "yum", "zypper", "mock", "koji")
)
OR
(
event.category == "file"
AND file.path LIKE "/tmp/%" OR file.path LIKE "/var/tmp/%" OR file.path LIKE "/dev/shm/%"
AND file.owner == "root"
AND (file.mode LIKE "04%")
)
OR
(
event.category == "process"
AND process.name == "bash"
AND process.real_user.id != "0"
AND process.effective_user.id == "0"
AND NOT process.parent.name IN ("sudo", "su", "sshd", "login", "pam")
)
Поведенческая цепочка EDR
packagekitd
└─ sh / bash (cwd или аргумент соответствует /tmp, /var/tmp, /dev/shm или $HOME)
└─ install / cp / chmod (цель имеет SUID + владелец root)
Помечайте всю цепочку. Любой отдельный шаг сам по себе может быть безобидным; связь родитель-потомок через packagekitd с командой, устанавливающей SUID, является высокоточной независимо от выбранного каталога сброса. Расширьте правила на основе путей, чтобы покрыть все четыре кандидата.
Затронутые системы и версии
Проверьте установленную версию: pkcon backend-details или packagekit --version
Уязвим, если сообщённая версия ≤ 1.3.4.
Устранение
Основное: Обновите PackageKit до 1.3.5 или примените бэкпорт от конкретного вендора.
# Debian / Ubuntu
apt update && apt install --only-upgrade packagekit
# Fedora / RHEL
dnf upgrade packagekit
# SUSE
zypper update packagekit
Смягчающие меры (если установка исправления немедленно невозможна):
Ссылки
Сгенерировано: 2026-04-24 | Обновлено: 2026-04-25 | Оценка Purple Team | Только для внутреннего использования