False Vulnerability Report: WP Job Manager Arbitrary File Upload Vulnerability
As part of our cataloging the vulnerabilities in WordPress plugins for our service we come across false reports of vulnerabilities from time to time. So that others don’t spend their time looking over these as well, we post our findings on them.
Sometimes false reports of vulnerabilities are fairly easy to identify as likely being false without having to dig in to things, when the supposed proof of the vulnerability doesn’t match with what you should see with exploitation of a vulnerability. That was the case with a recent claim of an arbitrary file upload vulnerability in the WP Job Manager plugin. While an arbitrary file upload vulnerability allows any type of file to be uploaded, hence the name, hackers would normally use it to upload .php files. In this case those examples involved uploading .txt files. Also missing from the advisory was any information on the underlying code handling uploads, which if shown would have shown that the report was false.
The vulnerability was supposed to exist in the ability to upload a logo when creating a job posting through the plugin. If you try to upload a .php file through that you will get back error message that says:
Invalid file type. Accepted types: jpg|jpeg|gif|png
This is due to the JavaScript code that restricts the type of files that can be uploaded to the ones listing defined in the data-file_types attribute of the input (the JavaScript code that causes this is located in the file /assets/js/ajax-file-upload.min.js):
<input type="file" class="input-text wp-job-manager-file-upload" data-file_types="jpg|jpeg|gif|png" name="company_logo" id="company_logo" placeholder="" />
So you are only intended to be able to upload jpg, jpeg, gif, or png files through that. Since the checking is done in JavaScript, which runs on the client side, an attacker could just disable that code, so it doesn’t provide actual protection.
With that code disabled, uploading a .php file will cause the following message to be returned instead:
Uploaded files need to be one of the following file types: jpg|jpeg|jpe, gif, png, bmp, tiff|tif, ico, asf|asx, wmv, wmx, wm, avi, divx, flv, mov|qt, mpeg|mpg|mpe, mp4|m4v, ogv, webm, mkv, 3gp|3gpp, 3g2|3gp2, txt|asc|c|cc|h|srt, csv, tsv, ics, rtx, css, htm|html, vtt, dfxp, mp3|m4a|m4b, ra|ram, wav, ogg|oga, mid|midi, wma, wax, mka, rtf, js, pdf, class, tar, zip, gz|gzip, rar, 7z, psd, xcf, doc, pot|pps|ppt, wri, xla|xls|xlt|xlw, mdb, mpp, docx, docm, dotx, dotm, xlsx, xlsm, xlsb, xltx, xltm, xlam, pptx, pptm, ppsx, ppsm, potx, potm, ppam, sldx, sldm, onetoc|onetoc2|onetmp|onepkg, oxps, xps, odt, odp, ods, odg, odc, odb, odf, wp|wpd, key, numbers, pages
That message comes from the job_manager_upload_file() function in the file /wp-job-manager-functions.php. The message is due to a check to see if the file that is submitted for upload has an allowed mime type:
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 | function job_manager_upload_file( $file, $args = array() ) { global $job_manager_upload, $job_manager_uploading_file; include_once( ABSPATH . 'wp-admin/includes/file.php' ); include_once( ABSPATH . 'wp-admin/includes/media.php' ); $args = wp_parse_args( $args, array( 'file_key' => '', 'file_label' => '', 'allowed_mime_types' => get_allowed_mime_types() ) ); $job_manager_upload = true; $job_manager_uploading_file = $args['file_key']; $uploaded_file = new stdClass(); if ( ! in_array( $file['type'], $args['allowed_mime_types'] ) ) { if ( $args['file_label'] ) { return new WP_Error( 'upload', sprintf( __( '"%s" (filetype %s) needs to be one of the following file types: %s', 'wp-job-manager' ), $args['file_label'], $file['type'], implode( ', ', array_keys( $args['allowed_mime_types'] ) ) ) ); } else { return new WP_Error( 'upload', sprintf( __( 'Uploaded files need to be one of the following file types: %s', 'wp-job-manager' ), implode( ', ', array_keys( $args['allowed_mime_types'] ) ) ) ); |
The allowed mime types come from the WordPress function get_allowed_mime_types(), which is located in the file /wp-include/functions.php. That in turn gathers a list of mime types from the function wp_get_mime_type() in the same file, which is where the list of file types show in the message that starts “Uploaded files need to be one of the following file types:” comes from.
Since the types of files that can be upload is limited the arbitrary file upload vulnerability does not exist. That still leaves the issue that someone can upload a lot more types of files than are actually intended for the logo, so depending on what else is intended to uploadable through plugin, the developer may want to place additional restrictions in the PHP portion of the code on what can be uploaded.