PHP Object Injection Vulnerability in Backup & Restore Dropbox
Last Friday we had a pair of requests on one of our websites for a file from the plugin Backup & Restore Dropbox, /wp-content/plugins/dropbox-backup/template/css/tool-bar.css. Seeing as we never have had that plugin installed, that request would be likely a hacker probing for usage of the plugin. We quickly found an issue with the plugin’s handling of functions made available through WordPress’ AJAX functionality and notified the developer of the plugin of that issue and that that it looked like hackers were targeting the plugin.
We haven’t heard back from them, but in the meantime we had what look to be probing for usage of one of their other plugins, Stats Counter. In looking over that we quickly found a PHP object injection vulnerability and realized that the same issue was probably what hacker was targeting in this plugin. The vulnerability in this plugin involves substantially similar code, but lets go through it anyway.
In the file /dropbox-backup.php the function wpadm_full_backup_dropbox_run() gets registered to run during init (so it runs whenever WordPress loads):
18 | add_action('init', 'wpadm_full_backup_dropbox_run'); |
That function then causes the function wpadm_run() to run:
25 26 27 28 | function wpadm_full_backup_dropbox_run() { wpadm_run('dropbox-backup', dirname(__FILE__)); } |
When that function runs, if there is a POST input “dropbox-backup_request” included with the request to the website it will pass it to the function wpadm_unpack() (in the file /functions/wpadm.php):
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | function wpadm_run($pl, $dir) { require_once DRBBACKUP_BASE_DIR . '/modules/class-wpadm-method-class.php'; $request_name = $pl . '_request'; if( isset( $_POST[$request_name] ) ** ! empty ( $_POST[$request_name] ) ) { require_once DRBBACKUP_BASE_DIR . '/modules/class-wpadm-core.php'; WPAdm_Core::$cron = false; $user_ip = wpadm_getIp(); if ($_SERVER['SERVER_ADDR'] != $user_ip && $_SERVER['HTTP_USER_AGENT'] != 'dropbox-backup user-agent') { WPAdm_Running::init_params_default(false); } $params = wpadm_unpack($_POST[$request_name]); if ( isset($params['type']) ) { wpadm_class::$type = $params['type']; } $wpadm = new WPAdm_Core($params, $pl, $dir); echo '' . wpadm_pack($wpadm->;getResult()->;toArray()) . ''; exit; } } |
That in turns causes the POST input “dropbox-backup_request” to be run through the function unserialize,which allows the possibility of PHP object injection to occur:
36 37 38 | function wpadm_unpack( $str ) { return unserialize( base64_decode( $str ) ); } |
Proof of Concept
The following proof of concept will cause the specified object to be injected.
Make sure to replace “[path to WordPress]” with the location of WordPress and “[Object to be Injected]” with the object to be injected (must be base64 encoded).
<html> <body> <form action="http://[path to WordPress]" method="POST"> <input type="hidden" name="dropbox-backup_request" value="[Object to be Injected]" /> <input type="submit" value="Submit" /> </form> </body> </html>
Timeline
- December 19, 2016 – Contacted plugin’s developer about authenticated information disclosure vulnerability.
- December 15, 2016 – Notified wordpress.org Plugin Directory of vulnerability.
- December 15, 2016 – Added vulnerability to free data in the service’s companion plugin.
- December 15, 2016 – Plugin removed from Plugin Directory.
- December 16, 2016 – Version 1.4.8, which fixes vulnerability, submitted to Plugin Directory repository.