CVE-2023-30534: Insecure Deserialization in Cacti prior to 1.2.25

By admin

CVE-2023-30534
ORG

: Insecure Deserialization in Cacti prior to 1.2.25

Overview

We discovered

two
CARDINAL

instances of insecure deserialization in

Cacti
PERSON

versions prior to

1.2.25
CARDINAL

, tracked as

CVE-2023-30534
ORG

. Each instance of insecure deserialization can be triggered remotely, but cannot be exploited due to a limited execution environment which is discussed further in

the "Attempting Exploitation
EVENT

" section.

For those unfamiliar,

Cacti
PERSON

is an open source network management and graphing solution that utilizes

RRDtool
ORG

’s data storage and graphing functionality to discover devices, create graphs, and more. While some instances of Cacti are accessible externally, its primary use is for monitoring internal network systems.

Now, to dive a bit deeper into the technical aspect: Serialization is the process of taking complex data structures like

PHP
ORG

or

Java
PERSON

objects and transforming them into a format that is easier to send over the network.

Deserialization
ORG

is when that data gets transformed back into a complex data structure. An insecure deserialization occurs when user-controlled data is deserialized, potentially enabling attackers to instantiate arbitrary objects, read and write files, and even gain remote code execution.

Note: Cacti version

1.2.25
CARDINAL

(and

1.3.0
CARDINAL

) fixes

an additional 17
CARDINAL

vulnerabilities in Cacti, including critical and high-severity vulnerabilities, so administrators should upgrade when possible.

Affected versions

We originally discovered the insecure deserialization vulnerability in Cacti

1.2.10
DATE

, and all versions prior to

1.2.25
CARDINAL

are vulnerable. Cacti version

1.3.0
CARDINAL

, released alongside 1.2.5, also fixes the insecure deserialization.

Breaking down the insecure deserialization vulnerabilities

Each instance of insecure deserialization is tied to the usage of the unserialize function without properly sanitizing user input. While Cacti does offer a “safe deserialization” utility function that attempts to sanitize and verify that the string content only contains specific values before calling unserialize, this function was not used in these instances.

Note: In code blocks, … represents unreferenced code that has been removed for brevity.

managers.php

The vulnerable code is located in the managers.php file, specifically within the form_actions function. The following code snippet is from

Cacti
ORG

version

1.2.10
CARDINAL

:

