This is a smoke detector tripping in the basement, not the front door being kicked in
Plugin 109945 maps to CVE-2018-0739, an uncontrolled-recursion bug in OpenSSL ASN.1 parsing. Upstream affected ranges are 1.0.2b–1.0.2n and 1.1.0–1.1.0g, fixed in 1.0.2o and 1.1.0h. The crash path is tied to maliciously recursive ASN.1 structures such as those seen in PKCS7/CMS-style content, and the outcome is process DoS, not code execution or data theft.
The vendor MEDIUM label is technically defensible in a vacuum, but it overstates enterprise urgency for a generic OpenSSL version finding. OpenSSL's own advisory says the vulnerable structures are not used in SSL/TLS from untrusted sources, so the usual 'internet-facing TLS service with old OpenSSL' mental model is wrong here; add Tenable's version-only, self-reported detection and this becomes mostly a low-priority validation task, not a patch emergency.
4 steps from start to impact.
Find an app that actually feeds untrusted ASN.1 into OpenSSL
- Affected OpenSSL build in the upstream vulnerable range or an unfixed vendor package
- An exposed application workflow that parses attacker-supplied ASN.1/PKCS7/CMS/S/MIME content
- Most enterprise OpenSSL exposure is ordinary TLS, which is *not* the reachable path here
- Many flagged hosts will never parse attacker-controlled PKCS7/CMS data at all
109945 does not test exploitability; it keys off installed version data.Generate a deeply recursive ASN.1 payload
- Ability to craft malformed recursive ASN.1 content
- Understanding of the target application's accepted file/message format
- Public weaponization is weak; Tenable marks 'no known exploits are available'
- The payload must match a real ingest path, not just 'OpenSSL is installed'
Deliver the payload through the specific business workflow
- A reachable import/verification path
- The target service actually delegates parsing to vulnerable OpenSSL code
- Many enterprises front these workflows with mail hygiene, file screening, or simply do not expose them externally
- Lots of affected binaries sit behind authenticated or internal-only paths
Crash the parsing process
- Payload reaches the parser unchanged
- No upstream or distro backport fix present
- Supervisors, worker recycling, and service restarts reduce practical impact
- Outcome is availability-only; there is no demonstrated RCE path in the advisory
The supporting signals.
| In-the-wild status | No public active exploitation evidence found in the vendor/NVD corpus reviewed, and not present in CISA KEV as of 2026-02-14 (*inference from catalog search absence*). |
|---|---|
| Public exploit / PoC | Tenable records 'No known exploits are available' for this CVE/plugin. I did not find a mainstream Metasploit or Exploit-DB path in primary-source review. |
| EPSS | Tenable's CVE page, sourcing FIRST EPSS, shows 0.16197. That's non-zero exploit likelihood, but it does not override the big reachability friction here. |
| KEV status | Not KEV-listed on the CISA catalog page checked on 2026-02-14 (*inference from absence*). No due date pressure from KEV. |
| CVSS vector reality check | CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H reads like a network bug, but the real reachable path is narrower because normal untrusted SSL/TLS traffic is explicitly called out as safe by OpenSSL. |
| Affected versions | Upstream affected: OpenSSL 1.0.2b–1.0.2n and 1.1.0–1.1.0g. |
| Fixed versions | Upstream fixed in 1.0.2o and 1.1.0h. Canonical backported fixes to distro packages such as xenial 1.0.2g-1ubuntu4.11 and bionic/cosmic/disco 1.0.2n-1ubuntu5. |
| Detection quality | Plugin 109945 says Nessus 'has not tested for this issue' and relies on the application's self-reported version number. That is a strong false-positive amplifier on backported distro builds. |
| Exposure / scanning data | There is no meaningful Shodan/Censys-style census for this CVE alone because exposure depends on an application's use of OpenSSL's ASN.1 parser, not simply on port 443 being open. |
| Disclosure / credit | Disclosed 2018-03-27. Reported by OSS-Fuzz; fix developed by Matt Caswell per the OpenSSL advisory. |
noisgate verdict.
The decisive downgrade factor is that normal untrusted SSL/TLS traffic is not the vulnerable path; an attacker needs a much narrower application workflow that parses attacker-controlled ASN.1/PKCS7/CMS content. Combined with version-only scanner evidence and availability-only impact, this does not justify MEDIUM patch priority across a 10,000-host fleet.
Why this verdict
- Major downward adjustment: reachable only through non-standard parser paths. The attacker position is *not* generic unauthenticated remote-to-TLS; it implies a specific app workflow that ingests attacker-controlled ASN.1/PKCS7/CMS data, which sharply shrinks the exposed population.
- Impact is limited to DoS. Even where reachable, the practical outcome is a process crash or service interruption, not RCE, credential theft, or tenant-wide compromise.
- Scanner evidence is weak. Plugin
109945explicitly relies on self-reported versioning and does not test exploitability, so backported distro packages and non-reachable library instances inflate the queue. - No KEV / no exploitation signal. There is no CISA KEV pressure and no strong public weaponization evidence in the primary-source set reviewed.
Why not higher?
If this were a generic TLS-handshake bug on internet-facing services, a MEDIUM or HIGH argument would be easier. It is not: OpenSSL says the vulnerable recursive structures are not part of untrusted SSL/TLS input, and that single fact collapses the exposed population. Add version-only detection noise and the case for urgent fleet-wide action falls apart.
Why not lower?
I am not calling it IGNORE because some products really do parse untrusted PKCS7/CMS/S/MIME and can be crashed if they are on a truly unfixed upstream build. Also, some custom or appliance-style OpenSSL deployments will not benefit from distro backports, so a blanket suppression without validation would be sloppy.
What to do — in priority order.
- Re-scope the finding to parser-exposed apps — Identify which assets actually process attacker-controlled PKCS7/CMS/S/MIME/ASN.1 content and downgrade the rest. For a LOW verdict there is no mitigation SLA; do this as backlog hygiene during the next triage cycle so your patch queue reflects reachable risk, not library name alone.
- Prefer vendor-packaged OpenSSL over hand-built copies — Backported distro packages often fix this without changing the upstream-looking version family. For LOW, there is no hard mitigation deadline; use normal maintenance windows to replace stray custom builds with supported packages where feasible.
- Gate risky content ingestion paths — Where apps do accept signed mail, CMS blobs, certificate imports, or other ASN.1-heavy artifacts, put validation and content screening in front of them and restrict external reachability. For LOW, do this opportunistically as part of service hardening rather than emergency response.
TLS 1.2-onlyor cipher-suite hardening doesn't solve this, because the advisory says the vulnerable recursive structures are not in normal untrusted SSL/TLS parsing.- A generic WAF is usually irrelevant unless the vulnerable ASN.1 payload is actually transiting an HTTP upload/import workflow the WAF can parse and block.
- Blindly keying on the OpenSSL upstream version string doesn't prove exposure on backported distro builds.
Crowdsourced verification payload.
Run this on the target host that Nessus flagged, not from an auditor workstation. Invoke it as python3 check_cve_2018_0739.py with normal user rights; it reads local openssl and package metadata and prints VULNERABLE, PATCHED, or UNKNOWN.
#!/usr/bin/env python3
# check_cve_2018_0739.py
# Purpose: classify likely exposure to CVE-2018-0739 on the local host.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
import os
import re
import shutil
import subprocess
import sys
def run(cmd):
try:
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=10)
return p.returncode, p.stdout.strip(), p.stderr.strip()
except Exception as e:
return 127, "", str(e)
def parse_upstream(ver):
# Handles forms like 1.0.2n, 1.0.2o-fips, 1.1.0g
m = re.search(r'(\d+)\.(\d+)\.(\d+)([a-z]?)', ver)
if not m:
return None
major = int(m.group(1))
minor = int(m.group(2))
patch = int(m.group(3))
letter = m.group(4) or ''
letter_num = ord(letter) - 96 if letter else 0
return (major, minor, patch, letter_num)
def cmp_tuple(a, b):
return (a > b) - (a < b)
def upstream_status(openssl_ver):
t = parse_upstream(openssl_ver)
if not t:
return 'UNKNOWN', 'Could not parse OpenSSL version string'
v_102b = (1, 0, 2, 2)
v_102n = (1, 0, 2, 14)
v_102o = (1, 0, 2, 15)
v_1100 = (1, 1, 0, 0)
v_110g = (1, 1, 0, 7)
v_110h = (1, 1, 0, 8)
if cmp_tuple(t, v_102b) >= 0 and cmp_tuple(t, v_102n) <= 0:
return 'POTENTIALLY_VULNERABLE', 'Upstream-style version falls in 1.0.2b-1.0.2n'
if cmp_tuple(t, v_1100) >= 0 and cmp_tuple(t, v_110g) <= 0:
return 'POTENTIALLY_VULNERABLE', 'Upstream-style version falls in 1.1.0-1.1.0g'
if cmp_tuple(t, v_102o) >= 0 or cmp_tuple(t, v_110h) >= 0 or t[0] > 1 or (t[0] == 1 and t[1] > 1):
return 'PATCHED', 'Upstream-style version is at or above fixed release'
return 'UNKNOWN', 'Version is outside the known affected/fixed ranges or uses unusual packaging'
def ubuntu_backport_check():
if not shutil.which('dpkg-query'):
return None
candidates = ['openssl', 'libssl1.1', 'libssl1.0.2', 'libssl1.0.0']
installed = {}
for pkg in candidates:
rc, out, _ = run(['dpkg-query', '-W', '-f=${Status} ${Version}\n', pkg])
if rc == 0 and out.startswith('install ok installed '):
installed[pkg] = out.split()[-1]
if not installed:
return None
# Canonical fixed examples from Ubuntu CVE page
fixed_thresholds = [
('openssl', '1.1.0g-2ubuntu3'),
('openssl', '1.0.2g-1ubuntu13.4'),
('openssl', '1.0.2g-1ubuntu4.11'),
('openssl', '1.0.1f-1ubuntu2.24'),
('libssl1.0.2', '1.0.2n-1ubuntu5'),
('libssl1.1', '1.1.0g-2ubuntu3'),
]
for pkg, fixed in fixed_thresholds:
if pkg in installed and shutil.which('dpkg'):
rc = subprocess.run(['dpkg', '--compare-versions', installed[pkg], 'ge', fixed]).returncode
if rc == 0:
return ('PATCHED', f'Debian/Ubuntu package {pkg}={installed[pkg]} is at/above known fixed threshold {fixed}')
return ('VULNERABLE', 'Debian/Ubuntu package version appears below the known Ubuntu fixed thresholds')
def rpm_backport_check():
if not shutil.which('rpm'):
return None
pkg_names = ['openssl', 'openssl-libs']
found = []
for pkg in pkg_names:
rc, out, _ = run(['rpm', '-q', '--qf', '%{NAME} %{EPOCHNUM}:%{VERSION}-%{RELEASE}\n', pkg])
if rc == 0 and out:
found.append(out.strip())
if not found:
return None
# Prefer authoritative comparison if rpmdev-vercmp exists.
if shutil.which('rpmdev-vercmp'):
target = '1:1.0.2k-16.el7_6.1'
for line in found:
nevra = line.split(None, 1)[1]
rc, _, _ = run(['rpmdev-vercmp', nevra, target])
# rpmdev-vercmp returns 0 even when printing relation; parse stdout is inconsistent across versions.
# Fall back to a conservative exact-match / prefix heuristic if parsing is not available.
# If rpmdev-vercmp exists but parsing is awkward in a portable script, return UNKNOWN rather than guessing.
return ('UNKNOWN', 'RPM package found; authoritative version comparison needs local vendor advisory review because backports are common')
return ('UNKNOWN', 'RPM package found, but safe comparison against backported vendor build levels is not available without distro-specific tooling')
def main():
if not shutil.which('openssl'):
print('UNKNOWN: openssl binary not found in PATH')
sys.exit(2)
rc, out, err = run(['openssl', 'version'])
if rc != 0 or not out:
print(f'UNKNOWN: failed to execute openssl version ({err})')
sys.exit(2)
base = out.splitlines()[0]
status, reason = upstream_status(base)
if status == 'PATCHED':
print(f'PATCHED: {base} | {reason}')
sys.exit(0)
if status == 'UNKNOWN':
print(f'UNKNOWN: {base} | {reason}')
sys.exit(2)
# Potentially vulnerable upstream version; check common backport-aware package managers.
deb = ubuntu_backport_check()
if deb:
s, r = deb
print(f'{s}: {base} | {r}')
sys.exit(0 if s == 'PATCHED' else 1 if s == 'VULNERABLE' else 2)
rpm = rpm_backport_check()
if rpm:
s, r = rpm
print(f'{s}: {base} | {r}')
sys.exit(0 if s == 'PATCHED' else 1 if s == 'VULNERABLE' else 2)
# No package metadata; likely custom or raw upstream install.
print(f'VULNERABLE: {base} | upstream version is in the affected range and no package-backport evidence was found')
sys.exit(1)
if __name__ == '__main__':
main()
If you remember one thing.
Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.