This is a seatbelt that looks latched until someone opens the door from the outside
BACKRONYM is a client-side cleartext-downgrade flaw in legacy MySQL connection handling. In affected builds, telling the client to use SSL/TLS did not reliably mean encryption was required; a man-in-the-middle could interfere with the handshake and push the session back to plaintext. The plugin tracks Oracle MySQL client library versions 5.1.x, 5.5.x, 5.6.x, and 5.7.x before 5.7.3; the underlying CVE also covers MySQL Connector/C before 6.1.3 and MariaDB before 5.5.44 / 10.0.20.
The vendor MEDIUM label is technically fair in a vacuum, but too high operationally for enterprise patch triage because exploitation requires an attacker to already be on-path between app and database or to control/poison DNS. That makes this a post-compromise or network-positioning issue, not an internet-to-RCE event. The blast radius can still be ugly if your apps talk to databases over shared or hostile networks, but for a 10,000-host patch program this is backlog hygiene, not a front-of-queue emergency.
4 steps from start to impact.
Gain network position with bettercap/ettercap or DNS spoofing
- Attacker has internal network access, L2 adjacency, routing influence, or DNS control
- The application connects to MySQL over TCP rather than a local Unix socket / named pipe
- The network path is not already pinned inside a trusted tunnel with endpoint identity validation
- Modern segmented networks, private service meshes, and VPC controls reduce easy on-path positioning
- Many enterprise apps reach local or same-host databases over sockets rather than routed TCP
- DNS hardening and static service discovery narrow the redirect option
Abuse legacy client behavior during the MySQL handshake
--ssl as effectively advisory. Oracle changed this in MySQL 5.7.3 so that client-side --ssl became prescriptive, and added MYSQL_OPT_SSL_ENFORCE semantics for the C API.- Client library is vulnerable: Oracle MySQL < 5.7.3, Connector/C < 6.1.3, or comparable legacy MariaDB builds
- The application depends on legacy
--sslbehavior rather than explicit enforced TLS mode / identity validation - Connection traverses the attacker-controlled path
- Newer clients fail closed instead of silently falling back
- Backported distro packages may already contain the fix even when package versions look old
- Apps that explicitly verify CA/server identity shut this down
Strip encryption with a custom proxy or published advisory logic
- Client will continue after downgrade instead of failing closed
- Server and app are reachable by the attacker-controlled relay/proxy
- No higher-layer tunnel or mutual-authenticated wrapper protects the session
- Enterprise TLS wrappers, SSH tunnels, or private link overlays can make the MySQL-layer bug irrelevant
- Connection retries, cert requirements, or app-specific error handling may break the attacker workflow
- The attacker must keep the proxy stable enough not to crash production traffic and reveal themselves
Ssl_cipher empty, connection type reported as plain TCP/IP, or packet captures showing unencrypted MySQL commands on paths that should be encrypted.Read or alter SQL traffic in transit
- Useful SQL traffic crosses the compromised path
- Application credentials have meaningful database permissions
- Attacker maintains session continuity without obvious outages
- Least-privilege DB accounts constrain what altered traffic can do
- App-layer integrity checks, signed business workflows, or out-of-band reconciliations can expose tampering
- Database audit trails may reveal odd client/source patterns if the proxy changes connection characteristics
The supporting signals.
| CVE mapping | tenable:83347 maps to CVE-2015-3152. |
|---|---|
| In-the-wild status | No current KEV listing was found in the CISA Known Exploited Vulnerabilities catalog page reviewed, and I found no primary-source reporting of active campaigns abusing this exact CVE. |
| Proof-of-concept availability | Public exploit/advisory material exists. NVD links the original Duo write-up ecosystem and tags mysqlblog.fivefarmers.com as Exploit, with Packet Storm also referenced. |
| EPSS | Tenable currently shows EPSS 0.51876 for CVE-2015-3152. Treat that as attacker-interest telemetry, not proof that the on-path prerequisite disappears. |
| KEV status | Not listed in CISA KEV. That matters: there is no public U.S. federal exploitation mandate signal here. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N = network reachable in theory, but high attack complexity because the attacker must gain MITM/DNS position first. |
| Affected versions | Primary plugin scope: Oracle MySQL client library 5.1.x / 5.5.x / 5.6.x / 5.7.x before 5.7.3. Broader CVE scope also includes MySQL Connector/C before 6.1.3 and MariaDB before 5.5.44 / 10.0.20. |
| Fixed versions | Oracle changed client behavior in MySQL 5.7.3 so --ssl became prescriptive and added MYSQL_OPT_SSL_ENFORCE; distro channels may instead carry backports under Debian/Red Hat advisories without upstream-looking version numbers. |
| Exposure / scanning reality | Shadowserver reported 3,957,457 MySQL servers on IPv4 port 3306 and 2,279,908 accessible with a server greeting on 2022-05-26. Useful context, but this CVE is client-side, so exposed-server counts overstate true exploitable population. |
| Disclosure / reporting | Public disclosure traces to oCERT-2015-003 and the Duo Security research/publication cycle in late April 2015; NVD publication followed on 2016-05-16. |
noisgate verdict.
The decisive factor is the attacker-position requirement: this bug is only useful if the adversary can already get on-path or poison DNS for the app-to-DB connection. That makes it a post-initial-access/network-manipulation issue with a sharply smaller real-world exposure pool than the vendor baseline implies.
Why this verdict
- Start from MEDIUM 5.9: the underlying impact is real because successful exploitation exposes or alters live SQL traffic.
- Subtract hard for attacker position: this is not unauthenticated internet-to-service exploitation; it needs MITM placement or DNS control, which usually implies prior compromise, insider position, or network abuse capability.
- Subtract again for reachable population: the vulnerable side is the client library, not just the server daemon, and many enterprise DB paths stay on private networks, local sockets, or already trusted overlays.
- No exploitation amplifier: there is no KEV signal and I found no primary-source campaign reporting for this CVE, so there is no reason to override friction with urgency.
- Impact is bounded: the outcome is traffic disclosure/manipulation, not default RCE or host takeover.
Why not higher?
Because the exploit chain starts with a strong prerequisite that modern programs should already make hard: getting between the application and the database or owning DNS for that relationship. If you cannot reach that position, the bug does nothing. It also does not hand an external attacker direct code execution on the MySQL host.
Why not lower?
Because once an attacker is on-path, the downgrade can quietly expose credentials and business data or let them tamper with query results. Legacy MySQL client code is still common in brownfield estates, so the condition is narrow but not exotic.
What to do — in priority order.
- Force private DB paths — Keep application-to-MySQL traffic on private segments, sockets, or dedicated overlays so an attacker cannot easily obtain the required MITM position. For a LOW verdict there is no SLA; treat this as backlog hygiene and align it with normal network-hardening work.
- Require identity-validated TLS — Move clients to enforced TLS modes that fail closed and verify the server identity, not just 'try SSL'. This directly removes the downgrade condition; for LOW, schedule it as backlog hygiene alongside client-library modernization.
- Reduce DNS trust for DB endpoints — Use static service discovery, tightly scoped internal DNS, and monitoring for changes to database records to make redirection attacks harder. For this LOW finding, fold the work into routine platform engineering rather than emergency change windows.
- Watch for plaintext MySQL — Baseline where MySQL traffic should be encrypted, then alert on sessions that show plain TCP MySQL where TLS is expected. This is a cheap detective control and fits backlog hygiene timing for a LOW issue.
- Setting legacy client
--sslon affected versions and assuming that means must encrypt. That assumption is the bug. - Closing public port 3306 alone. Helpful generally, but this vulnerability can still matter on east-west paths inside your estate.
- Server-side TLS support by itself. If the client does not enforce or validate it, the attacker can still aim for fallback behavior.
Crowdsourced verification payload.
Run this on the application host or database client host, not on your scanner, because the flaw lives in the client library / client binary behavior. Invoke it as python3 verify_backronym.py with no arguments; standard user privileges are usually enough, but package-manager queries may return less detail without elevated rights.
#!/usr/bin/env python3
# verify_backronym.py
# Heuristic checker for BACKRONYM / CVE-2015-3152 exposure on local hosts.
# Outputs exactly one of: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
import os
import re
import subprocess
import sys
from shutil import which
EXIT_PATCHED = 0
EXIT_VULN = 1
EXIT_UNKNOWN = 2
def run(cmd):
try:
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=8)
return p.returncode, (p.stdout or '') + (p.stderr or '')
except Exception:
return 127, ''
def parse_version(text):
# Accepts versions like 5.7.2, 5.5.44-MariaDB, 10.0.19-MariaDB
m = re.search(r'(\d+)\.(\d+)\.(\d+)', text)
if not m:
return None
return tuple(int(x) for x in m.groups())
def cmp_ver(a, b):
return (a > b) - (a < b)
def collect_evidence():
evidence = []
candidates = [
['mysql', '--version'],
['mysql_config', '--version'],
]
for cmd in candidates:
if which(cmd[0]):
rc, out = run(cmd)
if out.strip():
evidence.append(('binary', cmd[0], out.strip()))
# Package manager hints. These can be ambiguous because distros backport fixes.
pkg_cmds = [
['rpm', '-qa'],
['dpkg-query', '-W', '-f=${Package} ${Version}\n'],
]
for cmd in pkg_cmds:
if which(cmd[0]):
rc, out = run(cmd)
if rc == 0 and out:
for line in out.splitlines():
l = line.lower()
if any(x in l for x in ['mysql', 'mariadb', 'libmysqlclient', 'mysql-community', 'connector/c']):
evidence.append(('package', cmd[0], line.strip()))
return evidence
def decide(evidence):
# Prefer direct binary evidence over package names.
binary_text = ' | '.join(x[2] for x in evidence if x[0] == 'binary')
package_text = ' | '.join(x[2] for x in evidence if x[0] == 'package')
if not evidence:
return 'UNKNOWN', 'No MySQL/MariaDB client evidence found on host.'
text = (binary_text or package_text).strip()
t = text.lower()
ver = parse_version(text)
if not ver:
return 'UNKNOWN', 'Version string could not be parsed.'
# Distro package streams often backport without matching upstream versioning.
if package_text and not binary_text:
return 'UNKNOWN', 'Only package-manager evidence found; distro backports may already include the fix.'
# MariaDB logic from NVD/oCERT change history.
if 'mariadb' in t:
if ver[0] == 5 and ver[1] == 5:
if cmp_ver(ver, (5, 5, 44)) < 0:
return 'VULNERABLE', f'MariaDB client appears older than 5.5.44: {ver}'
return 'PATCHED', f'MariaDB client appears at or above 5.5.44: {ver}'
if ver[0] == 10 and ver[1] == 0:
if cmp_ver(ver, (10, 0, 20)) < 0:
return 'VULNERABLE', f'MariaDB client appears older than 10.0.20: {ver}'
return 'PATCHED', f'MariaDB client appears at or above 10.0.20: {ver}'
return 'UNKNOWN', f'MariaDB detected, but version branch is not directly covered by this heuristic: {ver}'
# Oracle/Percona/MySQL client heuristic aligned to plugin scope.
if 'mysql' in t:
if cmp_ver(ver, (5, 7, 3)) < 0:
return 'VULNERABLE', f'MySQL client appears older than 5.7.3: {ver}'
return 'PATCHED', f'MySQL client appears at or above 5.7.3: {ver}'
return 'UNKNOWN', 'Unable to classify local client software.'
def main():
evidence = collect_evidence()
verdict, reason = decide(evidence)
# Keep primary output machine-friendly.
print(verdict)
# Send evidence to stderr for operators.
print(reason, file=sys.stderr)
for kind, source, line in evidence[:20]:
print(f'[{kind}:{source}] {line}', file=sys.stderr)
if verdict == 'PATCHED':
sys.exit(EXIT_PATCHED)
if verdict == 'VULNERABLE':
sys.exit(EXIT_VULN)
sys.exit(EXIT_UNKNOWN)
if __name__ == '__main__':
main()
If you remember one thing.
tenable:83347 as a stop-everything patch wave. First, inventory where legacy MySQL client libraries are actually used on app hosts and identify the subset whose DB traffic crosses shared, routed, or otherwise untrusted network paths; that is the only slice that deserves attention. For a LOW verdict there is no noisgate mitigation SLA and no noisgate remediation SLA—treat it as backlog hygiene—but fold compensating controls into normal network/TLS hardening and retire vulnerable client versions during your routine legacy middleware refresh cycle. If you find a sensitive app talking to MySQL across a hostile/shared segment, pull that one forward out of backlog on exposure grounds, not because this CVE is broadly urgent.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.