APPSEC – PWNKIT – CVE-2021-4034

INTRO

It’s been awhile since I’ve made time to write here. Was feeling bored today catching up a the latest buzz and discovered an extremely easy script kiddy exploit out in the wild called PWNKIT aka CVE-2021-4034 Qualys Research Team. Shout out to them.

So What is it?

  • The PWNKIT vulnerability is based on polkit’s pkexec library
  • Pkexec SUID-root program that is installed by default on every major Linux distribution

IN DEPTH ANALYSYS

And what’s PolKit exactly?

https://linux.die.net/man/8/polkit

“PolicyKit provides an authorization API intended to be used by privileged programs (“MECHANISMS”) offering service to unprivileged programs (“CLIENTS”) through some form of IPC mechanism such as D-Bus or Unix pipes. In this scenario, the mechanism typically treats the client as untrusted. For every request from a client, the mechanism needs to determine if the request is authorized or if it should refuse to service the client. Using the PolicyKit API, a mechanism can offload this decision to a trusted party: The PolicyKit Authority.

In addition to acting as an authority, PolicyKit allows users to obtain temporary authorization through authenticating either an administrative user or the owner of the session the client belongs to”

Source code review

https://seclists.org/oss-sec/2022/q1/80

------------------------------------------------------------------------
 435 main (int argc, char *argv[])
 436 {
 ------------------------------------------------------------------------
 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     }
------------------------------------------------------------------------

So the primary flaw is both an input problem and a non NULL pointer reference …

at line 534, the integer n is permanently set to 1;

Hold on… what’s a pointer, I’m new to low level programming…

pointer is a variable whose value is the address of another variable, i.e., direct address of the memory location.

“In most of the operating systems, programs are not permitted to access memory at address 0 because that memory is reserved by the operating system. However, the memory address 0 has special significance; it signals that the pointer is not intended to point to an accessible memory location. But by convention, if a pointer contains the null (zero) value, it is assumed to point to nothing”

For CVE-2021-4034 , integers variables values are set to 1, however according to C best practices pointers should always be set to 0, when there is nothing to point to in the first place.

Oopsie!

So what memory location does the 1 point to?

- at line 610, the path of the program to be executed is read
  out-of-bounds from argv[1] (i.e. envp[0]), and points to "value";

This memory pointer issue later propagates down the code resulting the code at line 629 and 632 treating the “value” variable at envp(0) is actually a path to a file.… but value isn’t a path to a file… but the program doesn’t know that… does it?

So we make a file called, “value” within the directory path the pkexec program is searching in (sideloaded)…. This new file will trick the program into loading the file… and whatever nasty stuff is inside of it …

- at line 610, the path of the program to be executed is read
  out-of-bounds from argv[1] (i.e. envp[0]), and points to "value";

- at line 632, this path "value" is passed to g_find_program_in_path()
  (because "value" does not start with a slash, at line 629);

- g_find_program_in_path() searches for an executable file named "value"
  in the directories of our PATH environment variable;

- if such an executable file is found, its full path is returned to
  pkexec's main() function (at line 632);

- and at line 639, this full path is written out-of-bounds to argv[1]
  (i.e. envp[0]), thus overwriting our first environment variable.

In the case of the wild exploits… researches us LD_PRELOAD ….so what’s that?

https://attack.mitre.org/techniques/T1574/006/

“On Linux, adversaries may set LD_PRELOAD to point to malicious libraries that match the name of legitimate libraries which are requested by a victim program, causing the operating system to load the adversary’s malicious code upon execution of the victim program. LD_PRELOAD can be set via the environment variable or /etc/ld.so.preload file”

……..

When you execute libpolkit-gobject-1, it doesn’t have all the code for the functions it needs because it uses dynamically linked libraries… after you execute…

  • polkit gets loaded into memory
  • the dynamic linker maps the extenral .so libraries that program needs
  • linkers load the external libaries into memory

LD_PRELOAD is an environment variable that says “Whenever you look for a function name, look in me first!“.

…….

To use LD_PRELOAD to get root privilege shell for privilege escalation you also need some sudo permission  binary which use LD_PRELOAD envr.

Now that you understand this technique.. the question is which linked library does the libpolkit program use that we can impersonate using LD_PRELOAD…

GCONV_PATH is one of the "unsecure" environment variables
(because it leads to the execution of arbitrary libraries), and is
therefore removed by ld.so from the environment of SUID programs.

Unfortunately, CVE-2021-4034 allows us to re-introduce GCONV_PATH into
pkexec's environment, and to execute our own shared library, as root.

Exploit in Wild (Script Kiddie stuff)

with about ~20 lines of code ….

Detection, IoCs and Evasion

The Qualys and OpenWall team mention that the basic shell based exploit is easily detected, however there are means to bypass this detection …

Important: this exploitation technique leaves traces in the logs (either

"The value for the SHELL variable was not found the /etc/shells file" or

"The value for environment variable [...] contains suscipious content").

However, please note that this vulnerability is also exploitable without leaving any traces in the logs, but this is left as an exercise for the
interested reader.

I suspect that they are implying you can hijack c libraries using LD_PRELOAD altogether to avoid shell logging or execute the exploit in a non shell program to avoid … but I don’t feel it ethical to modify the exploit into a piece of more advanced malware…. remember the simple exploit attack uses shell which is logged whenever executing execv() within /bin/sh process …

So …. ?

Summary

  • PWNKIT is easy to exploit
  • PWNKIT is widely available on linux platforms
  • PWNKIT trace logs can be evaded
  • Attackers do need to first establish persistance on the machine before executing the LPE
  • Patches are available

https://access.redhat.com/security/vulnerabilities/RHSB-2022-001

https://ubuntu.com/security/CVE-2021-4034

THANK YOU

Leave a comment