UpdraftPlus 1.22.3 中修复的严重漏洞

在对 UpdraftPlus 插件进行内部审核期间,我们发现了一个任意备份下载漏洞,该漏洞可能允许订阅者等低权限用户下载站点的最新备份

如果被利用,该漏洞可能允许攻击者访问受影响站点数据库中的特权信息(例如,用户名和散列密码)。

我们向插件作者报告了这个漏洞,他们最近发布了 1.22.3 版本来解决这个问题。由于此问题的严重性,还推送了强制自动更新。如果您的站点尚未安装,我们强烈建议您更新到最新版本 (1.22.3) 并在您的站点上安装成熟的安全解决方案,例如 Jetpack Security。

您可以在此处找到 UpdraftPlus 自己的建议

细节

插件名称:UpdraftPlus
插件 URI:https://wordpress.org/plugins/updraftplus/
作者:https://updraftplus.com/

漏洞

任意备份下载

受影响的版本:1.16.7 和 1.22.3(免费版)之间的每个版本,以及
CVE-ID:CVE-2022-0633
WPVDB ID:d257c28f-3c7e-422b-a5c2-e618ed3c0bf3
CVSSv3.1:8.5
CWSS:87.6

该插件使用自定义“随机数”和时间戳来安全地识别备份。鉴于上述 nonce 和时间戳的知识可以让某人访问相当多的插件功能,确保这些信息只对那些合法需要它的人开放是至关重要的。

不幸的是,正如我们将展示的那样,事实并非如此。

随机数泄漏

第一个罪魁祸首是 UpdraftPlus_Admin::process_status_in_heartbeat 方法。

/**
 * Receive Heartbeat data and respond.
 *
 * Processes data received via a Heartbeat request, and returns additional data to pass back to the front end.
 *
 * @param array $response - Heartbeat response data to pass back to front end.
 * @param array $data     - Data received from the front end (unslashed).
 */
public function process_status_in_heartbeat($response, $data) {
    if (!is_array($response) || empty($data['updraftplus'])) return $response;
    try {
        $response['updraftplus'] = $this->get_activejobs_list(UpdraftPlus_Manipulation_Functions::wp_unslash($data['updraftplus']));
    } catch (Exception $e) {
        $log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during get active job list. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
        error_log($log_message);
        $response['updraftplus'] = array(
            'fatal_error' => true,
            'fatal_error_message' => $log_message
        );
    // @codingStandardsIgnoreLine
    } catch (Error $e) {
        $log_message = 'PHP Fatal error ('.get_class($e).') has occurred during get active job list. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
        error_log($log_message);
        $response['updraftplus'] = array(
            'fatal_error' => true,
            'fatal_error_message' => $log_message
        );
    }
 
    if (UpdraftPlus_Options::user_can_manage() && isset($data['updraftplus']['updraft_credentialtest_nonce'])) {
        if (!wp_verify_nonce($data['updraftplus']['updraft_credentialtest_nonce'], 'updraftplus-credentialtest-nonce')) {
            $response['updraftplus']['updraft_credentialtest_nonce'] = wp_create_nonce('updraftplus-credentialtest-nonce');
        }
    }
 
    $response['updraftplus']['time_now'] = get_date_from_gmt(gmdate('Y-m-d H:i:s'), 'D, F j, Y H:i');
 
    return $response;
}

它没有正确确保发送此心跳请求的用户是管理员(例如,通过诸如 current_user_can 之类的函数),这是一个问题,因为该函数尝试做的第一件事是通过 get_activejobs_list 方法获取活动备份作业的列表。

备份下载

有几种方法可以在 UpdraftPlus 上下载备份,其中大部分都得到了适当的保护。

    /**
     * Find out if the current request is a backup download request, and proceed with the download if it is
     */
    public function maybe_download_backup_from_email() {
        global $pagenow;
        if ((!defined('DOING_AJAX') || !DOING_AJAX) && UpdraftPlus_Options::admin_page() === $pagenow && isset($_REQUEST['page']) && 'updraftplus' === $_REQUEST['page'] && isset($_REQUEST['action']) && 'updraft_download_backup' === $_REQUEST['action']) {
            $findexes = empty($_REQUEST['findex']) ? array(0) : $_REQUEST['findex'];
            $timestamp = empty($_REQUEST['timestamp']) ? '' : $_REQUEST['timestamp'];
            $nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
            $type = empty($_REQUEST['type']) ? '' : $_REQUEST['type'];
            if (empty($timestamp) || empty($nonce) || empty($type)) wp_die(__('The download link is broken, you may have clicked the link from untrusted source', 'updraftplus'), '', array('back_link' => true));
            $backup_history = UpdraftPlus_Backup_History::get_history();
            if (!isset($backup_history[$timestamp]['nonce']) || $backup_history[$timestamp]['nonce'] !== $nonce) wp_die(__("The download link is broken or the backup file is no longer available", 'updraftplus'), '', array('back_link' => true));
            $this->do_updraft_download_backup($findexes, $type, $timestamp, 2, false, '');
            exit; // we don't need anything else but an exit
        }
    }
}

因此,攻击者可以针对此心跳回调制作恶意请求,以访问有关该站点迄今为止的最新备份的信息,其中包括备份的随机数。

不幸的是,与 admin_init 挂钩的 UpdraftPlus_Admin::maybe_download_backup_from_email 方法也没有直接验证用户的角色。

虽然它确实间接应用了一些检查,例如检查 $pagenow 全局变量,但过去的研究表明该变量可以包含任意用户输入。 不良行为者可以根据他们从上述心跳漏洞中泄露的信息,使用此端点下载文件和数据库备份。

时间线

2022-02-14 – 与 UpdraftPlus 的初次接触
2022-02-15 – 我们向他们发送有关此漏洞的详细信息
2022-02-16 – UpdraftPlus 1.22.3 发布,强制自动更新启动

结论

我们建议您检查您的站点使用的是哪个版本的 UpdraftPlus 插件,如果在受影响的范围内,请尽快更新!

在 Jetpack,我们努力确保您的网站免受此类漏洞的影响。 我们建议您为您的站点制定一个安全计划,其中包括恶意文件扫描和备份。 Jetpack Security 是一种出色的 WordPress 安全选项,可确保您的网站和访问者的安全。

学分

原始研究员:马克·蒙帕斯

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注