Authenticated Information Disclosure Vulnerability in Log Emails
Recently we took a quick look over plugins that log emails sent through WordPress. Those emails have the potential to contain sensitive information, so the security of them is important. In two cases we found that the plugin allowed any logged in user to view emails logged by the plugin. In the case of the Log Emails plugin we found that issue went further than the other plugin, as it not only allowed you to view logged emails, but also to view any thing else stored as a post. That includes not only posts, but also pages, and any content that a plugin might store in that way, things like logged emails from this plugin.
The other plugin’s issue was due to making the function that allows viewing logged emails accessible via AJAX and then not checking to insure that the user should be allowed to view it. This plugin issues comes involves a rather obscure action hook admin_action_, which about the only reference we could find to was this StackExchange question. The practical effect is the same as this makes the function available to anyone logged in.
Here is where admin_action_ comes in to play in the file /includes/class.LogEmailsPostTypeLog.php:
38 | add_action('admin_action_log_emails_view', array($this, 'viewLog')); |
You can see that functions that this causes to run, viewLog(), didn’t do any check on who is doing the request or if they are trying to view a post that was created by the plugin in version 1.0.6 of the plugin:
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | public function viewLog() { global $wpdb; $post_id = empty($_GET['post_id']) ? 0 : absint($_GET['post_id']); if (!$post_id) { return; } $post = get_post($post_id); // get next / prev links $sql = " select ID from {$wpdb->posts} where ID < {$post->ID} and post_status='publish' and post_type = '" . self::POST_TYPE . "' order by ID desc limit 1 "; $previous = $wpdb->get_var($sql); $previous = $previous ? $this->getLogViewURL($previous) : false; $sql = " select ID from {$wpdb->posts} where ID > {$post->ID} and post_status='publish' and post_type = '" . self::POST_TYPE . "' order by ID asc limit 1 "; $next = $wpdb->get_var($sql); $next = $next ? $this->getLogViewURL($next) : false; // current page and list links $current = $this->getLogViewURL($post->ID); $list = admin_url('edit.php?post_type=' . self::POST_TYPE); // actions and filters just for this page add_filter('admin_body_class', array($this, 'logViewBodyClass')); add_filter('parent_file', array($this, 'fixLogViewMenuHierarchy')); add_action('admin_enqueue_scripts', array($this, 'adminEnqueueScripts')); // show the view require_once ABSPATH . 'wp-admin/admin-header.php'; require LOG_EMAILS_PLUGIN_ROOT . 'views/log-detail.php'; require ABSPATH . 'wp-admin/admin-footer.php'; } |
After we contacted the developer about the issue they released version 1.1.0, which fixes the vulnerability by adding code to the viewLog() function to make sure that the requested post is a logged email and that the user has the ability to edit this type of post (which is defined in another location as a user who has the “activate_plugins capability) before displaying it:
265 266 267 268 269 270 271 272 273 274 275 276 | $post_type = get_post_type_object($post->post_type); if ($post->post_type !== self::POST_TYPE) { wp_die(__('This post is not an email log.', 'log-emails')); } if (!current_user_can($post_type->cap->edit_posts)) { wp_die(sprintf('<h1>%s</h1><p>%s</p>', __('Cheatin’ uh?', 'log-emails'), __('You are not allowed to view email logs.', 'log-emails')), 403); } |
Proof of Concept
The following proof of concept will display the post at ID 1, when submitted while logged in to WordPress.
Make sure to replace “[path to WordPress]” with the location of WordPress.
http://[path to WordPress]/wp-admin/admin.php?action=log_emails_view&post_id=1
Timeline
- 7/1/2016 – Developer notified.
- 7/2/2016 – Version 1.1.0 released, which fixes vulnerability.
Thanks again for responsible disclosure. I appreciate both that you researched and discovered this vulnerability, and that you gave me a chance to fix it before disclosing it publicly.
cheers,
Ross