最近在sebug上爆出Drupal7.x有PHP代码执行漏洞,但是又没人分析,所以只好自己下了源码搞下。从官网的安全研究员的博客里,了解了下漏洞的成因,感觉这个问题有点标题党了,这个漏洞只是一个重新安装的漏洞,至于PHP代码执行,还停留在幻想阶段。这个过程中得到的一个意外收获是,通过后台安装插件的地方有一个文件包含的问题,可以自己构造任意内容插件进行安装,来获得webshell,勉强算是代码执行吧(先把标题党的帽子甩掉)。
0×01 漏洞简述
Drupal 7.16之前的7.x版本中,出现攻击者可重新安装系统漏洞,利用这个问题攻击者可以修改系统连接的数据库为自己的数据库。Drupal厂商针对这个问题已经发布安全公告,安全公告编号为SA-CORE-2012-003。
Drupal系统安装插件模块,存在文件包含问题,攻击者可以利用这个问题,可以在拥有安装插件权限的用户的情况下,上传自己修改的恶意插件,进行安装执行。
0×02 漏洞分析
1. 重现安装问题
在Drupal 7.16版本之前的7.x版本的安装文件install.php中验证系统是否需要重新安装的逻辑出现问题,导致攻击者可尝试绕过验证进行重新安装。
跟踪install.php执行过程,其大致流程为,导入安装核心文件install.core.inc,并执行其中的install_drupal函数,install_drupal函数关键代码如下:
01 |
function install_drupal($settings = array()) { |
02 |
global $install_state; |
03 |
// Initialize the installation state with the settings that were passed in, |
04 |
// as well as a boolean indicating whether or not this is an interactive |
06 |
$interactive = empty($settings); |
07 |
$install_state = $settings + array('interactive' =>$interactive) + install_state_defaults(); |
09 |
// Begin the page request. This adds information about the current state of |
10 |
// the Drupal installation to the passed-in array. |
11 |
[color=#ff0000] install_begin_request($install_state);[/color] |
12 |
// Based on the installation state, run the remaining tasks for this page |
13 |
// request, and collect any output. |
14 |
$output = install_run_tasks($install_state); |
代码中红色的为判断是否需要安装的语句,其调用了install_begin_request函数,再继续跟踪这个函数,关键代码如下:
01 |
function install_begin_request(&$install_state) { |
03 |
$install_state['settings_verified'] = install_verify_settings(); |
04 |
if ($install_state['settings_verified']) { |
05 |
// Initialize the database system. Note that the connection |
06 |
// won't be initialized until it is actually requested. |
07 |
require_once DRUPAL_ROOT .'/includes/database/database.inc'; |
09 |
// Verify the last completed task in the database, if there is one. |
10 |
[color=#ff0000] $task = install_verify_completed_task();[/color] |
其中红色代码是执行校验的部分,即install_verify_settings()函数在校验中起到了决定性的作用,来看该函数代码:
01 |
function install_verify_settings() { |
04 |
// Verify existing settings (if any). |
05 |
if (!empty($databases) && install_verify_pdo()) { |
06 |
$database = $databases['default']['default']; |
07 |
drupal_static_reset('conf_path'); |
08 |
$settings_file = './' . conf_path(FALSE) .'/settings.php'; |
09 |
[color=#ff0000] $errors = install_database_errors($database, $settings_file);[/color] |
从代码中可以看出,这个函数进行判断只是依据数据库操作是否正常为依据,如果正常则不需重新安装,如果出错就可进行重新安装。
install_verify_settings()函数中红色代码的功能是,执行一系列的数据库操作,来判断数据库是否正常。这系列数据库操作中,它会创建一个名为drupal_install_test的表,并尝试对其进行insert,update,delete等操作。
综上所述,想要绕过验证的话,可以通过install_verify_settings()执行过程中,让数据库操作出错就可以了。Drupal官方安全小组的一个研究人员在博客中提出了一种绕过的方法:使用“CREATE TABLE drupal_install_test (id int NULL);”语句创建一个和测试时所用到的表同名的数据表,这样在进行校验的过程中数据库操作就会失败,从而达到绕过验证的目的。不过,在我进行本地实验的过程中,发现这种方法行不通,虽然可以绕过校验,但是,在提交新的数据库信息时会出现错误提示,如下图所示:
我自己重现这个漏洞,使用的方法是,将原有的数据库删除,然后便可很顺利的重现安装系统。这个方法能成功,而上面我所提到的方法却出现错误,感觉很怪异,不知哪里有问题。
2. 文件包含问题
在\includes\bootstrap.inc文件中的drupal_load函数,会将要执行的模块代码包含进webserver进程,drupal_load代码如下:
01 |
function drupal_load($type, $name) { |
02 |
// Once a file is included this can't be reversed during a request so do not |
03 |
// use drupal_static() here. |
04 |
static $files = array(); |
06 |
if (isset($files[$type][$name])) { |
10 |
$filename = drupal_get_filename($type, $name); |
13 |
include_once DRUPAL_ROOT . '/' . $filename; |
14 |
$files[$type][$name] = TRUE; |
红色代码为问题代码,Drupal应该是将这部分作为一种特性来开发的,但是其模块安装的方式,可以允许用户上传安装内容。这就导致了,用户可以控制模块加载内容,来执行自己的php代码。
我自己重现这个问题使用的方法很简单,只需要从官方网站随便下载一个符合相应版本的module,然后本地解压,修改其中后缀为module的文件内容为自己想要执行的php代码,最后重新打包上传到目标站点进行安装即可。安装完毕后,只要我们访问这个模块便可以执行我们的代码了。
0×03 漏洞重现
1. 重现安装问题
2. 文件包含问题
从官方网站随便下载的一个叫wysiwyg的插件
修改其中module文件内容
将修改过的文件夹重新打包
上传并装到目标站点
成功执行内容
0×04 漏洞总结
1. 重新安装问题需要获得数据库的操作权(不一定是root),方可实现。如获得数据库管理员用户名和密码,且数据库设置为可以对外连接;或者程序某个地方存在注入漏洞。
2. 文件包含问题,需要有后台管理员权限,方可实现。可以结合其他漏洞,例如本篇文章中提到的重新安装问题。
3. 这两个问题的危害性和影响范围比较大,drupal在国内外都是比较流行的cms系统,用户很多,如果出现数据库连接信息泄露或者SQL注入这样的问题,将会 直接导致攻击者可以获得webshell。
4. 在跟踪这两个漏洞的过程中,感觉这套cms比较有趣的地方是,它只有有限的几个php文件,大部分的代码文件都是以inc作为后缀的,在执行的过程中只要将内容包含进php文件执行就可以了。
0×05 防护建议
1. 重现安装问题,Drupal官方已经针对这个问题进行了修补,可以到官网下载最新的7.16版本,下载地址:http://drupal.org/download
2. 文件包含问题,没有太好的解决办法,个人建议,将安装插件这一模块禁用,如果需要安装插件,可以本地的拷贝要安装插件文件夹到安装路径中,也可以实现插件的安装。