- Access exclusive content
- Connect with peers
- Share your expertise
- Find support resources
08-31-2022 01:08 PM
PoC Lab ft. CVE-2021-3560
By: @mfakhouri
Executive Summary
What was CVE-2021-3560?
What Does Privilege Escalation Entail?
How is Polkit Supposed to Work?
Cortex XDR at Play
Overview of Lab Setup Script
Adversary Motion and Vulnerability In Action
Cortex XDR - Analytics
Cortex XDR - The Correlation Rule Pivot
Cortex XDR - The BIOC Pivot
Conclusion
Technical Specifications for Lab Work
Sources
Last year, CVE-2021-3560 was discovered by a security analyst that allowed for the rapid local privilege escalation of Linux users. This exploit abused a bug that was left in an old version of polkit, being introduced almost 8 years ago. Having many intricate yet simple components toward the exploitation of the vulnerability, this paper will examine the details of polkit, the service exploited in this vulnerability, and how Cortex XDR has the ability to respond to such attacks. This includes initial alerts created and how one can pivot toward the implementation of advanced detection/prevention techniques within Cortex XDR.
In May of 2021, security researcher Kevin Backhouse discovered that many popular Linux distributions had shipped a vulnerable version of polkit by default. Polkit is an authorization service typically installed by default on more popular distributions, which was later found to have a local privilege escalation vulnerability built into an old commit. This was first shipped with polkit version 0.113. Kevin also highlighted several popular distributions that came with versions of polkit that were vulnerable at the time: RHEL 8, Fedora 21, and Ubuntu 20.04. Interestingly enough, this seemed to have shipped with more recent distributions, as prior versions (RHEL 7, Fedora 20, Ubuntu 18.04) of the operating systems were not impacted by this vulnerability.
This CVE was assigned a base score of 7.8 -High by the National Vulnerability Database (NVD) and was published earlier this year on February 2nd, 2022. Interestingly enough, the addition of the bug for this service was introduced almost 8 years ago, identified by the following commit. It was found that, by tricking checks by the dbus (the Linux interprocess communications system), polkit could be tricked into elevating the local privilege of a user. This could allow the creation of a new administrator, provoking a great threat to potential confidential files or sensitive configurations attributed to most Linux servers.
Authentication bypass vulnerability fix, source
Surprisingly, it was only fixed with a three-line commit (in the figure above). We’ll look into how that came to be in just a moment.
The majority of the time, workstations are designed to include multiple user accounts varying between levels of permission. These permissions, also known as privileges, can grant access to a wide variety of actions for the administrator. This can include the ability to read, write, and execute multiple crucial endpoint configuration files, or provide access to greater communications among other endpoints within a network.
Overview of basic r/w/x permissions in Linux, source
Privilege escalation attacks seek to exploit these configured roles through a vulnerability, including programming errors, misconfigurations of access control, or errors in design. Though it has no immediate consequences toward the device that it is initiated upon, it can drive a threat actor to install ransomware onto an endpoint, gain access to private data, or have greater ease of access between multiple systems in a network (similar to lateral movement).
Polkit is an authorization toolkit used on Linux operating systems that ensures the user requesting a particular administrative behavior has the right to do so. How often have you seen the following login screen when attempting to change a setting, start a service, or in this case, format a new drive on a Linux endpoint?
Example auth required w/ polkit
This is just one example of how polkit functions under a desktop environment, running in the background and providing that decision-making process for the administrator permission in this case. Polkit works with many other groups of actions as well, such as systemd-logind (power off, reboot, suspend, and hibernate the system), and NetworkManager (enable/disable network, wifi, or mobile broadband). This is not limited to the graphical interface as well, as seen in the following SSH instance:
SSH instance of polkit
The sequence of events for the figures above represents the last few steps in the authorization process for polkit. After all, it makes sense to not repeatedly ask a user with an administrator role if they have any local authority, ensuring there is a valid check for sudo privilege beforehand when an administrative action is performed. The vulnerability largely comes into play right before this sequence of events when polkit looks at the UID of the connection initiated by the user.
Architecture of polkit in man, source
The figure of the polkit architecture above describes how each process within the operating system interconnects for this flow of authorization. Normally, right before the stage where the system requests the dialog box presented for the user (through the dbus aka System Message Bus), polkit will ask for the UID as mentioned. This is done through the authentication agent seen in the architecture abovc. In the vulnerability we’ll be looking at, we will see how the dbus will misinterpret an unexpected kill request sent through the command line to escalate local user privileges.
As mentioned prior, this type of attack does not immediately entail any damage to the workstation. Throughout a breach, attacker dwell times can last weeks. Earlier in 2022, it was identified that the average intruder dwell time found in 2021 was 21 days. Cortex XDR comes into play rather nicely with this particular incident since it demonstrates its use of multiple informative alerts regarding the attack which can then be used to pivot toward greater detection/prevention techniques.
To ensure reproduction for additional testing and for educational purposes, a lab setup script has been created. This script is broken down into several sections to capture the setup process and inform the user of the prerequisites required to properly exploit the CVE as outlined by Backhouse.
Menu of Cortex XDR PoC lab checklist script. Found here: https://github.com/mikefak/XDR-PoC
Though this exploit is vulnerable on various Linux distributions, all of this script’s testing has been performed on an Ubuntu endpoint. This is because of its ease of access for installation and set-up, as other distributions have proven to be difficult to establish environments for in this lab (particularly, Debian Bullseye (testing) and CentOS 8).
The “Initiate Checklist Scan” option will run through the many subtle requirements needed in order to run the exploit successfully. Keep in mind that the primary threat in regard to this CVE is that most of these conditions are already met upon the installation of the operating system, and Ubuntu 20.04 is a great example of this. It already has the necessary packages accountsservice, gnome-control-center, and polkit installed by default. The only other package that needs to be installed is SSH, which is already commonly installed on endpoints for administrative use.
Further, the checklist goes through the operating system information and environment it is set to run. The operating system information distinguishes the type of Linux distribution along with if it is known whether or not it is shipped with a vulnerable version of polkit by default. This is helpful since configurations may differ depending on the distribution.
Example checklist with all requirements met
The environment is also important, needing to be equipped within an SSH instance. Remember when we distinguished polkit running in a terminal and remote session? Running the exploit within an SSH session is key here because the GUI pop-ups will hinder our efforts to exploit the vulnerability greatly. Since this attack is time-based, it may take several tries to get right. There is no way to exit the prompt aside from entering credentials or clicking on cancel, leaving an SSH instance as a necessary and convenient way to execute the exploit successfully.
Example auth pop up after vulnerability attempt
Finally, there are some other miscellaneous checks. A non-root user must be executing the script. After all, what is the point of exploiting the service if the user already has privileged access to create a new user in the first place? Also, there is a check for the Cortex XDR agent installation on the endpoint to ensure the agent is capturing the events of the exploit to better see how privilege escalation attacks can be discovered in the first place. This is done by checking for the existence of the locked account cortexuser in /etc/passwd that is inserted upon agent installation. It is also recommended to ensure connectivity under Endpoints > All Endpoints in the Cortex XDR tenant.
With the power of modern reconnaissance tools in cybersecurity, discovering the operating system version of an endpoint utilizing enumeration tools such as nmap (-o flag) is not difficult. These tools make discovering operating systems with potentially vulnerable packages a lot easier, which can then be used to target exploits similar to the polkit vulnerability shipped with the default installation of the distributions mentioned.
Beyond this step, a variety of initial access techniques can be initiated to acquire a potential user account on an endpoint. Some popular Mitre techniques on the attack matrix include phishing, supply chain compromises, or brute force attacks.
At this point of an attack, privilege escalation would likely be one of the next few steps from an attacker's perspective. This could be for persistence, hijacking execution flows, searching for additional credentials, etc. Let's examine how to exploit CVE-2021-3560 from this point on.
The primary command used in this attack is “dbus-send”, which is accessible to unprivileged user processes. Dbus-send will ask the accounts-daemon to create a new user for us. The accounts-daemon will then ask polkit if the user creating the new account has sufficient permissions. To do this, polkit will ask for the UID of the user initiating the command. This is right before the authentication agent opens the dialog box we saw prior to authorize users with a password.
If, when asking for the UID of the user, the request is cancelled, the command will function normally in the sense that it will return an error. The way the error is handled, though, is where the vulnerability comes into play. Rather than throwing out an error and exiting the program, the request is treated as though it came from a process with a UID of 0 (sudo privileges).
Commit code that resulted in vulnerability
In the commit where the vulnerability was added, we can get a better understanding of where the code falls short here. If the data captured falls into “data.caught_error”, there is no error handling that exists. It will exit next and default to that “ret = TRUE” line at the bottom. With this in mind, the commit to fix the vulnerability makes a lot more sense, having the program properly exit the loop when the error is received. The following code was placed right above the two if statements to fix the vulnerability:
Commit that fixed vulnerability
Thomas Claburn said it best in his article last year talking about the vulnerability: “Error handling? Nah, let's just unlock everything and be done with it”. This is only on one of the code paths where the error can occur according to Backhouse. So, when executing the command and killing it early on, if we hit this codepath, the command will execute as if our UID was 0. Here is an example of what the initial username insertion process may look like:
Initial account insertion
The first dbus-send command sent is requesting the approximate time that the command will take to run. A reminder that this is the command asking the accounts-daemon to create that new account for us. Backhouse has approximated that the time required before abruptly closing the connection is around half of the time it takes to run the command to hit that vulnerable code path.
So, in the following next two lines, I am sending the command and attempting to create “mfak-eviladmin”. Sleep is utilized here with half of the time I was given in the first command, followed by the kill signal.
Account insertion successful
This usually takes a few tries, but with some luck, I have now successfully inserted my new user with sudo privileges. The “id” command will show if it is created and prove its existence within the sudo group.
I can’t exactly login yet since I need to also insert a password attributed with the account. Dbus specifically accepts hashed passwords, so I need to create one with openssl (ex. openssl -passwd -5 evilsecurepassword). Here is what the second insertion may look like:
Password insertion successful
The command has changed just a bit this time around. “CreateUser” is now “SetPassword” and the hash takes the place of the first string in the command. The UID of the inserted user is also specified in the command, being 1002. Now, the account is accessible via the switch user, or “su” command, and I can enter sudo bash for a root command prompt.
Here, the sky's the limit with the capabilities I’m able to produce on the endpoint. I can change/edit permissions of configuration files, add persistence users, etc. Let's take a look at how Cortex XDR can respond to the exploit.
The following tests were performed on an Ubuntu 20.04.2 endpoint with the Cortex XDR agent installed. The agent installation was on version 7.8 and Pro capabilities were enabled on the endpoint. This allows the agent to have a greater scope of capabilities, such as enhanced data collection, advanced responses, and attached add-ons. The exploit was performed multiple times on the same endpoint originating from the unprivileged user “mf-user”. The following evil administrators were created with the exploit: boris and mf-eviladmin.
As a result of the initial steps to exploit the vulnerability, as seen above, Cortex XDR Analytics covers a lot of initial ground for the visibility of the exploit. This feature examines logs and data to establish an activity baseline to recognize abnormal behavior when it occurs. Since a new user was created with administrator privileges, which then performed reconnaissance to confirm access, Cortex XDR can alert that there may be suspicious activity occurring.
Low severity Analytics Alert created in a new Incident
Here, we can see an incident created and sourced from Cortex XDR’s Analytics engine. As a part of the exploit, multiple discovery commands must be made to see if the inserted user was created along with ensuring root privileges as well. This involves looking through sensitive files, like /etc/passwd or /etc/sudoers. Even simple discovery commands such as “id” to check for our created user also contribute toward unique discovery commands that can be captured by Cortex XDR Analytic Alerts.
Informational BIOC from alert
When looking into insights from the alerts provided, numerous informational BIOCs are attributed to the alert created. Alerts like these will not create an incident of their own but will provide context to the alerts attributed to the incident.
As a security analyst, one could now be curious about the full story regarding the informational BIOCs related to these suspicious Analytic Alerts and relevant insights. Especially in the case of insights like the following where the root user is engaging in discovery commands:
Root user informational BIOC insight
We can look at the Causality View of the insight by examining it in XQL (right-click menu of insight) and looking at its Causality View in the output of the query (right-click menu of query output). This perspective demonstrates how the insight originated with intelligently built process nodes.
Causality Analysis view of alert (Disclaimer: tree shortened for demonstration as a result of testing)
Surprisingly, Cortex XDR is able to intelligently identify each step toward the creation of our dbus-send command followed by the enumeration that sets off the insight after gaining access. On the top, we have the initial commands entered for the exploit. This starts from our initial SSH from root to the “mf-user” account, which has only user privileges on the host. The number “42” on the bash icon next to our initial SSH shows the total number of child processes attributed to that particular instance. As mentioned, this exploit takes multiple attempts on both the username and password insertion as well as reconnaissance commands to ensure success. All commands entered in this instance are viewable by clicking on the node and viewing the description. After selecting the node, we can quickly tell that we are dealing with CVE-2021-3560.
Dbus-send insertion attempts listed under the bash node
On the bottom tree, we can see the exact instance where “mf-user” switches to its created user “boris” and begins enumeration on the endpoint to identify and confirm administrator access. We also see that this extends until the “cat” command that was triggered with Cortex XDR Information Analytics and how we were able to view the chain of processes initially.
With the help of the Analytic Alerts and the wonderful Causality Instance presented, we can now better integrate the information given with a standard working environment. After all, we are given this useful information, but how can a security analyst potentially pivot after seeing suspicious activity such as the exploit above? Beyond the immediate isolation of the endpoint or package updates, the creation of a new detection rule can prove to be useful for future exploitation attempts.
When an endpoint policy is configured to monitor and collect enhanced endpoint data, additional insightful information regarding actions performed on the endpoint is collected and queryable via the XQL search query.
XDR Pro Endpoints enabled via Agent Settings profile
I can create a search query to look for dbus-send process actions sent on Linux endpoints with the query builder. Here is a basic example query to look for such events:
dataset = xdr_data //Endpoint Data Collected by Cortex XDR)
| filter action_process_image_name ~= “dbus-send” //Process instances of the Dbus-send command
Basic XQL query for "dbus-send"
Here, 21 instances of dbus-send commands have been discovered beyond the description seen above. Along with this, we are given a wide range of information available about every instance of dbus-send. One problem with this is that this will apply to all instances of dbus-send commands being sent. Usually, this can be used as an administrative tool to direct messages toward systems running on any given endpoint. So, by utilizing some more XQL to filter through the information while keeping the exploit in mind, we can alter our XQL to better reflect the available information. The following query was created to address this issue.
//XQL Query for CVE-2021-3560
//Multiple dbus send commands via SSH (>=3)
dataset = xdr_data
| filter event_type = ENUM.PROCESS
| filter action_process_image_name ~= "dbus-send"
| filter agent_os_type = AGENT_OS_LINUX
| filter causality_actor_process_image_name = "sshd"
| fields agent_hostname as Linux_Hostname, actor_process_command_line as Command_Executed, actor_process_os_pid as PID, actor_effective_username as Actor_Username, action_process_image_command_line as DBUS_Command, causality_actor_process_image_name, action_process_image_name as DBUS_Action, action_file_path
| comp count(Command_Executed) as Potential_Cred_Insertions by Linux_Hostname, PID, Actor_Username, DBUS_Command, DBUS_Action
| filter Potential_Cred_Insertions >= 3
| sort desc Potential_Cred_Insertions
This query starts by looking at all endpoint data collected with XDR data. Next, the first four filter commands all help to siphon down potential real cases of dbus-send commands on the endpoint. This includes filtering for process event types, only searching for “dbus-send” commands, searching for only Linux endpoints, and finally searching for causality actors to exist within an SSH instance (which is required by the exploit in most situations).
Next, the field commands help organize and control the output for a better understanding of the exploit and what occurred. Finally, the “comp” command on the bottom allows us to count the number of times this command is being executed. To prevent false positives, results must have more than three instances of dbus-send commands executed from the same SSH instance. This can be adjusted depending on the environment on the second to last line. With the tests performed, here’s what the query output looks like:
More elaborate XQL Query results
Here, I get a neat output of each instance of potential credential insertions on the endpoint. What's nice about this output menu as well is the fact that we can see the dbus-command executed, which is a separate entry for both the username and password of the inserted user. This means that we are also able to read the hashed password and potentially decrypt it as well. We also see the hostname of the endpoint, the process ID, the active user, the dbus-commands, the dbus action, and the number of attempted potential credential insertions.
Full dbus command to insert a hashed password into the created user
You may notice an additional “MF-UbuntuKernelTest” hostname on the output as well. This exploit was tested both on Linux endpoints running the Cortex XDR agent on User Mode and Kernel Mode. This was done because Ubuntu 20.04 by default does not have a compatible kernel version with the XDR agent and must either be run in User Mode (done in the agent settings profile) or by switching to a compatible kernel version. Both appear to provide information about the exploit performed that can be queried by the XQL provided.
With this XQL query, we can now create a Correlation Rule to create alerts on new data that is found with the query. A Correlation Rule alerts correlations from multiple sources/events utilizing XQL, which allow us to be notified of these specific conditions for the exploit to occur in. This rule also occurs periodically, initiating the query up to several times a day depending on our preferences.
Correlation Rule creation
The Correlation Rule’s primary parameters involve an XQL query, so we can use the one made to create alerts for future attempts to exploit this vulnerability.
Correlation Rule creation cont.
After implementing the XQL, additional settings can be attributed to our new Correlation Rule. This includes the ability to throw an alert if the XQL query is met. Here, I am naming the alert, providing a description, and selecting privilege escalation as one of Mitre's attack techniques and tactics. Notice that in the alert name and description, I can use variables found from my query for additional information when examining the alert.
Correlation Rule alert of exploit
After initiating the exploit on the same endpoint again, I am given the alert above that is sourced from our newly created Correlation Rule. Cortex XDR was able to intelligently attribute this alert with the low severity Cortex XDR Analytics generated incident as well, updating its name and description (notice the query variables in the name/description also).
With our new Correlation Rule, I can now successfully identify the discrepancy I am looking for in the collected logs, being more than three dbus-send commands initiated via SSH to identify the potential for the polkit vulnerability.
Though the Correlation Rule is a nice and sophisticated way to create an alert for this exploit, it isn’t always the case that this would be the desired route in the first place. After all, dbus-send is already an uncommon administrative command to be initiated on a terminal while also running in an SSH instance. As a result, it may be the case where one would want to outright prevent any sort of activity detected in these circumstances. BIOC rules allow us to create behavioral detecting rules utilizing part of our XQL query, which can then be implemented toward our endpoint’s Restrictions Profile to block attack attempts. A BIOC rule can be created under: Detection Rules > BIOC > +Add BIOC.
BIOC rule creation
Since the visual output of our XQL query is irrelevant if we want to prevent the action, the only XQL logic needed will be our dataset and filters. In this case, rather than waiting for the number of dbus-send attempts to grow beyond three before raising an alert, all instances of dbus-send commands through SSH sessions will be alerted through our BIOC. Aside from that detail, all other information can remain the same as our Correlation Rule regarding the Mitre tactics/techniques and severity.
This will only begin actively creating alerts whenever each dbus-send command is sent via SSH in comparison to the Correlation Rule’s periodic scan with our XQL query. To begin preventing the initial command, our BIOC must be attributed to our endpoint’s Restriction Profile. Restrictions Profiles can add the custom rule we created with the BIOC and create a prevention rule out of it. This can be performed on the BIOC right-click menu: Right-click a BIOC > Add to Restrictions Profile > Select Applicable Restrictions Profile > Add. The finished result in our profile will look like the following:
BIOC Rule added to Restrictions Profile
Here, we are able to see all instances of the BIOC alert being triggered. This indicates that an action was indeed blocked on the endpoint since every time the alert will occur, the BIOC prevents the attack. Let's try to run the exploit again and see what happens.
BIOC prevention test
From the test back on the endpoint, I logged into the user account with SSH and executed the username dbus-send insertion. After, my connection to the local host was closed by a remote host.
Well… what happened? Did the sleep command go through? Apparently not, since after setting the sleep to 100s, the sleep period was avoided and the connectivity abruptly shut. Because of the crucial timing this exploit requires, it seems the efforts to exploit this vulnerability have been thwarted. My user was also never inserted after checking with the ID command. Let's take a look at a more detailed view of what happened back to the tenant.
Prevention alerts on new Incident
Many new high-severity alerts were created and attributed to the same incident that caught the Correlation alerts, and all were created for each test done on the endpoint. The exploit was attempted multiple times in an effort to see if “sleep” was run in the command chain. As a result, all five of my attempts were prevented with the alert name and description relating to the BIOC rule that I created earlier. The full picture still appears to be a little vague, however, so let's take a proper look at the Causality View of the alert through the right-click menu:
Causality View of BIOC prevention alert
With the full Causality View, aspects of our test on the endpoint seem to come together. The chain begins with the Causality Group Owner, being the SSH instance launched by the root user. Further enumeration of log information was done on the next two nodes, which can prove to be incredibly useful in the case of an actual attack, but is irrelevant in this demonstration.
Then, the login to the mf-user account is made, and executes additional commands in the bash node that follows. When finally entering the dbus-send command, our BIOC alert triggers, identifiable with the “B” triangle above the final node. With this triggered BIOC, we can see the prevention action initiated on the Causality Group Owner, being the SSH instance beginning with the root user. This series of actions make a lot more sense from what we saw from the endpoint’s perspective with the SSH connection abruptly ending.
Causality Group Owner of exploit prevented
Closing the SSH connection is great for the prevention of this particular exploit since the consistent way of performing the exploit is now mitigated. Backhouse also notes in the write-up of his discovery of the exploit that “...it's also the reason why the bug wasn’t previously discovered. If you could trigger the vulnerability by killing the dbus-send command immediately, then I expect it would have been discovered a long time ago.” Since the timing is now killed, the exploit attempt will no longer function properly and is successfully prevented.
The exploitation of CVE-2021-3560 allows for remote privilege escalation on Linux endpoints on relatively recent installations of popular distributions, including Ubuntu 20.04, Fedora 21, CentOS 8, and RHEL 8. After deploying the CVE in an environment alongside Cortex XDR, Analytic Alerts were shown to be a powerful form of detection in cases where privilege escalation may occur. Further, when analyzing the Causality Group Owner of insights related to these alerts, the ability to pivot work effort toward prevention/detection rules have also demonstrated relevant use in the case of this exploit when utilizing XQL querying. Correlation and BIOC rules were created as a result, which successfully alerted and prevented this exploit in action.
For the purposes of reproduction and testing, here are some of the Technical Specifications on the lab:
Lab Setup Script: https://github.com/mikefak/XDR-PoC
XQL Queries, Correlation basic/advanced and BIOC:
//Correlation Basic
dataset = xdr_data //Endpoint Data Collected by Cortex XDR)
| filter action_process_image_name ~= “dbus-send” //Process instances of the Dbus-send command
//Correlation Advanced
//XQL Query for CVE-2021-3560
//Multiple dbus send commands via SSH
dataset = xdr_data
| filter event_type = ENUM.PROCESS
| filter action_process_image_name ~= "dbus-send"
| filter agent_os_type = AGENT_OS_LINUX
| filter causality_actor_process_image_name = "sshd"
| fields agent_hostname as Linux_Hostname, actor_process_command_line as Command_Executed, actor_process_os_pid as PID, actor_effective_username as Actor_Username, action_process_image_command_line as DBUS_Command, causality_actor_process_image_name, action_process_image_name as DBUS_Action, action_file_path
| comp count(Command_Executed) as Potential_Cred_Insertions by Linux_Hostname, PID, Actor_Username, DBUS_Command, DBUS_Action
| filter Potential_Cred_Insertions >= 3
| sort desc Potential_Cred_Insertions
//BIOC
dataset = xdr_data
| filter event_type = ENUM.PROCESS
| filter action_process_image_name ~= "dbus-send"
| filter agent_os_type = AGENT_OS_LINUX
| filter causality_actor_process_image_name = "sshd"
https://www.cvedetails.com/cve/CVE-2021-3560
https://gitlab.freedesktop.org/polkit/polkit/-/issues/140
https://github.blog/2021-06-10-privilege-escalation-polkit-root-on-linux-with-bug/#conclusion