[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[FD] [0day-rubbish] RCDevs WebADM 2.4.14 authenticated log viewer sid command injection to webadm uid 999 code execution (7.2)



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@xxxxxxxxxxxxxxxx
https://0day-rubbish.com
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/