Authenticated Persistent Cross-Site (XSS) Vulnerability in InPost Gallery
One of the ways we keep track of vulnerabilities in WordPress plugins to provide our customers with the best data is by monitoring our websites for apparent activity by hackers. We recently had a request for a file from the plugin InPost Gallery, /wp-content/plugins/inpost-gallery/js/front.js. We don’t have that plugin installed on the website, so the request would likely be from someone probing for usage of the plugin. In looking over the plugin for something that hackers might target, we found a couple of vulnerabilities and some additional security issues. We are not sure if either of the vulnerabilities we found are are what the hacker was looking for, or if there is still some other issue lurking in the plugin.
The lesser of the two vulnerabilities was an authenticated persistent cross-site scripting (XSS) vulnerability.
The plugin registers the function save_settings() to be accessible to anyone logged in through WordPress’ AJAX functionality (through the file /index.php):
91 | add_action('wp_ajax_inpost_gallery_save_settings', array(__CLASS__, 'save_settings')); |
The settings page is only accessible to users who have the “edit_pages” capability (which would normally be Editor and Administrator level users). The save_settings() function therefore should be restricted in the same way, but it wasn’t as of version 2.1.2:
155 156 157 158 159 160 161 | public static function save_settings() { $data = array(); parse_str($_REQUEST['values'], $data); update_option('inpost_gallery_settings', $data); exit; } |
There also wasn’t any nonce check needed to prevent cross-site request forgery (CSRF), which also could have much the same impact as a capabilities check since the nonce shouldn’t be accessible to lower level users. You can also see that there is no sanitization done there.
When the value is echoed through the file /views/admin/settings.php to be shown on the settings page the values are not escaped. For example, the value for input “admin_thumb_width” is echoed out on line 28:
<b><?php _e("Post metabox thumbnails size", 'inpost-gallery') ?></b>: <input class="inpost_gallery_image_size_field" type="text" value="<?php echo $admin_thumb_width ?>" name="admin_thumb_width" /> x <input class="inpost_gallery_image_size_field" type="text" value="<?php echo $admin_thumb_height ?>" name="admin_thumb_height" /> px<br />
After we notified the developer of the issue, version 2.1.2.1 was released, which adds a capabilities check to the save_settings() function (no protection against CSRF has been added yet):
556 557 558 559 560 561 562 563 564 565 566 | public static function save_settings() { if (current_user_can('manage_options')) { $data = array(); parse_str($_REQUEST['values'], $data); update_option('inpost_gallery_settings', $data); } exit; } |
Proof of Concept
The following proof of concept will cause an alert box with any accessible cookies to be shown on the page /wp-admin/options-general.php?page=inpost-gallery-settings, when logged in to WordPress.
Make sure to replace “[path to WordPress]” with the location of WordPress
http://[path to WordPress]/wp-admin/admin-ajax.php?action=inpost_gallery_save_settings&values=admin_thumb_width="><script>alert(document.cookie);</script>
Timeline
- 10/16/2016 – Developer notified.
- 10/18/2016- Version 2.1.2.1 released, which fixes issue.