From: disclosure via Fulldisclosure <fulldisclosure () seclists org>
Date: Tue, 20 Oct 2026 02:30:46 +0000
0day Rubbish Research Team is publicly disclosing a vulnerability in Exasol
Database 7.1.30, the in-memory MPP analytical database from Exasol AG
(Germany), examined in its docker-db single-container deployment form. The SQL
engine is a proprietary C implementation named EXASolution, the server process
is exacts, clients speak a proprietary binary SQL protocol on port 8563 rather
than HTTP, TLS terminates on that port with a self-signed certificate carrying
no subjectAltName, and the vendor's console client exaplus ships inside the
image. Three further services share the container: ConfD, an HTTPS JSON-RPC
management daemon on 443; BucketFS, an HTTP file service observed on 2580; and
an OpenSSH server on 22. The image as pulled is about 6 GB and is distributed
through Docker Hub.
One fact about this deployment form belongs at the top rather than at the
bottom, because it explains why the research is public now instead of being
held for a patch. Exasol's own upstream repository warns that the docker
distribution is an open source project that is not officially supported by
Exasol; that the base image is an end-of-life CentOS 7 release; that official
support for docker-db 7 is no longer available and that users should move to a
newer release line; that the repository now only contains documentation while
the binaries are distributed through Docker Hub; that issues are disabled; and
that the project is mainly intended for automatic testing of Exasol
deployments. None of that reduces the mechanism, because the credential is a
property of the shipping database and the script engine is a supported core
feature of the product rather than a container add-on. It does mean that on
the vendor's own statements no fix is planned for this deployment form, so
there was no patch to coordinate around and holding the finding would have
left operators exposed without warning. Only version 7.1.30 in this deployment
form was executed. Other 7.1.x releases, the supported non-container
installation and the vendor's newer release line share the mechanism, a
constant SYS credential plus an unrestricted script language in the UDF
engine, and are plausibly affected; none was tested, that is stated as an
explicitly labelled inference, and no version range is claimed.
Type and root cause. Two defects, separable but jointly decisive, classified
as CWE-1392 use of default credentials (primary) and CWE-94 improper control
of generation of code (co-equal), with CWE-798 hard-coded credentials, CWE-78
OS command injection, CWE-1188 insecure default initialization and CWE-250
execution with unnecessary privileges recorded alongside, and CWE-284 and
CWE-862 reported separately for the absent source-address restriction on 8563
and the absent authorisation distinction for script creation. Neither
separately reported item raises a metric. Leg one on its own is a data breach.
Leg two on its own is a documented feature. The pair produces an entry point
that required no provisioning decision by anyone, because nobody ever created
the account an attacker uses, and that converts SQL-layer administrative
access into operating-system command execution with the command output
returned in-band through the ordinary result set.
The credential is the vendor's own published text, not a leak and not an
inference. The upstream docker-db README publishes it under the heading
"Connecting to the Database", instructing the reader to authenticate with
username sys and password exasol. Two image-internal CI test scripts use the
same pair against a freshly initialised database on the same port:
basic_test.sh:112 carries $X -c n11:8563 -u sys -P exasol -jdbcparam
validateservercertificate=0 and basic_sc_test.sh:98 uses -u sys -P exasol as
well. Those two files are not in the current upstream repository, which now
carries documentation only, so they are cited as artifacts observed inside the
7.1.30 image at /usr/opt/EXASuite-7/EXAClusterOS-7.1.30/docker/test/ and not
as repository contents. Nothing rotates the constant, and that was traced
rather than assumed: the running controller process command line carries no
-defaultSysPasswordHash argument; the [DB:DB1] stanza of EXAConf carries no
DefaultSysPasswdHash key; db_jobs.py:104 sets self.sys_passwd_text =
secrets.token_hex(20), which generates an additional random password rather
than replacing the built-in one; database.py:57 passes -defaultSysPasswordHash
only when EXAConf configures it explicitly; and the container's init-sc path
does not configure it. Nothing in the container's start path presents a
first-login change-password step, sets a must-change flag on the SYS account
or refuses service while the constant remains in place, and the README carries
guidance about persistent volumes, hugepages, resource limits and license
mounting with no instruction to change the SYS password; that absence is as
load-bearing as the presence of the constant. The conclusion, corrected once
during the research before being accepted, is that the accepted value is a
built-in default of the database engine rather than a hash handed to it by the
container initialiser, and both the built-in value and the generated random
are accepted, which is why random generation in the provisioning code is not a
defence. The contrast the product supplies is what makes this a defect rather
than a design choice: Exasol generated per-deployment randoms for two of its
three service credentials, the ConfD AuthenticationToken and the BucketFS
WritePasswd, and did not do so for the most privileged one, and an attacker
must read EXAConf to recover either random while sys / exasol is a constant
every installation shares and the documentation prints.
The sink, in full:
CREATE SCHEMA IF NOT EXISTS poc_schema;
OPEN SCHEMA poc_schema;
CREATE OR REPLACE PYTHON3 SCALAR SCRIPT poc_udf()
RETURNS VARCHAR(2000000) AS
import os
def run(ctx):
out = os.popen("id").read()
return 'RCE_OUT:' + out
/
SELECT poc_udf();
Three properties make this a sink rather than a curiosity. The os module is
importable with no declaration, allow-list or capability request. The command
string is an ordinary Python literal built from what the caller supplied, so
shell metacharacters, pipelines and quoting all work, and the measured round
used cat /etc/passwd | head -3 whose pipeline was honoured by the shell
os.popen starts. And the return value crosses the trust boundary back to the
caller through the ordinary result set, which removes the need for any
separate exfiltration channel. Sanitisation over what the body does is absent:
no module allow-list or deny-list, no policy forbidding os or subprocess, no
capability gate, no per-statement approval, no audit prompt and no privilege
beyond SYS itself. What does exist is well-formedness checking rather than a
security control: the engine validates the language alias, submitting PYTHON
instead of PYTHON3 yields its own diagnostic "no definition found for
language: PYTHON", and it enforces SQL syntax and the forward-slash script
terminator. Both were satisfied by the payload without evasion. That alias
diagnostic is worth more than it looks, because it shows script languages are
resolved through a named alias table inside the engine, that the table carries
the standard aliases PYTHON3, LUA, JAVA and R, and that EXAConf contains no
[ScriptLanguages] stanza customising it, so reachability is not conditional on
an operator having installed or enabled a language pack.
Execution identity, reported exactly as id returned it and not rounded up:
uid=500(exadefusr) gid=500(exausers) groups=500(exausers),0(root). This is a
dedicated script-execution account, not the database's own service identity,
and it is not uid=0. Root appears only as a supplementary group, no escalation
to an effective root identity was attempted, observed or is claimed, and
nothing in this research should be described as a root compromise. The
vendor's README does state that privileged container mode is required for
permissions management, UDF support and environment configuration, so the
privileged posture is the documented one rather than an unusual one, and gid 0
on Linux governs access to files and devices whose group is root. The whole of
what the evidence supports is a conditional sentence: if an attacker in that
position could write a setuid binary or reach a device node exposed by
privileged mode, an effective root identity would follow. Neither was tested.
What was tested is that the group membership is present, and it is reported as
an untested escalation position under CWE-250 rather than as an achieved
outcome.
The isolation boundary was not glossed either. The UDF engine runs in a
separate kernel namespace and that isolation is real but partial. A file
written by the UDF did not appear in the container's own filesystem view, so
the two views are distinct mount namespaces. Yet uname from inside the UDF
returned the host kernel release, 5.10.134-19.2.al8.x86_64, which is expected,
a namespace not being a hypervisor and the kernel being shared. Consequently
the account names in the id output come from the namespace's own view, so even
the /etc/passwd read is not asserted to have been the container's file or the
host's. Command execution inside that namespace is confirmed and non-blind and
is a substantial capability on its own; a host or container escape is not
confirmed, not attempted and not claimed, and no cross-namespace file
primitive is asserted. This is why the impact ratings rest on the SQL-layer
authority of SYS, which does not depend on any of it.
Network position, and a claim that was withdrawn. A socket inventory taken
inside the running container reported exacts on 8563, bucketfsd on 2580, confd
on 443 and sshd on 22, each bound to all interfaces within the container's
network namespace. A listener bound to all interfaces inside a container is
not the same thing as a listener reachable from a network, and no
source-address restriction of the product's own was observed in its
configuration or listener behaviour at any point. The vendor's README
documents two ways to run the image and they differ exactly on the question
that matters. The stand-alone command is docker run --name exasoldb -p
127.0.0.1:9563:8563 --detach --privileged --stop-timeout 120
exasol/docker-db:<version>, and the page explains that port 8563 within the
container is exposed on local port 9563 and that the reader should use that
port to connect, so the published port is bound to the host loopback; the
persistent-volume variant on the same page uses the same loopback-bound
publication. The multi-node command is docker run --detach --network=host
--privileged -v "$CONTAINER_EXA:/exa" exasol/docker-db:<version> init-sc
--node-id 11, and the vendor's note says the example uses the host network
stack, that there is no need to expose ports in this mode, and that they are
all accessible on the host. The image's FAQ adds that if you want to check
from outside the Docker network you need port forwarding, which confirms that
host-side reachability is an explicit operator action. Under default bridge
networking with no port publication, which several of the README's own example
commands use including the license-mount and resource-limit examples, the port
is reachable from the host and from every other container attached to the same
bridge, which is a logically adjacent topology.
The research notes originally asserted that the production docker deployment
exposes 8563 on all interfaces by default, and the chain was scored as
remotely reachable on that basis. That assertion rested on the state of the
researchers' own test harness and on a general expectation about how databases
are deployed, not on any product artifact, and it does not survive contact
with the vendor's documentation. It is therefore withdrawn in that form in the
published advisory and replaced by the narrower artifact-backed set of
statements above, and the headline Attack Vector is Adjacent rather than
Network. Withdrawing it lowered the published score from 9.8 to 8.8. That
direction is worth stating plainly: the correction was made against the
researchers' own interest, and a reader who disagrees about the deployment
posture ends up with the larger figure rather than the smaller one.
Scoring. One score is published, 8.8 High,
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. The arithmetic is shown so any
reader can reproduce it with the CVSS 3.1 base algorithm and its
round-up-to-the-tenth rule: ISS = 1 - ((1-0.56) x (1-0.56) x (1-0.56)) = 1 -
0.44^3 = 0.914816; Impact at Scope Unchanged = 6.42 x 0.914816 = 5.873119;
Exploitability = 8.22 x 0.62 x 0.77 x 0.85 x 0.85 = 2.835255; Base = 8.708373
rounded up to the nearest tenth, which is 8.8. Adjacent is the reading the
vendor's artifacts support for the deployment form that was actually executed.
AC:L because the constant is published, the certificate fingerprint is
obtainable by an unauthenticated handshake, the PYTHON3 alias is registered by
default, and there is no race, no window and no operator action to wait for;
all three rounds succeeded on their first attempt.
Two further reachability readings are published as labelled conditionals, each
with its own complete vector and arithmetic, and neither is the headline.
Conditional reading A, where 8563 is reachable from another host, is 9.8
Critical on CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H: Exploitability =
8.22 x 0.85 x 0.77 x 0.85 x 0.85 = 3.887043, Base = 9.760161 rounded up. It
applies to the documented multi-host --network=host form, to any operator
publication of the port without a loopback restriction, to a deployment
reachable across a management network or NAT, and to the supported
non-container installation whose entire purpose is to answer client
connections on 8563. It is the reading most operators of a real warehouse are
in, and it is labelled conditional precisely because the deployment form
executed in this research published loopback-only and the cross-host leg was
argued from vendor artifacts rather than detonated between two machines.
Conditional reading B, loopback-only publication exactly as the stand-alone
quickstart documents, is 8.4 High on
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H: Exploitability = 8.22 x 0.55 x
0.77 x 0.85 x 0.85 = 2.515145, Base = 8.388264 rounded up. It applies where
the only publication is the documented loopback one and the attacker therefore
needs local access to the host, which is a realistic position for anything
else already running there, a sibling container included. The published score
is 8.8 and never 9.8; a reader whose deployment publishes loopback-only should
read the 8.4.
Privileges Required was argued rather than inherited, and both rejected
readings are published with their arithmetic so that a reader who disagrees
can see what the difference costs. An attacker does type a password, so a
naive reading says PR:L. The published reading is PR:N because CVSS 3.1
defines it as the attacker being unauthorized prior to attack and not
requiring any access to settings or files of the vulnerable system to carry it
out, and both halves hold: no account was ever provisioned to the attacker and
no trust decision admitted them, and the attacker needs to read nothing from
the target, not EXAConf and not a startup log, to obtain the value. A
credential every installation shares and whose own documentation prints it is
not a privilege the defender granted; it is the absence of a credential
requirement wearing one's shape. Rejected PR:L is 8.0 High on
CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, Exploitability = 8.22 x 0.62 x
0.77 x 0.62 x 0.85 = 2.068068, Base = 7.941187 rounded up; it charges the
attacker for a privilege nobody granted, and it is also the honest reachable
reading for an instance where the factory credential has been rotated but a
provisioned non-administrative account still holds script-creation rights.
Rejected PR:H is 6.8 Medium on CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H,
Exploitability = 8.22 x 0.62 x 0.77 x 0.27 x 0.85 = 0.900610, Base = 6.773729
rounded up, reading the metric as the authority level the successful attack
needs because SYS is the database's most privileged account; it is rejected
more strongly than PR:L, since it would rate a constant requiring no grant as
though it were a personal administrator account, and the same metric under a
Network vector computes to 7.2 Medium. Scope Changed was considered on the
strength of the separate namespace, the root supplementary group and the
documented privileged mode, and is rejected at 9.7 High on
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H, impact term = 7.52 x (0.914816 -
0.029) - 3.25 x (0.914816 x 0.9731 - 0.02)^13 = 6.128026, Base = 1.08 x
(6.128026 + 2.835255) = 9.680344 rounded up; the same reading under a Network
vector, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H, is capped by the formula
at 10.0 Critical. It is rejected as the headline because the namespace
boundary measured as a boundary in one direction and not the other, a file
written inside it not appearing outside, and because no cross-boundary effect
was demonstrated, so charging Scope Changed on an untested escalation position
would be exactly the inflation the section exists to avoid. The SQL service,
its script engine and the database it administers are one product on one host,
and executing a script is what the engine is built to do.
One state an operator can enter deliberately deserves its own sentence. With
the factory credential rotated, this finding does not arise for an
unauthenticated attacker at all: if the SYS password has been changed and no
other account holds script-creation privilege, there is no path from the
network to the sink and the script engine is then simply a documented feature
used by authorised administrators. Rotation moves the finding from 8.8 to not
applicable, which is why it heads the operator recommendations.
Authentication. Nothing in this research claims that authentication is missing
or that the protocol can be bypassed. A negative control ran before the
constant was accepted: five incorrect passwords, admin, password, EXASOL,
exasol123 and 123456, were tried against the same transport and the same
client invocation, and all five returned [28000] authentication failed.
Without that control, "the constant worked" would be consistent with a broken
or disabled authentication check; with it, the acceptance is specific to the
shipped value. Every step of the chain was performed while authenticated as
SYS with that value. Three of the container's four authentication surfaces
were characterised and ruled out as doors: ConfD on 443 requires a Bearer
token that is the per-deployment AuthenticationToken from EXAConf; BucketFS on
2580 returned 403 to a write attempt because the bucket WritePasswd is
likewise a per-deployment random and 400 to a path traversal attempt; and
OpenSSH on 22 performs ordinary host authentication with nothing
product-specific observed. The distinction is what makes this a
credential-hygiene defect rather than an authentication-bypass defect.
Impact. Two layers, and the first does not depend on the sink at all. Through
the SQL channel as SYS: the complete warehouse, every schema, table and view
including whatever an analytical platform holds, which is typically the
organisation's consolidated business data; the ability to write and drop any
of it; the user and privilege catalogue, so further accounts can be created
with chosen privileges, giving an attacker a durable and legitimate-looking
second entry point that survives rotation of the factory credential; and the
ability to stop the database. That layer alone justifies High on all three
impact metrics independently of anything the sandboxing question decides.
Through the sink: operating-system command execution as uid=500(exadefusr)
with root present as a supplementary group, inside the script engine's
namespace, with stdout returned through the ordinary SELECT result set.
Because the return path is in-band, no DNS, HTTP or ICMP exfiltration channel
is needed, so egress filtering on the host does not defeat it. Availability
follows the same authority, and the deployment runs privileged as the vendor's
README requires, which widens what resource consumption inside the container
can reach beyond it; that widening was not tested and is not scored. The chain
is also idempotent in a way that matters for defence: the payload uses CREATE
OR REPLACE, so re-running the attack rewrites one script object rather than
creating one artifact per command, and there is no accumulation for a
volume-based alert to catch.
Detection is weak by construction, because every step is legitimate documented
product usage: a TLS handshake, a SYS login, script creation and a SELECT. A
SYS session from an unexpected address is indistinguishable from a real
administrator, and an operator who never rotated the constant has no means of
telling them apart. The durable artifact is the schema and the script object
the attacker created; it survives the session and is enumerable with ordinary
SQL. Audit trails recording script-object creation with the creating user and
source address are therefore the highest-value signal available, and their
absence from the default deployment is part of the problem. The second-best
signal is a trial sequence of [28000] authentication failed responses against
the sys user on 8563, since no rate limit and no lockout were observed on SQL
authentication; that same absence is what made the six-password control
practical to run at all.
A separate smaller finding, published alongside and deliberately not folded
into any metric or into the score above: the BucketFS default bucket is
Public=True, which yielded unauthenticated read listing of that bucket. A
write attempt returned 403 and a path traversal attempt returned 400. It is
real, it is much smaller than the chain above, it has its own root cause, it
does not reach execution, and no score is published for it.
What was measured, and what was only read. Measured live, with the returned
values reproduced in the advisory: authentication with the shipped constant;
rejection of wrong passwords; creation of a PYTHON3 scalar UDF by SYS;
execution of os.popen inside it; return of the command's stdout through the
SELECT result set; the executing identity; visibility of the host kernel
release from inside the UDF; and readability of /etc/passwd from the UDF
process. Three independent detonations succeeded, each an independent
create-and-select cycle with a different command, each returning real system
data, each succeeding on its first attempt. There was no fourth round and no
round was repeated merely to demonstrate determinism, three successes with
three different commands being evidence of repeatability on their own. Nothing
was driven from a separate network host. All three rounds ran the vendor's own
console client inside the container against the container's loopback on 8563,
and the host-side publication was loopback-restricted. The cross-host legs of
the chain, that a client on another machine can complete the same TLS
handshake, retrieve the fingerprint, authenticate and submit the same
statements over 8563, follow from the protocol being a network protocol and
from the listener binding all interfaces inside the container, and they are
argued from the vendor artifacts quoted above; they were not demonstrated
between two machines, and the advisory says so wherever the reachability
metric is derived. Not verified and not claimed: escalation to uid=0; any
write or execution crossing from the UDF namespace into the container's or the
host's filesystem view; persistence; the effect of the chain on a
non-container installation or on another 7.1.x release; and the sibling sinks
os.system, subprocess and the LUA, JAVA and R aliases, none of which was
detonated. Read from source or documentation rather than detonated: the
absence of -defaultSysPasswordHash on the controller command line, the absence
of DefaultSysPasswdHash in EXAConf, the behaviour of db_jobs.py:104 and
database.py:57, the contents of the image's test scripts, the ConfD token
generation scheme, and every documented deployment command quoted above.
Verification boundary, stated plainly. One container from the vendor's
docker-db image at 7.1.30, pulled onto an isolated cloud sandbox, started with
the privileged flag the vendor's README requires for permissions management,
UDF support and environment configuration, with a host directory mounted at
/exa and the SQL port published to the host loopback only. Researcher-side
commands ran under an ordinary unprivileged account, and nothing in the chain
depended on elevated privileges on the researchers' host. One inconsistency is
disclosed rather than smoothed over: the notes record the host-side port
publication as 8562 in one place and 8563 in another, and because every
measured leg ran through the container loopback that discrepancy is not
load-bearing for anything claimed. It is recorded so that a reader can see the
boundary of the evidence rather than infer it. The container must run
privileged for UDF support according to the vendor's README, which means the
UDF engine is present and enabled in the documented deployment rather than
being an optional add-on an operator might have skipped. Exactly three
commands were executed as the payload, an identity capture, a file read and a
kernel-version read. No file was written outside the UDF namespace test, no
product file was modified or deleted, and the proof of concept's cleanup mode
drops only the schema the run created.
Mitigation summary: rotate the SYS password immediately after initialisation,
the one control that breaks this chain and that moves the finding from 8.8 to
not applicable where no other account holds script-creation privilege, and
treat any deployment still answering the constant as compromised until audited
because the credential is public and its use leaves no distinguishing trace;
on the vendor side, generate a per-deployment random SYS password during
initialisation exactly as the product already does for the ConfD
AuthenticationToken and the BucketFS WritePasswd, reporting it through a
channel that requires local access to read, since db_jobs.py:104 already calls
secrets.token_hex(20) and making that value the only accepted password rather
than an additional one is the smallest change with the largest effect; remove
the built-in acceptance of the constant or require an explicit initialisation
argument with no default; add a forced first-login rotation gate that refuses
to serve SQL until the password has been changed once and logs the refusal,
the pairing that products shipping a documented initial credential usually
have and this deployment form lacks; make the module set available to UDFs an
allow-list that excludes os, subprocess, socket and equivalents with an
explicit per-database or per-session opt-in and a log entry for the opt-in,
treating process creation from the query layer as a privilege that is granted
rather than a library that happens to be importable; stop granting the
script-execution account root group membership unless a specific documented
function requires it, and say in the documentation which function that is;
document the exposure next to the host-networking example, stating that 8563
accepts SQL from the network, that the default credential must be rotated
before that form is used, and that BucketFS's public-read default discloses
bucket contents without authentication; and surface script-object creation in
audit trails with the creating user and source address, since that event is
the only durable artifact this chain leaves behind. A regression test that
would catch the class rather than the instance: initialise a container with no
arguments, then assert from a remote client that the documented constant no
longer authenticates and the response is an authentication failure, that a
connection succeeds only with the value the initialiser reported, that
creating a PYTHON3 script whose body calls os.popen fails with a policy error
naming the restricted module, and that the script-execution account's
supplementary groups read from inside a permitted script do not include gid 0.
Until a supported release line is confirmed fixed, operators should not
publish 8563 without a loopback or named-address restriction, should prefer
the documented loopback publication, should front remote access with a VPN or
a mutually authenticated proxy, should audit every deployment running
--network=host where the vendor's own note says all ports are accessible on
the host, should enumerate and review script objects against a known-good
inventory periodically because CREATE OR REPLACE leaves no accumulation to
alert on, should restrict who can reach SYS at the network layer since no
source-address control of the product's own was observed, should watch
authentication failures on 8563 for trial sequences against sys, and should
treat the out-of-support status of this release line as a reason to plan
migration on its own merits.
The published proof of concept is Python 3 using only the standard library,
with no third-party dependency and no hardcoded target. It refuses a
non-loopback target unless an explicit --allow-remote flag is passed; acquires
the certificate fingerprint with an unauthenticated TLS handshake, printing
only the first and last few hex characters so that a per-deployment value is
not written into a log, with --fingerprint to supply it and --no-encryption
for a deployment that disabled TLS; asserts the credential gate with a trivial
query before doing anything else; and creates and selects the UDF once per
requested command, with --rounds 3 reproducing the verification method by
cycling three different commands. It also offers --control to run the negative
control alone and create nothing, --gate to probe only the credential, and
--cleanup to drop the schema the run created. Two client behaviours had to be
engineered around and both are recorded in the advisory because they are what
made the difference between a hanging tool and a working one: the vendor
client's single-statement mode rejects a multi-statement payload containing
the slash terminator and reports an unfinished command, so the payload is fed
on stdin, and the client does not exit at end of file on stdin, so the tool
starts it with a pipe, waits a bounded interval, kills it and keeps the
partial stdout, by which point the result set has already been printed. An
early transcript parser matched the marker inside the echoed CREATE SCRIPT
source; the fix filters matches followed by a quote, a space or a plus sign,
which is how echoed source differs from a real result. The tool establishes no
listener, opens no reverse shell, writes no file, installs no persistence,
touches no other container or host service, does not attempt to reach uid=0
and does not attempt to cross the UDF namespace boundary. The default command
is id. Those omissions are deliberate: the finding is that command execution
is reachable at all from a documented constant, and demonstrating more would
add risk without adding evidence.
Prior public coverage was checked before publication. A keyword search of the
NVD for the vendor name returned exactly one record, and it concerns a
client-side JDBC driver component rather than the database server; separate
searches for the database product name and for the docker deployment name
returned no records at all. No published advisory was found whose root cause
is either leg of this chain, neither the shipped constant credential nor the
unrestricted script-language sink. The single unrelated record is deliberately
not cited in the advisory and no neighbouring identifier should be inferred as
related.
Full technical analysis and the reproducible proof of concept, published
unconditionally:
https://0day-rubbish.com/blog/exasol-database-default-credential-python-udf-os-popen-rce
Project archive (ongoing disclosure series):
https://github.com/Exploit-Garbage/0day-Rubbish
Exasol AG was notified through the vulnerability-reporting mailbox it
publishes in an RFC 9116 security.txt served at the standard well-known path
on its www host, which is the only intake the vendor offers: the file welcomes
responsible disclosure of vulnerabilities in its products and services, offers
public acknowledgement where it assesses research to be relevant, original and
significant, notes that it gives no financial reward, offers a public key on
request for anyone who prefers to encrypt and declares a preference for
English and German. It publishes no inline key field, so the notification was
sent in clear text, which costs nothing here because the research is already
public. The vendor's separate security and compliance page describes its
information-security programme, including a board-level committee responsible
for information security topics and incident-response plans, and publishes no
reporting address and no intake form of its own. Its legal disclosure page
publishes a general information mailbox and a legal mailbox behind an
obfuscation script, neither of which is a security intake and neither of which
was used, and the impressum, legal-notice, imprint and trust-center paths on
that host returned no page. Nothing was submitted to any pre-publication
intake form and no individual was addressed by name. The vendor states that
this docker deployment form is not officially supported and that official
support for it has ended, so no fix is planned for it; that is a reason the
research was published rather than held rather than a reason to withhold it.
This disclosure is unconditional: the research is already public, no
permission was asked for, no embargo was requested, and nothing is withheld
pending a reply. No vulnerability identifier has been assigned to this finding
yet.
Mitigation offers from the research team are free and carry no condition,
including help reproducing the chain, auditing whether an installation still
answers the constant, and reviewing the UDF module-restriction design
described above.
--
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/
Current thread:
- [0day-rubbish] Exasol Database 7.1.30 docker-db form: shipped default SYS credential to PYTHON3 UDF os.popen command execution as uid=500(exadefusr), output returned in-band (8.8) disclosure via Fulldisclosure (Oct 20)