## https://sploitus.com/exploit?id=271EBE27-5D01-50E7-838C-586E6CD838C9
# CVE-2026-41651 โ PackageKit TOCTOU Local Privilege Escalation
> **Classification:** Purple Team Assessment Artifact
> **Authorized use only.** This document and the accompanying test script are intended solely for internal security validation on systems where written authorization has been obtained.
---
## Proof of Exploitation

---
## Table of Contents
1. [Vulnerability Overview](#vulnerability-overview)
2. [Technical Analysis](#technical-analysis)
3. [Test Script Description](#test-script-description)
4. [Indicators of Compromise](#indicators-of-compromise)
- [File System](#file-system)
- [Process & Execution](#process--execution)
- [D-Bus Activity](#d-bus-activity)
- [Audit Log Patterns](#audit-log-patterns)
- [Package Manager Artifacts](#package-manager-artifacts)
- [Privilege Escalation Artifacts](#privilege-escalation-artifacts)
5. [Detection Logic](#detection-logic)
6. [Affected Systems & Versions](#affected-systems--versions)
7. [Remediation](#remediation)
8. [References](#references)
---
## Vulnerability Overview
| Field | Value |
|--------------------|-----------------------------------------------------------------------|
| **CVE ID** | CVE-2026-41651 |
| **CWE** | CWE-367 โ Time-of-check Time-of-use (TOCTOU) Race Condition |
| **Component** | PackageKit (`packagekitd`, D-Bus service) |
| **Affected** | PackageKit โค 1.3.4 |
| **Fixed in** | PackageKit 1.3.5 |
| **Impact** | Local Privilege Escalation โ root |
| **Attack Vector** | Local / D-Bus (unprivileged user session) |
| **Disclosed** | 2026-04-22 (Deutsche Telekom Red Team) |
| **Advisory** | GHSA-f55j-vvr9-69xv |
| **Fix commit** | `76cfb675fb31acc3ad5595d4380bfff56d2a8697` |
PackageKit is a D-Bus abstraction layer for system package management, present by default on GNOME-based desktops across Debian, Ubuntu, Fedora, RHEL, SUSE, and Arch Linux. Because it mediates privileged package operations on behalf of unprivileged users, a flaw in its authorization flow has system-wide root impact.
---
## Technical Analysis
### Root Cause
`pk-transaction.c` (pre-1.3.5) did not enforce a state guard on action method re-invocation. A D-Bus client could call `InstallFiles` (or other action methods) **multiple times on the same transaction object** after it had already transitioned out of `PK_TRANSACTION_STATE_NEW`.
### Attack Chain
```
Attacker (unprivileged)
โ
โโโ CreateTransaction() โ PackageKit returns transaction object path (tid)
โ
โโโก InstallFiles(tid, FLAG_SIMULATE=4, [dummy.pkg])
โ PackageKit queues a polkit authorization check for dummy.pkg.
โ No installation occurs yet โ SIMULATE means dry-run only.
โ
โโโข InstallFiles(tid, FLAG_NONE=0, [payload.pkg]) โ TOCTOU window
โ Re-invokes on the same tid before auth resolves.
โ Vulnerable versions overwrite the queued parameters with payload.pkg.
โ
โโโฃ polkit grants authorization (user approved or auto-authorized)
packagekitd installs payload.pkg as root.
payload postinst/post script: install -m 4755 /bin/bash /tmp/.suid_bash
Attacker executes /tmp/.suid_bash -p โ root shell.
```
### Why the Race Wins
Steps โก and โข are sent as **non-blocking async D-Bus calls** on the same connection and flushed in a single write. The two messages arrive at `packagekitd` before it can process โก and advance the state machine, leaving the TOCTOU window open. The fix in 1.3.5 adds an explicit state check that returns `PK_TRANSACTION_ERROR_INVALID_STATE` on any re-invocation after `PK_TRANSACTION_STATE_NEW`.
---
## Test Script Description
**File:** `cve-2026-41651-purpleteam.py`
**Language:** Python 3
**Dependencies:** `python3-gi` (GObject introspection / GLib/Gio bindings)
### Purpose
Demonstrates exploitability of CVE-2026-41651 on a prepared test system for the purposes of:
- Validating whether the installed PackageKit version is vulnerable
- Generating realistic IOC telemetry for SIEM/EDR tuning
- Testing detection coverage before and after patching
### Behavior
| Phase | Action |
|---------------|---------------------------------------------------------------------------------|
| **Setup** | Detects RPM (RHEL/Fedora/SUSE) or DEB (Debian/Ubuntu) and builds a dummy and a payload package in `/tmp` |
| **Exploit** | Opens a system D-Bus connection, creates a PackageKit transaction, fires the two-call race |
| **Payload** | Package post-install script copies `/bin/bash` to `/tmp/.suid_bash` with mode `04755`, owner `root` |
| **Escalation**| Polls for the SUID binary (90 s timeout), then `execl`s into it with `-p` for a root shell |
| **Cleanup** | Removes the temporary `.deb`/`.rpm` files on exit (success or failure) |
### Compatibility
| Distribution Family | Package Tool | Tested |
|---------------------|----------------|--------|
| Debian / Ubuntu | `dpkg-deb` | โ |
| RHEL / Fedora | `rpmbuild` | โ |
| SUSE / openSUSE | `rpmbuild` | โ |
---
## Indicators of Compromise
> IOCs are listed from generic/infrastructure-level down to script-specific artifacts. Detections built on the generic indicators will catch this CVE regardless of which PoC variant is used.
### File System
| IOC | Path / Pattern | Notes |
|-----|---------------|-------|
| SUID binary in world-writable directory | `/tmp/*` with mode `04755` and `uid=0` | Canonical payload drop location; any SUID root file in `/tmp`, `/var/tmp`, `/dev/shm` is high-fidelity |
| Transient package file in `/tmp` | `/tmp/*.deb`, `/tmp/*.rpm` | Built by unprivileged user; legitimate package operations use `/var/cache` or download paths |
| dpkg build tree | `/tmp/pkbuild_*`, `/tmp/build_*` | Staging directories for `dpkg-deb -b` |
| rpmbuild tree in `/tmp` | `/tmp/rpmbuild_*` | Staging directories for `rpmbuild` invoked outside `~/rpmbuild` |
| postinst / %post script in `/tmp` | `/tmp/*/DEBIAN/postinst`, `/tmp/*/SPECS/*.spec` | Scripts that copy or chmod system binaries are high-confidence |
### Process & Execution
| IOC | Detail |
|-----|--------|
| `dpkg-deb` spawned by non-root, non-apt process | Parent is a user Python/shell process, not `apt`, `dpkg`, or `unattended-upgrades` |
| `rpmbuild` spawned by unprivileged user | Without a packaging-related parent (`mock`, `koji`, CI runner) this is anomalous |
| `packagekitd` spawning `/bin/sh` or `/bin/bash` from `/tmp` path | `packagekitd` runs postinst scripts; source path in `/tmp` is the anomaly |
| `bash` process where `UID โ EUID` | SUID execution; `EUID=0`, `UID=` |
| `bash -p` invocation | The `-p` flag enables privileged mode when SUID is set โ rarely used legitimately |
| Short-lived `.suid_bash` process ancestry | Grandparent is `packagekitd`, parent is attacker's shell |
### D-Bus Activity
| IOC | Detail |
|-----|--------|
| `org.freedesktop.PackageKit.Transaction.InstallFiles` called twice on same object path | Both calls arrive within milliseconds; legitimate clients call once per transaction |
| `FLAG_SIMULATE (4)` followed immediately by `FLAG_NONE (0)` on same `tid` | This sequence has no legitimate use case |
| `CreateTransaction` โ rapid double `InstallFiles` pattern | Detectable via D-Bus monitor (`dbus-monitor --system`) or audit `dbus` rules |
| `InstallFiles` with a file path under `/tmp` | Legitimate GUI package installers (GNOME Software, Discover) use paths in `$HOME` or `/var/cache` |
### Audit Log Patterns
> Enable with: `auditctl -a always,exit -F arch=b64 -S all -F path=/usr/bin/packagekitd`
> Or use the rules below in `/etc/audit/rules.d/`:
```
# Detect SUID file creation in world-writable directories
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/tmp -k suid_in_tmp
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/var/tmp -k suid_in_tmp
# Detect dpkg-deb / rpmbuild by non-root
-w /usr/bin/dpkg-deb -p x -k pkg_build_nonroot
-w /usr/bin/rpmbuild -p x -k pkg_build_nonroot
# Detect bash executed with SUID from /tmp
-a always,exit -F arch=b64 -S execve -F exe=/tmp/.suid_bash -k suid_bash_exec
-a always,exit -F arch=b64 -S execve -F dir=/tmp -F uid!=0 -F euid=0 -k priv_esc_tmp
```
### Package Manager Artifacts
| IOC | Detail |
|-----|--------|
| Package named `pk-dummy-*` or `pk-payload-*` in dpkg/rpm history | Script-specific but variants will use different names |
| Package installed from local file (`/tmp/*.deb` or `/tmp/*.rpm`) | `dpkg -l` or `rpm -qa --last` โ look for packages with no repository origin |
| Package installed with no changelog / empty description | Crafted packages use minimal metadata; `dpkg -s ` or `rpm -qi ` |
| Package removed immediately after install or never appears in package DB | Failed exploit attempts may leave partial state |
| `packagekit` transaction log entries for local-file installs | `/var/log/PackageKit/transactions.db` or journald `packagekitd` entries |
### Privilege Escalation Artifacts
| IOC | Detail |
|-----|--------|
| `/tmp/.suid_bash` exists on disk | Primary payload; filename varies by attacker but `/tmp/.*` (hidden in tmp) is common |
| Any file in `/tmp` owned by `root` with SUID bit | `find /tmp -uid 0 -perm -4000` โ should always return empty on clean systems |
| `bash` process tree with `euid=0` and no PAM / sudo / su ancestor | Indicates SUID execution path rather than legitimate privilege transition |
| polkit grant for `org.freedesktop.packagekit.package-install` to non-admin user | Unexpected if user is not in `sudo` / `wheel` group |
---
## Detection Logic
### SIEM Pseudo-Rule (Generic โ covers all CVE-2026-41651 variants)
```
(
event.category == "process"
AND process.name IN ("dpkg-deb", "rpmbuild")
AND process.user.id != "0"
AND NOT process.parent.name IN ("apt", "apt-get", "dpkg", "rpm", "dnf", "yum", "zypper", "mock", "koji")
)
OR
(
event.category == "file"
AND file.path LIKE "/tmp/%"
AND file.owner == "root"
AND (file.mode LIKE "04%")
)
OR
(
event.category == "process"
AND process.name == "bash"
AND process.real_user.id != "0"
AND process.effective_user.id == "0"
AND NOT process.parent.name IN ("sudo", "su", "sshd", "login", "pam")
)
```
### EDR Behavioral Chain
```
packagekitd
โโ sh / bash (cwd or arg matches /tmp)
โโ install / cp / chmod (target has SUID + owner root)
```
Flag the full chain. Any individual step alone may be benign; the parent-child relationship through `packagekitd` to a SUID-setting command sourced from `/tmp` is high-fidelity.
---
## Affected Systems & Versions
| Distribution | Default PackageKit | Vulnerable | Patched version available |
|--------------------------|--------------------|------------|---------------------------|
| Ubuntu 24.04 LTS | 1.3.x | Yes | Via `apt upgrade` |
| Ubuntu 22.04 LTS | 1.2.x | Yes | Backport in progress |
| Debian 12 (Bookworm) | 1.2.x | Yes | Security tracker pending |
| Fedora 41 | 1.3.x | Yes | `dnf upgrade packagekit` |
| RHEL 9 / CentOS Stream 9 | 1.2.x | Yes | RHSA pending |
| SUSE Linux Enterprise 15 | 1.1.x | Likely | SUSE advisory pending |
| Arch Linux | 1.3.x | Yes | AUR / pacman updated |
> Check installed version: `pkcon backend-details` or `packagekit --version`
> Vulnerable if reported version is **โค 1.3.4**.
---
## Remediation
**Primary:** Upgrade PackageKit to 1.3.5 or apply the vendor-specific backport.
```bash
# Debian / Ubuntu
apt update && apt install --only-upgrade packagekit
# Fedora / RHEL
dnf upgrade packagekit
# SUSE
zypper update packagekit
```
**Mitigations (if patching is not immediately possible):**
| Mitigation | Command / Config | Caveat |
|------------|-----------------|--------|
| Disable PackageKit service | `systemctl disable --now packagekitd` | Breaks GNOME Software / Discover GUI updates |
| Restrict D-Bus access | Add `deny` rule in `/etc/dbus-1/system.d/org.freedesktop.PackageKit.conf` for unprivileged users | May break legitimate user-facing package tools |
| Polkit hardening | Set `org.freedesktop.packagekit.package-install` to `auth_admin` (require admin password always) | Reduces convenience but narrows the attack surface |
| Audit monitoring | Deploy audit rules from the [Audit Log Patterns](#audit-log-patterns) section | Detective only, not preventive |
---
## References
| Resource | Link |
|----------|------|
| OSS-Security disclosure | https://www.openwall.com/lists/oss-security/2026/04/22/6 |
| GitHub Security Advisory | GHSA-f55j-vvr9-69xv |
| Fix commit | https://github.com/PackageKit/PackageKit/commit/76cfb675fb31acc3ad5595d4380bfff56d2a8697 |
| PackageKit 1.3.5 release | https://github.com/PackageKit/PackageKit/releases/tag/v1.3.5 |
| CWE-367 | https://cwe.mitre.org/data/definitions/367.html |
| polkit documentation | https://www.freedesktop.org/software/polkit/docs/latest/ |
---
*Generated: 2026-04-24 | Purple Team Assessment | Internal Use Only*