
Escalation locale dei privilegi tramite condizione di gara TOCTOU in 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
Escalata locale dei privilegi tramite condizione di gara TOCTOU nel gestore delle transazioni D-Bus di PackageKit.
Qualsiasi utente locale senza privilegi può installare pacchetti arbitrari come root — nessuna autenticazione oltre ad avere una sessione locale.
Solo test di laboratorio / autorizzati (HTB, CTF, engagement con scope scritto).
python3 exploit.py
Tutto qui. Rilascia /tmp/.suid_bash, poi esegue exec in una shell root.
Percorso SUID personalizzato o timeout:
SUID_BIN=/dev/shm/.sh TIMEOUT=90 python3 exploit.py
apt install python3-gi dpkg-dev
L'exploit costruisce due pacchetti .deb a runtime — nessun compilatore necessario.
Tre bug in src/pk-transaction.c si concatenano:
InstallFiles() sovrascrive cached_transaction_flags e cached_full_paths senza controllo di stato. Una seconda chiamata D-Bus sulla stessa transazione li sostituisce alla cieca — anche mentre la transazione è già in esecuzione.
pk_transaction_set_state() rifiuta transizioni all'indietro illegali (RUNNING→READY, ecc.) senza ripristinare i flag sovrascritti del Bug 1. I flag corrotti persistono.
pk_transaction_run() legge cached_transaction_flags al momento della spedizione (idle di GLib), non al momento dell'autorizzazione. Il backend vede i flag dell'attaccante.
Impostare PK_TRANSACTION_FLAG_SIMULATE (0x4) salta completamente il controllo di autorizzazione di polkit. La chiamata 1 viene autorizzata senza interazione da parte dell'utente.
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)
Entrambe le chiamate arrivano prima che scatti l'idle di GLib — nessuna gara da vincere, è deterministico.
Ubuntu Desktop 18.04–26.04, Debian Trixie, Fedora 43, RockyLinux 10.1 e qualsiasi distribuzione che include PackageKit 1.0.2–1.3.4 con il demone attivo.
systemctl mask packagekittransaction->state != PK_TRANSACTION_STATE_NEW → rifiuta