The Wordfence Threat Intelligence Team discovered two vulnerabilities in MapPress Maps for WordPress, a WordPress plugin with over 80,000 installations. One vulnerability that allowed stored Cross-Site Scripting (XSS) was present in both the free and pro versions of the plugin, while a far more critical vulnerability that allowed Remote Code Execution (RCE) was present in the pro version.
A patched version of both MapPress Free and MapPress Pro were released within hours. We strongly recommend updating both the free and pro versions to the latest version, 2.54.2, as soon as possible.
Description: Authenticated Map Creation/Deletion Leading to Stored Cross-Site Scripting (XSS)
Affected Plugin: MapPress Maps for WordPress
Plugin Slug: mappress-google-maps-for-wordpress
Affected Versions: <=2.53.8 Free and Pro
CVE ID: CVE-2020-12077
CVSS Score: 6.5(Medium)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:L
Fully Patched Version: 2.53.9
Affected Plugin: MapPress Maps for WordPress
Plugin Slug: mappress-google-maps-for-wordpress
Affected Versions: <=2.53.8 Free and Pro
CVE ID: CVE-2020-12077
CVSS Score: 6.5(Medium)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:L
Fully Patched Version: 2.53.9
MapPress Maps for WordPress allows site owners to add custom maps on their site, using both the Google Maps API and the open-source Leaflet engine. Both the free and pro versions of this plugin registered AJAX actions that called functions lacking capability checks and nonce checks. The affected AJAX hooks:
54
| add_action( 'wp_ajax_mapp_delete' , array ( __CLASS__ , 'ajax_delete' )); |
57
| add_action( 'wp_ajax_mapp_save' , array ( __CLASS__ , 'ajax_save' )); |
As such, it was possible for a logged-in attacker with minimal permissions, such as a subscriber, to add a map containing malicious JavaScript to an arbitrary post or page by sending a
$_POST
request to wp-admin/admin-ajax.php
with the action
parameter set to mapp_save
, the postid
parameter set to the post to add the map to, and the map
parameter containing JSON data representing the map to be added. Malicious JavaScript could be added to the title
and body
parameters of a “Point of Interest” in the saved map, which would be executed whenever a visitor to the site clicked on the mapping pin denoting that Point of Interest (POI). Alternatively, if the global setting for “Show a list of POIs with each map” was enabled, the JavaScript would be executed immediately upon visiting a page with an impacted map.
This vulnerability could redirect a site visitor to a malicious site, or even use an administrator’s session to take over the site by adding a malicious administrative user.
The vulnerable function:
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
| static function ajax_save() { ob_start(); $mapdata = (isset( $_POST [ 'map' ])) ? json_decode( stripslashes ( $_POST [ 'map' ]), true) : null; $postid = (isset( $_POST [ 'postid' ])) ? $_POST [ 'postid' ] : null; if (! $mapdata ) Mappress::ajax_response( 'Internal error, your data has not been saved!' ); $map = new Mappress_Map( $mapdata ); $mapid = $map ->save( $postid ); if ( $mapid === false) Mappress::ajax_response( 'Internal error, your data has not been saved!' ); do_action( 'mappress_map_save' , $mapid ); // Use for your own developments // Return saved mapid Mappress::ajax_response( 'OK' , array ( 'mapid' => $mapid )); } |
Alternatively, an attacker could delete an existing map by sending a
$_POST
request to wp-admin/admin-ajax.php
with the action
parameter set to mapp_delete
and the mapid
parameter of the map to delete. While this would be significantly less impactful, it could still be used by an attacker to remove any of the original maps on the site, potentially prompting an administrator to investigate and trigger a script inserted into a malicious map.
The vulnerable function:
276
277
278
279
280
281
282
283
284
285
286
287
| static function ajax_delete() { ob_start(); $mapid = (isset( $_POST [ 'mapid' ])) ? $_POST [ 'mapid' ] : null; $result = Mappress_Map:: delete ( $mapid ); if (! $result ) Mappress::ajax_response( "Internal error when deleting map ID '$mapid'!" ); do_action( 'mappress_map_delete' , $mapid ); // Use for your own developments Mappress::ajax_response( 'OK' , array ( 'mapid' => $mapid )); } |
Description: Authenticated File Upload, Deletion, and Disclosure Leading to RCE or Site Reset
Affected Plugin: MapPress Maps for WordPress
Plugin Slug: mappress-google-maps-for-wordpress
Affected Versions: <=2.53.8 Pro
CVE ID: CVE-2020-12077
CVSS Score: 9.9(Critical)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
Fully Patched Version: 2.53.9
Affected Plugin: MapPress Maps for WordPress
Plugin Slug: mappress-google-maps-for-wordpress
Affected Versions: <=2.53.8 Pro
CVE ID: CVE-2020-12077
CVSS Score: 9.9(Critical)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
Fully Patched Version: 2.53.9
The pro version of the MapPress plugin offers the ability to create templates controlling how maps are displayed. It saves these templates as custom .php files. Unfortunately, the plugin registered several AJAX actions that called functions without capability checks or nonce checks:
19
20
21
| add_action( 'wp_ajax_mapp_tpl_get' , array ( __CLASS__ , 'ajax_get' )); add_action( 'wp_ajax_mapp_tpl_save' , array ( __CLASS__ , 'ajax_save' )); add_action( 'wp_ajax_mapp_tpl_delete' , array ( __CLASS__ , 'ajax_delete' )); |
Note that while the names of some of these functions are identical to functions in the previous vulnerability, they are located in another file and belong to a different class. The file containing this vulnerable code was present in both the free and pro versions of the MapPress plugin, but was only active in the pro version.
As such, it was possible for an authenticated attacker with minimal permissions to upload an executable PHP file such as a backdoor or webshell. This could easily lead to complete site takeover, as an attacker with backdoor access could then modify any file on the site, upload additional files, or connect to the database and insert an administrative user.
An attacker could exploit this vulnerability by sending a
$_POST
request to wp-admin/admin-ajax.php
with the action
parameter set to mapp_tpl_save
, the name
parameter set to the base name of the file they wanted to create, and the content
parameter set to executable PHP code. This file would then be created and could be executed from the directory of the currently active theme, resulting in Remote Code Execution.
The vulnerable function:
70
71
72
73
74
75
76
77
78
79
80
81
| static function ajax_save() { $name = (isset( $_POST [ 'name' ])) ? $_POST [ 'name' ] : null; $content = (isset( $_POST [ 'content' ])) ? stripslashes ( $_POST [ 'content' ]) : null; $filepath = get_stylesheet_directory() . '/' . $name . '.php' ; $result = @ file_put_contents ( $filepath , $content ); if ( $result === false) Mappress::ajax_response( 'Unable to save' ); // Return filepath after save Mappress::ajax_response( 'OK' , $filepath ); } |
An authenticated attacker could also delete any existing PHP file on the site by sending a
$_POST
request to wp-admin/admin-ajax.php
with the action
parameter set to mapp_tpl_delete
, and the name
parameter set to the basename of the file to delete.
For example, to delete
wp-config.php
a directory traversal attack could be used, with the name
parameter set to ../../../wp-config
. This would cause the site to be reset, at which point an attacker could gain control of the site by setting it up from scratch and connecting it to a remotely hosted malicious database.
The vulnerable function:
35
36
37
38
39
40
41
42
43
44
| static function ajax_delete() { $name = (isset( $_POST [ 'name' ])) ? $_POST [ 'name' ] : null; $filepath = get_stylesheet_directory() . '/' . $name . '.php' ; $result = @unlink( $filepath ); if ( $result === false) Mappress::ajax_response( 'Unable to delete' ); Mappress::ajax_response( 'OK' ); } |
Finally, an authenticated attacker could view the contents of any existing PHP file on the site by sending a
$_GET
request to wp-admin/admin-ajax.php
with the action
parameter set to mapp_tpl_get
, and the name
parameter of the file to disclose. For example, to view the contents of wp-config.php
, an attacker could set the name
parameter to ../../../../wp-config
. This could allow an attacker to determine the site’s database credentials. If the site’s database allowed remote access, the attacker could then use this to add an administrative user or make any other desired changes to the database, up to and including deleting nearly all of the site’s content.
The vulnerable function:
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| static function ajax_get() { $name = (isset( $_GET [ 'name' ])) ? $_GET [ 'name' ] : null; $filename = $name . '.php' ; $filepath = get_stylesheet_directory() . '/' . $filename ; $html = @ file_get_contents ( $filepath ); $standard = @ file_get_contents (Mappress:: $basedir . "/templates/$filename" ); if (! $standard ) Mappress::ajax_response( 'Invalid template' ); $template = new Mappress_Template( array ( 'name' => $name , 'content' => ( $html ) ? $html : $standard , 'path' => $filepath , 'standard' => $standard , 'exists' => ( $html ) ? true : false )); Mappress::ajax_response( 'OK' , $template ); } |
Conclusion
In today’s post, we detailed two vulnerabilities in the MapPress Maps for WordPress plugin, including a stored Cross-Site Scripting (XSS) and a more critical Remote Code Execution (RCE), File Disclosure, and File deletion vulnerability. These vulnerabilities have been fully patched in version 2.53.9 and we strongly recommend that all users of this plugin upgrade to the latest version available immediately.
Special thanks to Chris Richardson, the developer of the MapPress Maps for WordPress plugin, for his extremely rapid and professional handling of our disclosure. Patching a vulnerability on the same day the vulnerability disclosure is received by the developer is an exemplary response.
Comments
Post a Comment