What if I told you, there has been a rather unnoticed vulnerability within most, if not all, Linux operating systems for over 10 years!? Well, this wouldn’t be a record-breaking time period that a weak point within a particular operating system has gone unnoticed, however, this particular one is quite peculiar. 

What is PwnKit?

So, what exactly is this vulnerability? Well, let’s start at the beginning (insert your best impression of Zuma). To do so, let’s acknowledge the excellent research that was done by Qualys Research Team (basically a mini version of the avengers…if Tony and the gang were cybersecurity professionals). Qualy’s excellent team of professionals, identified a memory corruption within Policy Kit, aka polkit, which enables an unprivileged user to effectively escalate their privileges…essentially hulking up after transforming from Bruce Banner (Marvel films will be the death of me). Now you might be curious, as I was when dwelling into the details of this vulnerability, what is Polkit? Polkit is a rather useful toolkit within Linux systems that enables unprivileged processes to communicate with privileged processes. When we have low privileged applications running within a given system, there are instances, where the unprivileged application requires some resources, as an example, from a more privileged application or processes. With Polkit, the aim is to avoid the unprivileged process from having root permission for an entire process, but rather, it allows for a finer level of control of centralized system policy.

How is PwnKit?

So how is a simple, system toolkit, responsible for a privilege escalation? Well, just like Tony made JARVIS, with great intent, and tweaked him during the Age of Ultron, a simple program that’s part of Polkit is responsible for this vulnerability, and that is, pkexec

Why is pkexec?

In May 2009, pkexec’s first version was added to polkit. Pkexec was created with the sole purpose of enabling a program to execute as another user, however, if a username is not given, the program will execute as a super user, root. Nifty tool for certain occasions however, as we shall see, can be a dangerous foe to all system admins and security architects, et al. Simply put, if you pass a command after pkexec, that command will be executed with elevated privileges.

Alright, let’s get back on course. What makes PwnKit possible is when pkexec, within Polkit, is leveraged by an attacker. An attacker, who already has a low-level foothold within a given system, can escalate their privileges by breaking out-of-bounds (this is when a program writes data past, or in some cases, before the beginning of the buffer) when executing pkexec. Observe the code snippet below (am not good at explaining code, so bear with me):

/* First process options and find the command-line to invoke. Avoid using fancy library routines

   * that depend on environment variables since we haven’t cleared the environment just yet.

   */

  opt_show_help = FALSE;

  opt_show_version = FALSE;

  for (n = 1; n < (guint) argc; n++)

    {

      if (strcmp (argv[n], “–help”) == 0)

        {

          opt_show_help = TRUE;

        }

      else if (strcmp (argv[n], “–version”) == 0)

        {

          opt_show_version = TRUE;

        }

      else if (strcmp (argv[n], “–user”) == 0 || strcmp (argv[n], “-u”) == 0)

        {

          n++;

          if (n >= (guint) argc)

            {

              usage (argc, argv);

              goto out;

            }

          opt_user = g_strdup (argv[n]);

        }

Pkexec()’s main function, parses commands that are passed after it, this is processed from the highlighted portion in the above code snippet (keep in mind of argc, it’s a “surprise tool for later”). Once it has parsed the commands, it searches for the program that will be executed, that’s if, the path to the program is not absolute e.g. (bar – not absolute path, /faa/faa/bar – absolute path): 

/* Now figure out the command-line to run – argv is guaranteed to be NULL-terminated, see

   *

   *  http://lkml.indiana.edu/hypermail/linux/kernel/0409.2/0287.html

   *

   * but do check this is the case.

   *

   * We also try to locate the program in the path if a non-absolute path is given.

   */

  g_assert (argv[argc] == NULL);

  path = g_strdup (argv[n]);

  if (path == NULL)

    {

      usage (argc, argv);

      goto out;

    }

  if (path[0] != ‘/’)

    {

      /* g_find_program_in_path() is not susceptible to attacks via the environment */

      s = g_find_program_in_path (path);

      if (s == NULL)

        {

          g_printerr (“Cannot run program %s: %s\n”, path, strerror (ENOENT));

          goto out;

        }

      g_free (path);

      argv[n] = path = s;

    }

So, if argc is null, i.e., 0, then the pointer path will be read out-of-bounds. Now, to explain how this is a problem, we turn our attention to execve(): this is another linux program that executes a program that is referred to by a pathname. When execve is called, this causes the currently running program to be replaced with a new program. This is then accompanied by the newly initialized stack, heap and data segments.  Within execve are two variables/arguments that we need to cover: argv and envp. Argv – is an array that holds or points to the strings that are passed to the new command as command-line arguments. Envp – is a key-pair array(key=value), which houses the environment of the new program.

Now with all this in mind, assume that argc=0 hence, argv[1] will be out-of-bounds, thus, when execve runs, the value within envp will be read instead of argv. This value will then be passed to g_find_program_in_path(), this is because the value does not start with a slash. The g_find_program_in_path(), will search for the program in the directories, find it, return it to pkexec’s main function and then finally, that full path will be written out-of-bounds to argv(which is essentially, envp). Thus, JARVIS has become Ultron! By introducing an environment variable into pkexec’s environment, we are able to leverage how pkexec works and thus leading to exploitation of this vulnerability.

Avengers, assemble.

Now that you know how this works, in brief, is there a way to stop it? Well, the answer is yes, patching up your system will upgrade to the latest version of polkit and its subsidiary programs. Additionally, because of the broad number of linux systems that are affected by this vulnerability, patches may not be available for all, considering how long this vulnerability has existed. Therefore, legacy system users can remove the SUID bit from pkexec as a temporary measure. This can be done via the command chmod 0755 /usr/bin/pkexec.

End Credits

Before we close this chapter, here are some useful information for all, should you wish to discover more about PwnKit:

  • PwnKit is being tracked as CVE-2021-4034.
  • PwnKit is not an Remote Code Execution exploit, but a Local Privilege Escalation exploit, hence, an attacker with access to an unprivileged user, can exploit this vulnerability in affected systems to gain higher privileges.
  • PwnKit leaves traces in the system logs so a good IOC will be to look for the strings:
    • “The value for the SHELL variable was not found the /etc/shells file”
    • “The value for environment variable […] contains suspicious content”

And that’s it, be sure to give a shout out to The Qualy’s Research Team, as they were responsible for identifying and disclosing this vulnerability. 

No cameo?

Stay tuned, for a guide on how to setup Wazuh to monitor and scan for any PwnKit exploitation, within your environment.

References 

Scroll to top