function form_actions ( ) { global $manager_actions , $manager_notification_actions ; if ( isset_request_var ( ‘selected_items’ ) ) { if ( isset_request_var ( ‘action_receivers’ ) ) { … … … } elseif ( isset_request_var ( ‘action_receiver_notifications’ ) ) { get_filter_request_var ( ‘id’ ) ; $selected_items = unserialize ( stripslashes ( get_nfilter_request_var ( ‘selected_items’ ) ) ) ; … } … }

By setting the

POST
ORG

request variable action_receiver_notifications , we can direct the code flow to hit the unserialize call in the form_actions function. To trigger form_actions , we need to set the “action” variable to “actions”. This ensures we hit the proper case in the switch statement, as shown below:

switch ( get_request_var ( ‘action’ ) ) { case ‘save’ : form_save ( ) ; break ; case ‘actions’ : form_actions ( ) ; break ; … …

To target the vulnerable unserialize function, an authenticated user sends a POST request that includes a URL encoded serialized PHP object in the “selected_items” variable, as follows:

If we put an invalid object (e.g. one that is malformed or includes a class Cacti does not know about) as the value for the “selected_items” variable, we can see Cacti failing to unserialize the payload in the logs:

At this point, we can control code flow to call unserialize on a user-controlled, serialized object in managers.php.

graphs_new.php

The vulnerable code is located in the graphs_new.php file, specifically in the host_new_graphs_save function. The following code snippet is from

Cacti
ORG

version

1.2.10
CARDINAL

:

function host_new_graphs_save ( $host_id ) { $selected_graphs_array = unserialize ( stripslashes ( get_nfilter_request_var ( ‘selected_graphs_array’ ) ) ) ; $values = array ( ) ;

This function unserializes the user controlled parameter selected_graphs_array . While stripslashes is run

first
ORDINAL

, this simply removes extra slashes that are needed in strings during pre-processing (e.g. \” to “).

In order to reach this function, the user makes a request to graphs_new.php with

two
CARDINAL

parameters: action=save and save_component_new_graphs=1 , which causes the vulnerable function to be called, as shown in the code snippet below:

switch ( get_request_var ( ‘action’ ) ) { case ‘save’ : form_save ( ) ; break ; case ‘query_reload’ : … … … function form_save ( ) { … … … if ( isset_request_var ( ‘

save_component_new_graphs
WORK_OF_ART

‘ ) ) { host_new_graphs_save ( get_filter_request_var ( ‘host_id’ ) ) ; header ( ‘Location: graphs_new.php?host_id=’ . get_filter_request_var ( ‘host_id’ ) . & header = false ‘ ) ; } }

To target the vulnerable unserialize function, an authenticated user sends a POST request that includes a URL encoded serialized PHP object in the selected_graphs_array variable, as follows:

If we put an invalid object (e.g. one that is malformed or includes a class Cacti does not know about) as the value for the selected_graphs_array variable, we can see Cacti attempting to unserialize the payload in the logs:

At this point, we can control code flow to call unserialize on a user-controlled, serialized object in graphs_new.php .

Attempting Exploitation

PHP Magic Methods

Exploiting a PHP deserialization vulnerability requires access to Objects that have “ magic methods ” implemented. Magic methods are called on objects automatically as they are created, destroyed, and in other situations. Examples of these methods include __construct , __unserialize , __destruct , __wake , and others. We need access to objects that use these functions because some of them will be automatically called when our payload is unserialized into an Object. In this context, a “gadget” is an object with

one
CARDINAL

of these methods implemented that we can use in a payload. By using nested objects in payloads, we combine these gadgets together into a “gadget chain” to perform a desired action such as reading a file, writing a file, or gaining code execution.

Searching for Gadget Chains

Over time, many gadget chains have been discovered in popular libraries. The

PHPGCC
ORG

tool has a list of known gadget chains that it can use to create payloads for insecure deserialization vulnerabilities. There is one known usable gadget chain in

Cacti
PRODUCT

’s

PHP
ORG

vendors, PHPSecLib. However, Cacti does not require or include any of the necessary gadgets that are needed (TripleDES,

AES
ORG

, and SSH1) in order to successfully use the PHPSecLib gadget chain in a payload.

In addition to making use of existing gadget chains, it’s possible to create new ones if the project has objects with usable magic methods. For example, you can look at cacti’s __construct method implementations by viewing the source code to see if some of those are usable. After looking through the implemented magic methods in Cacti’s PHP objects, none were found to be usable in a new gadget chain.

This leaves the vulnerability not exploitable, because of the inability to find a usable gadget chain.

Nuclei Template for

CVE-2023-30534
ORG

In order to facilitate quick testing for the vulnerability, as well as to aid remediation efforts, we created a nuclei template that tests for

CVE-2023-30534
ORG

. This template requires authentication and submits an invalid PHP object in order to generate a log message that shows unserialize being called on the object. The template then verifies the unserialize call was reached by checking for the error message in the logs, ensuring the unserialize function was called on our payload. The template being run locally is shown below:

Cacti administrators can remediate the vulnerability by upgrading to version 1.2.5 or later (e.g.,

1.3.0
CARDINAL

). This vulnerability cannot be exploited in a standard

Cacti
PRODUCT

installation, but users should follow the advice provided by Cacti in the security advisory for further details on remediation.

Note: Cacti version

1.2.25
CARDINAL

(and

1.3.0
CARDINAL

) fixes

an additional 17
CARDINAL

vulnerabilities in Cacti, including critical and high-severity vulnerabilities, so administrators should upgrade as soon as possible.