Share
## 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

![Proof of exploitation](proof.png)

---

## 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*