Pulsar preventing vulnerabilities #1 — polkit (CVE-2021–4034) #238
cybermari-rs
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Pulsar preventing vulnerabilities #1 - polkit (CVE-2021-4034)
Pulsar is a security framework. Its primal goal is to prevent actual attacks in your IoT environment. One part of achieving that are generic rules which might help with detecting suspicious activity in your system, but that’s only one part of what we are focusing on. The other important part is studying known vulnerabilities in order to prevent them.
In this series of articles we are going to show Pulsar on the battlefield - how it can be used to prevent actual known vulnerabilities.
Understanding CVE-2021-4034
Introducing PwnKit
CVE-2021-4034, also known as "PwnKit," is a security vulnerability discovered in polkit, a system service installed by default on many Linux distributions. Polkit (formerly PolicyKit) is used to manage system-wide privileges in Unix-like operating systems.
To be precise, the vulnerability specifically affects pkexec, a program that is part of the polkit system. pkexec allows an authorized user to execute commands as another user, including the superuser (root). It’s responsible for communicating with polkit and making a verdict whether the user executing the command should be able to do it, even though that user normally cannot execute the wrapped command.
You can think of pkexec of being somehow similar to sudo, although the difference is that sudo simply allows some groups of users (or some specific users) to authenticate as root just by using their passwords, while polkit has more complex rules which define what and under what circumstance can be done.
A common rule used in most graphical Linux installations is mounting external drives. Normally, mounting new filesystems with the
mount
syscall, requires root privileges. But when you are using Linux with a desktop environment, you are not being asked for a password after plugging in an USB stick. That’s because of udisks which has polkit rule!Without it, using Linux on a desktop would be quite annoying, wouldn’t it?
That’s why the security of pkexec itself is extremely important. If there is any way of tricking pkexec into making a wrong decision, the game is over. And unfortunately, PwnKit won the game.
How PwnKit works
In Linux, all processes have an array of arguments, called
argv[]
, which is followed by an array of environment variables, calledenvp[]
. Both arrays areNULL
terminated. The length ofargv[]
is being provided in another variable, calledargc
. For a simplepkctl my-command
call, the arrays and their memory layout would look like:There are no requirements with regards to the size of these - they can be empty. In that case,
argc
would have value 0.The problem is that the vulnerable version of pkctl doesn’t check
argc
in a safe manner. Instead, it assumes thatargv[1]
is eitherNULL
or a command to execute, no matter what. But then ifargv[]
is empty, according to pointer arithmetics in C, readingargv[1]
results in readingenvp[0]
. C doesn’t check the bounds of the pointers, the language simply computes the memory location by treating the index (1 inargv[1]
) as an offset from the starting point (argv[0]
). This calculation leads directly to the memory location, without any validation of the pointer's limits.If an attacker manages to make the argument array empty, pkexec will mistakenly use the content from the adjacent environment array as the application to execute. By adjusting these environment variables to include certain values and payloads, the attacker can exploit this to run commands as a privileged user. This execution occurs without needing any authentication.
If you are curious about details, you can look at one of the exploit examples.
Polkit upstream fix
Polkit fixed this issue by introducing explicit checks for argc.
To prevent such issues in general, Linux kernel 5.18 introduced a change which:
For userspace processes, when argv[] is empty, it adds an empty string and sets argc to 1.
For kernel threads, it rejects ones with empty argv[].
Preventing polkit exploitation in vulnerable environments
To come up with an answer, let’s think about what’s unique about the pwnkit exploit in comparison to all the other processes in the system.
The answer is simple - it’s being scheduled with an empty array of arguments - argc of value 0 and with empty argv. We can already consider this simple fact as a suspicious property of any process. Why would we even have processes launching without argv? Every command which is being executed correctly, has at least its own name as an argument. Can you think of any legitimate use case of stripping the argv when executing a binary? Me neither!
Could we then just disallow any processes with empty argc and argv? Yes!
When running Linux with kernel older than 5.18, one can mitigate the issue by this simple Pulsar rule:
- name: CVE-2021-4034, possible envp manipulation with empty argv type: Exec condition: payload.argc == 0
This rule monitors all
Exec
events (a new process launched through execution a binary) and is triggered whenargc
(number of arguments) is 0.Pulsar with the rule above is going to issue the following alert whenever we are trying to either use a PwnKit exploit or, in general, launch processes with empty argv[], trying our luck in finding out whether some software can be vulnerable to manipulation with argv[] and envp[].
Final remarks
As we mentioned at the beginning, with this post, we are starting a whole series about using Pulsar on the battlefield against CVEs and known attack vectors. Stay tuned for more rules and examples in the coming weeks.
If you like it, don't forget to try out Pulsar and give it a star on github!
Beta Was this translation helpful? Give feedback.
All reactions