
# Lab Docker in stile CTF per CVE-2026-41651 (Pack2TheRoot): escalatione dei privilegi locale di PackageKit permissive-polkit
Un laboratorio Dockerizzato in stile CTF per l'escalation locale dei privilegi, costruito attorno all'advisory Pack2TheRoot (CVE-2026-41651), una vulnerabilità di 12 anni nel demone PackageKit divulgata dal Red Team di Deutsche Telekom il 22 aprile 2026.
Il laboratorio include tre container: una sfida CTF con polkit permissivo, un target di confronto indurito e una riproduzione completa dell'exploit TOCTOU che compila PackageKit vulnerabile dal sorgente ed esegue l'exploit reale della causa principale di CVE-2026-41651.
| Container | Porta | Ruolo | Esito dell'exploit |
|---|
pack2theroot-vuln | tcp/2222 (ssh) | PackageKit ≤ 1.3.4 + regola polkit permissiva | Root tramite RPM modificato |
pack2theroot-patched | tcp/2223 (ssh) | Stesso, ma con polkit indurito | L'exploit fallisce |
pack2theroot-exploit | — | PackageKit vulnerabile 1.3.4 compilato dal sorgente | Root tramite race TOCTOU su D-Bus |
Inoltre:
docs/CHALLENGE.md)docs/HINTS.md)docs/SOLUTION.md)docs/diagrams/)| Campo | Valore |
|---|---|
| CVE | CVE-2026-41651 |
| Nome | Pack2TheRoot |
| Classe | Escalation locale dei privilegi (TOCTOU / CWE-367) |
| Componente | Demone PackageKit (pk-transaction.c) |
| Intervallo vulnerabile | >= 1.0.2 e <= 1.3.4 (12 anni di release) |
| Corretto in | PackageKit 1.3.5 (commit 76cfb675, rilasciato il 2026-04-22) |
| CVSS 3.1 | 8.8 (ALTO) — AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H |
| Pre-condizioni | Shell locale non privilegiata su un host che esegue PackageKit |
| Scopritore | Deutsche Telekom Security GmbH — Red Team |
pk-transaction.c| Bug | Posizione | Effetto |
|---|---|---|
| BUG 1 | InstallFiles() (~riga 4036) | Sovrascrive cached_transaction_flags e cached_full_paths incondizionatamente — nessun controllo di stato |
| BUG 2 | pk_transaction_set_state() (~righe 876–881) | Elimina silenziosamente le transizioni di stato all'indietro invece di generare un errore — i flag sono già avvelenati |
| BUG 3 | pk_transaction_run() (~righe 2273–2277) | Legge cached_transaction_flags al momento dell'invio, non al momento dell'autorizzazione |
| Bypass | Flag SIMULATE (~righe 2893–2900) | PK_TRANSACTION_FLAG_SIMULATE (0x4) bypassa completamente polkit |
L'exploit invia due chiamate D-Bus asincrone InstallFiles() sulla stessa transazione: prima con SIMULATE (bypassa polkit, accoda un callback idle GLib), poi immediatamente con NONE + il pacchetto dannoso (sovrascrive i flag/percorsi memorizzati prima che l'idle scatti). L'ordinamento per priorità di GLib garantisce che entrambi i messaggi D-Bus vengano inviati prima del callback idle — rendendo questo deterministico, non una race temporale.
IOC noto (dall'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 # password: labuser
# poi segui docs/CHALLENGE.md
Il flag si trova in /root/flag.txt (modalità 0400 root:root). Formato:
PACK2THEROOT{...}
# Build ed esecuzione — la modalità automatica esegue l'exploit immediatamente:
docker compose run --rm exploit
# Oppure modalità manuale:
docker compose run --rm --entrypoint /entrypoint.sh exploit
# Poi all'interno del container:
su - victim -c /exploit/cve-2026-41651
L'exploit compila due pacchetti .deb in C (nessuno strumento esterno necessario), invia la race D-Bus a due chiamate e crea una bash SUID in /tmp/.suid_bash. Vedi docs/SOLUTION.md per il walkthrough tecnico completo.
Smontaggio:
docker compose down -v
pack2theroot-lab/
├── README.md
├── docker-compose.yml
├── docs/
│ ├── CHALLENGE.md # brief del giocatore
│ ├── HINTS.md # suggerimenti progressivi (entrambi i percorsi)
│ ├── SOLUTION.md # walkthrough completo + flag
│ ├── references.md # fonti primarie e secondarie
│ ├── threat-model.md # presupposti attaccante/difensore
│ └── diagrams/ # diagrammi SVG del flusso dell'exploit
│ ├── 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 # compila PackageKit vulnerabile 1.3.4 dal sorgente
│ ├── entrypoint.sh # avvia dbus + polkitd + packagekitd
│ ├── Makefile
│ └── src/
│ └── cve-2026-41651.c # l'exploit TOCTOU (PoC pubblico)
├── vulnerable/
│ ├── Dockerfile
│ ├── entrypoint.sh
│ └── policy/
│ └── 10-pack2theroot-lab-misconfig.rules # sfida CTF
├── patched/
│ ├── Dockerfile
│ ├── entrypoint.sh
│ ├── local/ # inserisci qui un RPM di backport 1.3.5 (opzionale)
│ └── policy/
│ └── 10-pack2theroot-lab-hardened.rules # la correzione
└── scripts/
├── exploit-check.sh # controlla versione, polkit, D-Bus, IOC
├── check-version.sh # verdetto VULNERABILE vs CORRETTO
├── check-preconditions.sh # sanity check pkcon / polkit / D-Bus
├── monitor-ioc.sh # tail del journal per l'IOC dell'advisory
├── compare-env.sh # diff di entrambi i container
└── apply-polkit-mitigation.sh # indurimento provvisorio per host non corretti
La directory docs/diagrams/ contiene diagrammi SVG che mostrano il flusso dell'exploit. Aprilo in qualsiasi browser:
| Diagramma | Descrizione |
|---|---|
01-docker-build.svg | Build Docker in due fasi — compilazione di PackageKit vulnerabile |
02-container-startup.svg | Avvio del container — avvio di dbus, polkitd, packagekitd |
03-exploit-execution.svg | Output dell'exploit passo dopo passo con fasi annotate |
04-dbus-race-sequence.svg | Diagramma di sequenza D-Bus — come BUG 1/2/3 si concatenano con la priorità GLib |
05-attack-overview.svg | Flusso dell'attacco ad alto livello: attaccante vs sistema con timeline |
06-auto-mode-full-run.svg | Terminale completo della modalità --auto — dall'avvio del container alla shell root |
Vedi docs/CHALLENGE.md. In breve:
labuser (password labuser).rpm-build, rpmdevtools sono installati).pkcon install-local --allow-untrusted.%post viene eseguito come root. Leggi /root/flag.txt.Bloccato? docs/HINTS.md contiene suggerimenti sempre più espliciti. Apri docs/SOLUTION.md solo dopo aver risolto la sfida o se hai davvero bisogno del write-up.
All'interno di uno dei container, come qualsiasi utente:
/opt/lab/check-version.sh # verdetto VULNERABILE o CORRETTO
/opt/lab/check-preconditions.sh # auto-controllo dell'esposizione
/opt/lab/exploit-check.sh # controllo versione + polkit + D-Bus + IOC
/opt/lab/monitor-ioc.sh # tail del journal per l'IOC
Dall'host, affiancato:
./scripts/compare-env.sh
Applica la mitigazione polkit provvisoria a un container vulnerabile:
docker exec pack2theroot-vuln /opt/lab/apply-polkit-mitigation.sh
# Poi riprova l'exploit — ora dovrebbe fallire.
L'immagine patched gestisce onestamente lo stato della versione di PackageKit:
/etc/pack2theroot-banner) che indica se la versione installata è la correzione reale o un segnaposto della distribuzione.Per compilare un'immagine corretta completa di versione quando la tua distribuzione pubblica il backport, inserisci gli RPM in patched/local/ e ricompila:
docker compose build --build-arg USE_LOCAL_RPM=1 patched
--privileged per eseguire l'intero stack dbus/polkitd/packagekitd. Eseguilo solo in ambienti isolati.labuser) è volutamente debole. Non riutilizzarla mai.Fonti primarie:
CVE-2026-41651:
https://nvd.nist.gov/vuln/detail/CVE-2026-4165176cfb675:
https://github.com/PackageKit/PackageKit/commit/76cfb675fb31acc3ad5595d4380bfff56d2a8697Vedi docs/references.md per la copertura secondaria e i tracker delle distribuzioni.
MIT — vedi LICENSE.