Enviar #986584: yogeshojha reNgine <=v2.2.0 Command Injectioninformación

Títuloyogeshojha reNgine <=v2.2.0 Command Injection
DescripciónSummary An authenticated command injection vulnerability in ReNgine allows any user with the PenetrationTester role (or higher) to achieve remote code execution (RCE) as root. The POST /api/listTargets/ endpoint creates a Domain record via DomainSerializer without the validate_domain check that the canonical AddTarget endpoint applies, so a target name containing shell metacharacters can be written to the database. When a scan is run against that target, subdomain_discovery interpolates the malicious name (as host) into external-tool commands executed with shell=True, resulting in arbitrary command execution. CVSS 3.1: 8.8 (High). Details Root cause (all paths under the repo): web/api/urls.py:8-10 - DefaultRouter() registers ListTargetsDatatableViewSet. web/api/views.py:527 - ListTargetsDatatableViewSet(viewsets.ModelViewSet) with no http_method_names restriction and no permission_classes -> POST /api/listTargets/ reaches the default create. web/api/serializers.py:73 - DomainSerializer is a ModelSerializer(fields='all') with no validate_name / no validate_domain. web/targetApp/models.py:149 - Domain.name = CharField(...) with no model validator. Contrast: web/api/views.py:942 - AddTarget.post calls validators.domain(domain_name) and requires PERM_MODIFY_TARGETS. The same protection is missing on the DataTables viewset. web/reNgine/tasks.py:414 - host = self.subdomain.name if self.subdomain else self.domain.name. web/reNgine/tasks.py:445-540 - host is f-string-interpolated into 9 commands (amass/subfinder/sublist3r/oneforall/ctfr/tlsx/netlas/chaos/custom) and run via run_command(cmd, shell=True). web/reNgine/common_func.py:931-937 - get_nmap_cmd calls is_valid_nmap_command(cmd) before cmd += f" {host}", so host is never checked. This is distinct from CVE-2025-24962 (which only added is_valid_nmap_command() for the nmap_cmd parameter) and CVE-2023-50094 (WAF detector url injection). It also shows CVE-2025-24962's fix is incomplete: host is appended to the nmap command after is_valid_nmap_command() runs, so it bypasses the denylist. PoC Verified end-to-end in a docker-compose deployment of ReNgine master (2026-07-13): Log in as a user with the PenetrationTester role (has PERM_MODIFY_TARGETS and PERM_INITATE_SCANS_SUBSCANS). Obtain the session cookie. Create a target whose name contains shell metacharacters via the unvalidated endpoint: curl -b cookies.txt -X POST http://rengine/api/listTargets/ -H "Content-Type: application/json" -d '{"name":"evil.com;id>/tmp/pwned","project":1}' DomainSerializer accepts it (no validate_domain); a Domain row is created with the malicious name. (The endpoint returns HTTP 500 due to DomainSerializer depth=2 response serialization, but the Domain record IS persisted to the database.) Start a scan against that target with an engine that runs subdomain_discovery (default engines do; subfinder/tlsx/etc. are enabled by default). During the scan, subdomain_discovery builds e.g. subfinder -d evil.com;id>/tmp/pwned -o /tmp/sub.txt and executes it with shell=True. The shell splits on ; and runs id>/tmp/pwned. Arbitrary code execution achieved as root. Actual verification results: HTTP POST /api/listTargets/ with {"name":"evil.com;id > /tmp/pwned","project":2} returned HTTP 500, but the Domain record was persisted to the DB (id=1) with the malicious name intact. The canonical AddTarget endpoint rejected the same payload: {"status":false,"message":"Invalid domain or IP"}. initiate_scan (celery) was triggered for the malicious target. Celery logs show subdomain_discovery executed with host = evil.com;id > /tmp/pwned, interpolating it into tool commands: tlsx -san -cn -silent -ro -host evil.com;id > /tmp/pwned python3 /usr/src/github/OneForAll/oneforall.py --target evil.com;id > /tmp/pwned run netlas search -d domain -i domain domain:"*.evil.com;id > /tmp/pwned" -f json The shell split on ; and executed id > /tmp/pwned; /tmp/pwned was created in the celery container -- confirming RCE via the full scan-triggered flow. Additionally, run_command(f'subfinder -d {host} -o /tmp/sub.txt', shell=True) with payload x;echo PWNED_BY_RENGINE_RCE > /tmp/rce_proof; # resulted in /tmp/rce_proof containing PWNED_BY_RENGINE_RCE. Impact This is an authenticated OS Command Injection (CWE-78) leading to Remote Code Execution. Any user with the PenetrationTester role (a standard role in ReNgine's multi-user role system) can obtain root remote code execution on the ReNgine server. ReNgine is designed as a multi-user team reconnaissance platform (with SysAdmin/PenetrationTester/Auditor roles and project isolation), commonly deployed as a shared instance. The vulnerability allows a low-privilege user to escalate to root, leading to full compromise: theft of all scan data, stored third-party API keys (subfinder/nuclei/chaos/etc.), other tenants' projects, and use of the server as a pivot point into the internal network (ReNgine servers typically have internal network access for scanning).
Fuente⚠️ https://github.com/yogeshojha/rengine/issues/1561
Usuario
 Lim2frEe (UID 100470)
Sumisión2026-09-17 15:27 (hace 18 días)
Moderación2026-10-05 17:26 (18 days later)
EstadoAceptado
Entrada de VulDB413623 [yogeshojha reNgine hasta 2.2.0 listTargets Endpoint web/reNgine/tasks.py subdomain_discovery name escalada de privilegios]
Puntos20

Are you interested in using VulDB?

Download the whitepaper to learn more about our service!