
Élévation de privilèges locale via une condition de course TOCTOU dans PackageKit.
CVSS 3.x : 7.8 HIGH
CWE : CWE-367 (Time-of-Check Time-of-Use)
Fix : PackageKit 1.3.5+
Affects : PackageKit 1.0.2 – 1.3.4
Élévation de privilèges locale via une condition de course TOCTOU dans le gestionnaire de transactions D-Bus de PackageKit.
Tout utilisateur local non privilégié peut installer des paquets arbitraires en tant que root — aucune authentification au-delà d'une session locale n'est requise.
Uniquement pour labo / tests autorisés (HTB, CTF, engagement avec périmètre écrit).
python3 exploit.py
C'est tout. Dépose /tmp/.suid_bash, puis exec dans un shell root.
Chemin SUID personnalisé ou délai d'attente :
SUID_BIN=/dev/shm/.sh TIMEOUT=90 python3 exploit.py
apt install python3-gi dpkg-dev
L'exploit construit deux paquets .deb à l'exécution — aucun compilateur requis.
Trois bogues dans src/pk-transaction.c s'enchaînent :
InstallFiles() écrase cached_transaction_flags et cached_full_paths sans vérification d'état. Un second appel D-Bus sur la même transaction les remplace aveuglément — même pendant que la transaction est déjà en cours d'exécution.
pk_transaction_set_state() rejette les transitions arrière illégales (RUNNING→READY, etc.) sans restaurer les flags écrasés du Bug 1. Les flags corrompus persistent.
pk_transaction_run() lit cached_transaction_flags au moment de la distribution (idle GLib), pas au moment de l'autorisation. Le backend voit les flags de l'attaquant.
Définir PK_TRANSACTION_FLAG_SIMULATE (0x4) contourne entièrement la vérification d'autorisation polkit. L'appel 1 est autorisé sans aucune interaction utilisateur.
Attacker packagekitd
│ │
│ CreateTransaction() │ state = NEW
│─────────────────────────────────►│
│ │
│ InstallFiles(SIMULATE, dummy) │ polkit skipped (SIMULATE)
│─────────────────────────────────►│ state = READY, idle queued
│ │
│ InstallFiles(NONE, payload) │ flags+paths overwritten
│─────────────────────────────────►│ set_state(WAITING_FOR_AUTH) rejected
│ │ state stays READY (BUG 2)
│ │
│ [idle fires]│
│ │ pk_transaction_run() reads NONE (BUG 3)
│ │ → dpkg installs payload as root
│ │ → postinst: chmod +s /tmp/.suid_bash
│ │
│ execv("/tmp/.suid_bash -p") │
│─────────────────────────────────►│ euid=0(root)
Les deux appels arrivent avant que l'idle GLib ne se déclenche — aucune course à gagner, c'est déterministe.
Ubuntu Desktop 18.04–26.04, Debian Trixie, Fedora 43, RockyLinux 10.1, et toute distribution fournissant PackageKit 1.0.2–1.3.4 avec le démon actif.
systemctl mask packagekittransaction->state != PK_TRANSACTION_STATE_NEW → rejeter