Posted by disclosure via Fulldisclosure on Oct 060day Rubbish Research Team is publicly disclosing a vulnerability in RCDevs WebADM
2.4.14, Freeware Edition, the closed-source IAM/MFA management platform from RCDevs
Security SA (Luxembourg) that fronts the vendor's OpenOTP, SpanKey and TiQR
authentication products.
Type: OS command injection (CWE-78, with CWE-20 and CWE-116 contributing, and
CWE-732/CWE-276 and CWE-250 added for two auxiliary conditions). The administrator
console log...
Full Disclosure
mailing list archives
0day Rubbish Research Team is publicly disclosing a vulnerability in RCDevs WebADM 2.4.14, Freeware Edition, the closed-source IAM/MFA management platform from RCDevs Security SA (Luxembourg) that fronts the vendor's OpenOTP, SpanKey and TiQR authentication products. Type: OS command injection (CWE-78, with CWE-20 and CWE-116 contributing, and CWE-732/CWE-276 and CWE-250 added for two auxiliary conditions). The administrator console log viewer admin/logfile_viewer.php interpolates the sid GET parameter, percent-decoded once and with no escaping of any kind, into the single-quoted shell command grep -E '<sid>' <logfile> | tail -n 10000 which the page hands to PHP's popen(). A single apostrophe closes the quoted grep pattern, everything after it is parsed by /bin/sh as command text, and the trailing quote pair re-opens an empty quoted string that swallows the remainder of the pipeline. There is no escapeshellarg, no escapeshellcmd, no quote stripping, no charset allow-list and no length cap on the recorded path; the absence of a filter, not the bypass of one, is the root cause. Commands execute as the webadm service account, uid=999(webadm) gid=999(webadm) groups=999(webadm), the identity the webadm-httpd workers run under with no privilege drop configured. Root was not achieved, is not claimed, and no privilege escalation was attempted. The endpoint does not echo command output into its HTTP response, so confirmation is out-of-band: the injected command appends a line to /opt/webadm/logs/webadm.log and the same endpoint reads that file back over HTTPS when asked for a different log selector. This also means the finding is self-verifying rather than interpretive. The published advisory reproduces the identity string but deliberately not the per-run marker token or the container hostname from the run, since both are artefacts of one execution on one host. Scoring. One score is published: 7.2 High, CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H. That vector computes to 7.107826 raw and is taken to 7.2 by the CVSS ceiling-to-tenth Roundup, which is why a calculator reporting 7.1 is not in disagreement with anything but with the specification's rounding rule. Our research record carried a higher base score beside this same PR:H vector, and that pairing cannot compute; the higher figure is the base score of the PR:L variant, which asserts that an authenticated principal below administrator reaches the sink. This research did not support that assertion: the session is issued by an LDAP bind as the administrator DN, the no-cookie negative control never reached popen(), and no lower-privileged console role was documented. The advisory therefore publishes 7.2 alone and leaves PR:L as an open question about the product's role model, to be amended if an auditor- or help-desk-class role can open this viewer in a shipped or supported configuration. Scope Changed was considered and rejected: under S:C the same vector would compute to 9.1, but the injected command runs as the same identity, on the same host, with the same backend access the vulnerable application already holds, so no authorization boundary is crossed. No unauthenticated reading is published. License registration was required to bring the console up, the record documents no vendor-shipped default administrator credential, and this research did not establish whether one exists, so no PR:N figure is claimed on evidence the record does not carry. Authentication: post-authentication console administrator. Eleven endpoints reachable without a console session were examined in full, plus two independent adversarial passes tasked specifically with breaking the "a session is required" conclusion. That sweep found no shell sink and no file-write sink reachable from unauthenticated input; every include hit was a static framework bootstrap; the certificate signing daemon on port 5000 carries no shell strings; and the mail() transport keeps recipients off the command line, removing the notification path as an injection route. The advisory publishes that disposition table so the negative result is auditable. Unauthenticated remote code execution was not reached and none is claimed. Impact: arbitrary OS command execution as the webadm application account on the host that runs an identity platform, which is why the qualitative weight exceeds what the number alone conveys. From uid 999 an attacker can read and rewrite platform configuration under /opt/webadm, including the httpd and PHP configuration defining routing, authentication domains and backend connectivity - a persistence path that survives a service restart without touching the operating system; reach the directory backend on the local LDAP listener and the application database on the local MariaDB listener with the credentials the application itself carries, which for an MFA platform means user records, OTP state and second-factor enrolments, so modification can disable, redirect or re-enrol a user's second factor; interact with the certificate signing daemon from inside the trust boundary where its network-level protections no longer apply; write to product logs, supporting both anti-forensics and the observation channel this exploit uses; and disrupt availability of the console and of the authentication path it fronts, locking out users of every relying application. Everything gained sits inside the authorization domain the application already occupies, hence Scope Unchanged, but the content of that domain is the identity infrastructure of whatever WebADM was deployed to protect. Verification boundary, stated plainly. All dynamic work was performed against a Docker container running WebADM 2.4.14 Freeware Edition, reached over TLS on the container's HTTPS listener by a pure-standard-library Python client, driven from the container host, and recorded across four independent runs that each used their own marker and all returned the same uid 999 identity. The container's published ports were mapped to loopback addresses and no request crossed a network boundary, so remote reachability is argued from the product's own binding configuration for an admin console vhost that exists to be reached over a network, not measured from a separate host. The application ships as a Blowfish-encrypted opcache file_cache corpus that only the vendor's custom webadm-runphp interpreter (PHP 8.2.30, ZTS) decodes at load time, so there is no plaintext PHP on disk: the decoder was located in that interpreter by following cross-references to the container magic, the parser and the decryption were reimplemented offline, and 315 files were recovered. That recovery yields the literal string layer, not vendor source text, so the sink construction in the advisory is labelled as a reconstruction from decoded string literals plus observed behaviour, confirmed by the executed result. Exactly one command shape was executed and only that shape is claimed - a single echo carrying three command substitutions and a redirection into the product log - because the target shell rejected top-level parentheses and statement separators inside the injected text; a nested sh -c wrapper, a pipeline, an && -joined chain and any write into the document root were never exercised. Privilege escalation, persistence and lateral movement to the LDAP or MariaDB backends were reasoned about from the identity and the listener layout, not executed. Only WebADM 2.4.14 Freeware Edition was tested; other versions and licensed editions with additional web service modules installed are unclaimed. Two detection notes worth carrying into any rule. Every /admin/*.php request returns HTTP 200 together with the WebADM doctype even with no session cookie, because the framework renders the common HTML shell before the page logic runs the session check, so status code, response length and doctype are unusable as authorization signals and will produce false positives if used that way. Detect on shell metacharacters in sid, above all the apostrophe, and on unstructured lines appearing in /opt/webadm/logs/webadm.log; process ancestry alone is weak, because a webadm-httpd child running grep and tail for the viewer is normal behaviour. Mitigation summary: escapeshellarg() on sid at the sink (escapeshellcmd is not an acceptable substitute, since it does not move a value out of the quoting context it was placed in); remove the shell entirely with proc_open() over an argument vector or filter the file in PHP with a bounded tail counter, which also covers the second interpolation site, the file operand derived from the log selector; validate sid against the alphanumeric shape the product's own random_id() generates and return 400 on mismatch; resolve the log selector through a fixed server-side enumeration; set an explicit minimal User= and Group= for the httpd workers and stop the service account from appending to any log the viewer displays back; set disable_functions in php.ini, which the recorded configuration does not; and add a regression test that fails on a metacharacter. Until a patch exists operators should bind the admin vhost to a management interface, VPN or mutually authenticated proxy, treat console administrator credentials as tier-zero secrets behind a second factor, alert on the indicators above, and on suspicion of exploitation rotate the administrator, LDAP and database credentials and audit second-factor enrolments for the interval in question. Full technical analysis and a reproducible proof-of-concept: https://0day-rubbish.com/blog/rcdevs-webadm-logfile-viewer-sid-command-injection Project archive (ongoing disclosure series): https://github.com/Exploit-Garbage/0day-Rubbish RCDevs Security SA has been notified through the general corporate contact mailbox it publishes for enquiries, support and problem submissions; the vendor publishes no RFC 9116 security.txt and we found no product security page, vulnerability-disclosure policy or researcher intake form, so there was no pre-publication channel for us to use and this disclosure is unconditional. No vulnerability identifier has been assigned to this finding yet. -- 0day Rubbish Research Team disclosure () 0day-rubbish com https://0day-rubbish.com _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/