
CTF-стиль Docker-лаборатория для CVE-2026-41651 (Pack2TheRoot): локальное повышение привилегий через permissive-polkit в PackageKit
Лаборатория локального повышения привилегий в стиле CTF на базе Docker, построенная вокруг
Pack2TheRoot advisory (CVE-2026-41651) — 12-летней уязвимости в
демоне PackageKit, раскрытой
Red Team компании Deutsche Telekom 22 апреля 2026 года.
Лаборатория включает три контейнера: CTF-задачу с разрешающим polkit, ужесточённую цель для сравнения и полную репродукцию TOCTOU-эксплойта, которая собирает уязвимый PackageKit из исходников и запускает реальный эксплойт первопричины CVE-2026-41651.
| Контейнер | Порт | Роль | Результат эксплойта |
|---|
pack2theroot-vuln | tcp/2222 (ssh) | PackageKit ≤ 1.3.4 + разрешающее polkit-правило | Root через поддельный RPM |
pack2theroot-patched | tcp/2223 (ssh) | То же, но polkit ужесточён | Эксплойт не срабатывает |
pack2theroot-exploit | — | Уязвимый PackageKit 1.3.4, собранный из исходников | Root через TOCTOU-гонку D-Bus |
Плюс:
docs/CHALLENGE.md)docs/HINTS.md)docs/SOLUTION.md)docs/diagrams/)| Поле | Значение |
|---|---|
| CVE | CVE-2026-41651 |
| Название | Pack2TheRoot |
| Класс | Локальное повышение привилегий (TOCTOU / CWE-367) |
| Компонент | Демон PackageKit (pk-transaction.c) |
| Уязвимый диапазон | >= 1.0.2 и <= 1.3.4 (12 лет релизов) |
| Исправлено в | PackageKit 1.3.5 (коммит 76cfb675, выпущен 2026-04-22) |
| CVSS 3.1 | 8.8 (HIGH) — AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H |
| Предусловия | Локальная непривилегированная оболочка на хосте с запущенным PackageKit |
| Обнаружитель | Deutsche Telekom Security GmbH — Red Team |
pk-transaction.c| Ошибка | Место | Эффект |
|---|---|---|
| ОШИБКА 1 | InstallFiles() (~строка 4036) | Безусловно перезаписывает cached_transaction_flags и cached_full_paths — нет проверки состояния |
| ОШИБКА 2 | pk_transaction_set_state() (~строки 876–881) | Молча отбрасывает обратные переходы состояния вместо ошибки — флаги уже отравлены |
| ОШИБКА 3 | pk_transaction_run() (~строки 2273–2277) | Читает cached_transaction_flags в момент диспетчеризации, а не авторизации |
| Обход | Флаг SIMULATE (~строки 2893–2900) | PK_TRANSACTION_FLAG_SIMULATE (0x4) полностью обходит polkit |
Эксплойт отправляет два асинхронных D-Bus-вызова InstallFiles() в рамках одной
транзакции: сначала с SIMULATE (обходит polkit, ставит в очередь GLib idle-колбэк),
затем сразу с NONE + вредоносным пакетом (перезаписывает кэшированные
флаги/пути до срабатывания idle). Приоритетный порядок GLib гарантирует,
что оба D-Bus-сообщения будут обработаны до idle-колбэка — это делает
атаку детерминированной, а не гонкой по времени.
Известный IOC (из advisory):
journalctl --no-pager -u packagekit | grep -iE 'emitted_finished|pk_transaction_finished_emit|pk-transaction\.c:514'
git clone https://github.com/dinosn/pack2theroot-lab.git
cd pack2theroot-lab
docker compose build
docker compose up -d
ssh labuser@localhost -p 2222 # пароль: labuser
# затем работайте по docs/CHALLENGE.md
Флаг находится в /root/flag.txt (режим 0400 root:root). Формат:
PACK2THEROOT{...}
# Сборка и запуск — авто-режим немедленно выполняет эксплойт:
docker compose run --rm exploit
# Или ручной режим:
docker compose run --rm --entrypoint /entrypoint.sh exploit
# Затем внутри контейнера:
su - victim -c /exploit/cve-2026-41651
Эксплойт собирает два .deb-пакета на C (без внешних инструментов),
отправляет D-Bus-гонку из двух вызовов и создаёт SUID bash по пути
/tmp/.suid_bash. См. docs/SOLUTION.md для
полного технического разбора.
Завершение работы:
docker compose down -v
pack2theroot-lab/
├── README.md
├── docker-compose.yml
├── docs/
│ ├── CHALLENGE.md # брифинг игрока
│ ├── HINTS.md # постепенные подсказки (оба пути)
│ ├── SOLUTION.md # полное прохождение + флаг
│ ├── references.md # первоисточники и вторичные источники
│ ├── threat-model.md # допущения атакующего/защитника
│ └── diagrams/ # SVG-схемы потока эксплойта
│ ├── 01-docker-build.svg
│ ├── 02-container-startup.svg
│ ├── 03-exploit-execution.svg
│ ├── 04-dbus-race-sequence.svg
│ ├── 05-attack-overview.svg
│ └── 06-auto-mode-full-run.svg
├── exploit/
│ ├── Dockerfile # собирает уязвимый PackageKit 1.3.4 из исходников
│ ├── entrypoint.sh # запускает dbus + polkitd + packagekitd
│ ├── Makefile
│ └── src/
│ └── cve-2026-41651.c # TOCTOU-эксплойт (публичный PoC)
├── vulnerable/
│ ├── Dockerfile
│ ├── entrypoint.sh
│ └── policy/
│ └── 10-pack2theroot-lab-misconfig.rules # CTF-задача
├── patched/
│ ├── Dockerfile
│ ├── entrypoint.sh
│ ├── local/ # поместите сюда бэкпорт RPM 1.3.5 (необязательно)
│ └── policy/
│ └── 10-pack2theroot-lab-hardened.rules # исправление
└── scripts/
├── exploit-check.sh # проверяет версию, polkit, D-Bus, IOC
├── check-version.sh # вердикт VULNERABLE vs PATCHED
├── check-preconditions.sh # проверка pkcon / polkit / D-Bus
├── monitor-ioc.sh # отслеживает журнал на предмет IOC из advisory
├── compare-env.sh # сравнение обоих контейнеров
└── apply-polkit-mitigation.sh # промежуточное смягчение для незапатченных хостов
Каталог docs/diagrams/ содержит SVG-схемы,
показывающие поток эксплойта. Откройте их в любом браузере:
| Схема | Описание |
|---|---|
01-docker-build.svg | Двухэтапная Docker-сборка — компиляция уязвимого PackageKit |
02-container-startup.svg | Запуск контейнера — старт dbus, polkitd, packagekitd |
03-exploit-execution.svg | Пошаговый вывод эксплойта с аннотированными фазами |
04-dbus-race-sequence.svg | Диаграмма последовательности D-Bus — как ОШИБКИ 1/2/3 связываются с приоритетом GLib |
05-attack-overview.svg | Атака на высоком уровне: атакующий против системы с таймлайном |
06-auto-mode-full-run.svg | Полный терминал режима --auto — от запуска контейнера до root-оболочки |
См. docs/CHALLENGE.md. Кратко:
labuser (пароль labuser).rpm-build, rpmdevtools установлены).pkcon install-local --allow-untrusted.%post выполняется от root. Прочитайте /root/flag.txt.Застряли? В docs/HINTS.md есть всё более
явные подсказки. Открывайте
docs/SOLUTION.md только после того, как решите задачу
или действительно нуждаетесь в разборе.
Внутри любого контейнера, от любого пользователя:
/opt/lab/check-version.sh # вердикт VULNERABLE или PATCHED
/opt/lab/check-preconditions.sh # самопроверка подверженности
/opt/lab/exploit-check.sh # проверка версии + polkit + D-Bus + IOC
/opt/lab/monitor-ioc.sh # отслеживание журнала на предмет IOC
С хоста, бок о бок:
./scripts/compare-env.sh
Примените промежуточное смягчение polkit к уязвимому контейнеру:
docker exec pack2theroot-vuln /opt/lab/apply-polkit-mitigation.sh
# Затем повторите эксплойт — теперь он должен не сработать.
Образ patched честно обрабатывает статус версии PackageKit:
/etc/pack2theroot-banner), указывающий,
является ли установленная версия реальным патчем или заглушкой дистрибутива.Чтобы собрать версионно-полный запатченный образ после публикации бэкпорта
вашим дистрибутивом, поместите RPM-файл(ы) в patched/local/ и пересоберите:
docker compose build --build-arg USE_LOCAL_RPM=1 patched
--privileged для запуска полного стека
dbus/polkitd/packagekitd. Запускайте его только в изолированных средах.labuser) намеренно слабый. Никогда не используйте его повторно.Первоисточники:
CVE-2026-41651:
https://nvd.nist.gov/vuln/detail/CVE-2026-4165176cfb675:
https://github.com/PackageKit/PackageKit/commit/76cfb675fb31acc3ad5595d4380bfff56d2a8697См. docs/references.md для вторичного освещения
и трекеров дистрибутивов.
MIT — см. LICENSE.