Introduction
Team Qualys discovered a local privilege escalation vulnerability in PolicyKit’s (polkit) setuid tool pkexec which allows low-level users to run commands as privileged users. According to Qualys, the vulnerability exists in the pkexec.c code that doesn’t handle the calling parameters count correctly and ends trying to execute environment variables as commands. Thus, an attacker can craft environment variables in such a way that it will induce pkexec to execute arbitrary code. We are using the older vulnerable Ubuntu 20.04 in this demonstration which can be downloaded from Ubuntu’s old releases page. Newer releases already come with a patched polkit framework. Mitre post can be found here.
Polkit and pkexec
Polkit and pkexec: PolicyKit is also known as polkit in Linux systems. It is an authorization API used by programs to elevate its permissions to that of an elevated user and run processes as an elevated user (root, generally). If the user is not specified it tries to run that command as the root user. Sudo does the same thing in terms that it lets a user run commands as root, however, with pkexec, admins can finely control the execution of particular programs by defining policies for it. Sudo has no restriction and a user may run any command as an elevated user-given, he knows the password. Pkexec also takes some effort in setting up but Debian variants, including the popular Ubuntu, come with polkit and pkexec pre-installed. These authorization rules for third party packages are defined in *.rules JavaScript files kept in the directory /usr/share/polkit-1/rules.d/
You can read more about polkit and basics here.
Details about PwnKit
Pkexec’s code can be viewed on github here. In the main function, you can see two parameters being passed, argc and argv[].
If we do not pass any argument to this function, argc =0 and argv = NULL. In the for loop, n is now set to 1 and the loop does not execute as the condition fails.
When a program is executed, arguments, environment variables and pointers are placed contiguously in stack. path variable is set to NULL. This makes argv[argc] equal to Null and finally, argv[n] becomes argv[1] (as n=11) which becomes the envp[] or the environment variable. Author calls it “value”. (You can refer to the original post to understand in-depth)
Since the path is NULL, it doesn’t start with “/” (indicating absolute path) and hence, the function g_find_program_in_path searches for the value in the environment variables.
Variable s is finally set to that environment variable “value”
Attack vector: An attacker can create an environment variable and use this memory corruption technique to run his own executable named “value.” Hence, an attacker can use pre-existing environment variable privilege escalation methods to exploit this.
Demonstration
A proof of concept for this vulnerability has been uploaded on github which can be found here. To run the attack, we simply need to clone the repository, make the executable and run it. The program will exploit this memory corruption weakness as explained above.
cd /tmp git clone https://github.com/berdav/CVE-2021-4034 pwnkit make ./cve-2021-4034 whoami cat /etc/passwd
And just with two commands, we have exploited pkexec’s vulnerability and escalated ourselves to root!
Mitigation
- The vulnerability has already been patched by respective vendors. In Ubuntu 20.04 policykit-1 – 0.105-26ubuntu1.2 version mitigates this weakness.
- If no patches are available for your operating system, you can remove the SUID-bit from pkexec as temporary mitigation.
chmod 07555 /usr/bin/pkexec
Conclusion
All of the unupdated older versions of Debian flavours and Red hat flavours are susceptible to this attack making it a severe risk for an organization. The ease of exploitation of this attack makes it even more dangerous. It is highly recommended that sysadmins update their installed polkit packages today. Thanks for reading.
Author: Harshit Rajpal is an InfoSec researcher and left and right brain thinker. Contact here