盘点2017年的WordPress插件漏洞

译者:WisFree

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

 

前言

统计,全球29%的网站使用的都是WordPress。由于WordPress的使用非常广泛,使得WordPress插件的安全问题成为了网络犯罪分子们关注的焦点。一般来说,第三方提供的插件其安全等级肯定没有WordPress核心插件的安全等级高,因此它们对于攻击者来说,绝对是极具吸引力的攻击目标。为了入侵目标WordPress站点,攻击者需要利用插件中的安全漏洞,那么静态代码分析技术能检测到这些漏洞吗?

在这篇文章中,我们将会对2017年影响最为严重的插件漏洞进行分析。除此之外,我们还会跟大家介绍静态代码分析工具如何才能检测到这些漏洞。

漏洞选取

我们选取公开已知插件漏洞的条件如下:

1. 发布于2017

2. 受影响的插件安装量非常大

3. 漏洞影响严重

4. 不需要认证或对服务器有任何要求(例如WP statistics插件的SQLi漏洞

5. 不会影响非开源的商业插件

RIPS可以对非WordPress核心插件进行代码分析,接下来,我们会对WordPress的相关功能进行分析,并介绍如何对插件进行深入的代码分析。

RIPS针对WordPress的分析报告:【传送门

Loginizer 1.3.5-SQL注入漏洞(CVE-2017-12650

目前,总共有55WordPress站点安装了Loginizer插件。这款插件的作用理应是通过屏蔽暴力破解攻击、启用双因素身份验证、以及reCAPTCHA验证码机制来给WordPress的登录功能增加安全性。但是在今年八月份,研究人员在Loginizer的登录程序中发现了一个SQL注入漏洞,而这个漏洞反而会让原本需要得到保护的管理员凭证处于安全风险之中。

接下来,我们一起看一看包含漏洞的代码,并且跟大家解释静态代码分析工具(以下简称SAST工具)如果想要检测到这类漏洞的话,需要什么样的要求。在接下来的分析过程中,我们给大家提供的只是简单的代码段,而实际的分析会更加复杂。

第一步:识别自定义的SQL封装器

首先,SAST工具最基本的就是要识别出该插件中用户自定义的函数lz_selectquery(),这个函数可以利用WordPress的数据库驱动器来执行SQL语句。当这个函数被调用的时候,它需要对第一个参数进行SQL注入检测。

modules/Emails/DetailView.php

function lz_selectquery($query, $array = 0){

global $wpdb;

$result = $wpdb->get_results($query, 'ARRAY_A');

}

第二步:识别输入来源

对于SAST工具而言,另一种基本功能就是它必须能够识别出PHP中所有常见的和不常见的用户输入来源。但攻击者可以修改用户自定义函数lz_getip()所返回的HTTP请求头,因此该函数所返回的值就是不可信的了,所以整个数据流必须进行精准跟踪。

modules/Emails/DetailView.php

function lz_getip() {

global $loginizer;

if(isset($_SERVER["REMOTE_ADDR"])) {

$ip = $_SERVER["REMOTE_ADDR"];

}

if(isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {

$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];

}

return $ip;

}

第三步:分析WordPressactionfilter

WordPress允许我们定义各种不同的action来调用自定义函数,为了跟踪插件的控制流程,SAST工具必须要了解这些回调的运行机制。在下面给出的代码段中,我们可以看到loginizer_load_plugin()函数是通过action调用的,这个函数可以从lz_getip()函数中获取用户输入,并将其存储再全局数组$loginizer之中,然后再通过WordPress filter来调用另一个自定义函数loginizer_wp_authenticate()。因此,除了WordPress action之外,SAST工具还需要了解WordPress filter的工作机制。

modules/Emails/DetailView.php

function loginizer_load_plugin() {

global $loginizer;

$loginizer['current_ip'] = lz_getip();

add_filter('authenticate', 'loginizer_wp_authenticate', 10001, 3);

}

add_action('plugins_loaded', 'loginizer_load_plugin');

第四步:分析全局变量

虽然下面这段代码对于我们人类来说可以轻易看懂,但是对于SAST工具来说分析起来可就非常复杂了。它需要通过多个函数调用来分析全局数组$loginizer的数据流,只有这样它才能够检测到lz_getip()函数传递给loginizer_can_login()函数(为对SQL语句中的拼接内容进行数据过滤)的用户输入信息。其中的SQL语句是通过自定义的SQL函数lz_selectquery()实现的,虽然WordPress可以通过模拟magic_quotes来防止注入,但是来自HTTP头中的恶意用户输入数据并不会受此影响。

modules/Emails/DetailView.php

function loginizer_wp_authenticate($user, $username, $password) {

global $loginizer, $lz_error, $lz_cannot_login, $lz_user_pass;

if(loginizer_can_login()) {

return $user;

}

}

function loginizer_can_login() {

global $wpdb, $loginizer, $lz_error;

$result = lz_selectquery("SELECT * FROM ".$wpdb->prefix."loginizer_logs

WHERE ip = '".$loginizer['current_ip']."';");

}

由于RIPS的分析算法主要针对的是PHP语言,因此它对WordPress的分析会比较到位,因此它能够识别出WordPress复杂的数据流,并成功检测出插件中的SQL注入漏洞。

RIPS针对wp_loginizer_1.3.5的分析报告:【传送门

Ultimate Form Builder Lite 1.3.6-SQL注入漏洞(CVE-2017-15919

Ultimate Form Builder插件目前的安装量已经超过了5万,它允许我们使用拖拽的形式来创建联系表单。在今年十月份,研究人员在该插件中发现并报告了一个严重的SQL注入漏洞,而该漏洞将允许攻击者接管目标WordPress网站。

接下来,我们会分析代码中存在的问题,以及SAST工具如何才能检测到这个安全漏洞。

第一步:识别上下文环境

首先,插件要执行的所有SQL语句都需要被分析,虽然WordPress数据库驱动跟插件代码无关,但它所使用的方法(例如get_rwo())是可以被RIPS引擎识别的(搜索潜在的SQL注入漏洞)。

modules/Emails/DetailView.php

class UFBL_Model {

public static function get_form_detail( $form_id ) {

global $wpdb;

$table = UFBL_FORM_TABLE;

$form_row = $wpdb->get_row("SELECT * FROM $table WHERE form_id = $form_id");

return $form_row;

}

}

在这里,引擎可以分析SQL语句以识别注入环境。一般来说,这种地方的安全漏洞是很难被发现的。如果它读取的是form_id=’$form_id’而不是form_id=$form_id,那么这条语句就没有安全问题了,因为WordPress可以对用户的输入进行甄别。因此,只有那些上下文环境敏感的SAST工具才能够感知到这种隐蔽的安全问题。

第二步:跟踪用户输入数据流

这一步相对来说比较简答,你可以从在下面的代码中看到,如果工具无法分析到$form_id的潜在隐患,那么受污染的数据将有可能扩散到其他功能函数中。

modules/Emails/DetailView.php

class UFBL_Lib {

public static function do_form_process() {

$form_data = array();

foreach ( $_POST['form_data'] as $val ) {

if ( strpos( $val['name'], '[]' ) !== false ) {

$form_data_name = str_replace( '[]', '', $val['name'] );

if ( !isset( $form_data[$form_data_name] ) ) {

$form_data[$form_data_name] = array();

}

$form_data[$form_data_name][] = $val['value'];

} else {

$form_data[$val['name']] = $val['value'];

}

}

$form_id = sanitize_text_field( $form_data['form_id'] );

$form_row = UFBL_Model::get_form_detail( $form_id );

}

}

其中的$_POST[‘form_data’]被分配给了另一个数组,并使用了WordPress的内部过滤函数sanitize_text_field()来进行数据过滤。但是就我们现在所检测到的这个SQL上下文环境来说,这个过滤函数并不能防止SQL注入的发生。为了检测这种漏洞并防止假阳性,SAST工具需要跟踪复杂的数据流,它们不仅要能够识别WordPress的内部函数,而且还要能评估这些函数在不同环境下的影响。

RIPS针对wp_formbuilder_1.3.6的分析报告:【传送门

Zen Mobile App Native 3.0-文件上传漏洞(2017-02-27

研究数据表明,Zen Mobile App Native插件已经成为了近期最容易受到攻击的插件之一,而且这个漏洞也是2017年攻击者最喜欢利用的三大漏洞之一。下面代码中的漏洞还会影响很多其他的插件,例如Mobile App Builder 1.05

/zen-mobile-app-native/server/images.php

if (!$_FILES['file']['error']) {

$name = md5(rand(100, 200));

$ext = explode('.', $_FILES['file']['name']);

$filename = $name . '.' . $ext1;

$destination = 'images/' . $filename;

$location = $_FILES["file"]["tmp_name"];

move_uploaded_file($location, $destination);

echo $plugin_url.'/server/images/' . $filename;

}

受影响的代码行数很少,因此SAST工具可以轻松发现这个安全问题。代码会利用move_uploaded_file()函数来上传文件,RIPS对其中的两个用户输入参数进行了分析。虽然文件名会使用随机哈希代替,但是文件扩展名仍然是攻击者可以控制的。因此,攻击者就可以通过上传一个PHP shell文件(扩展名为.php)并在目标Web服务器中实现任意代码执行。

RIPS针对wp_zenmobile_3.0的分析报告:【传送门

Appointments 2.2.1-PHP对象注入漏洞(2017-10-02

最后这个例子是非常容易发现的,很多工具可以直接通过签名来发现其中的异常。不久之前,研究人员在Appointments插件中发现了一个PHP对象注入漏洞,而且很多其他的插件也存在这种漏洞,例如Flickr GalleryRegistrationMagic Custom Registration Forms。这里的问题并不复杂,因为这里只有一行代码:

/flickr-gallery.php

$pager = unserialize(stripslashes($_POST['pager']));

更重要的是,这一行代码就能给我们的应用程序带来严重的影响。

总结

在这篇文章中,我们给大家简单分析了2017年比较严重的四个WordPress插件漏洞,并且介绍了静态代码检测工具如何才能检测到这些安全漏洞。由于目前市场上大约有4万多款WordPress插件,再加上WordPress插件数量一直在稳步增长,因此在2018年我们很可能会看到更多包含安全漏洞的插件出现。

(完)