← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:103329 · CWE-434 · Disclosed 2017-09-19

Apache Tomcat 7

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is less a front-door master key and more a bad spare key hidden under one very specific mat

Tenable plugin 103329 flags any Apache Tomcat 7.0.0 through <7.0.81, but the real exposure is split across two very different flaws. CVE-2017-12615 is the serious one: unauthenticated remote JSP upload leading to RCE, but only on Windows and only when HTTP PUT is enabled, typically by setting the Default servlet readonly init-param to false; upstream says it affects 7.0.0 to 7.0.79. CVE-2017-12616 affects 7.0.0 to 7.0.80 and allows security-constraint bypass and JSP source disclosure, but only when VirtualDirContext is in use.

The vendor/plugin High label is fair for a host that actually meets those prerequisites, but it overstates risk for a generic fleet ticket because the plugin is a version-only check and does not prove Windows, PUT enablement, or VirtualDirContext. In a 10,000-host estate, those conditions are exactly the kind of friction that should drag a blanket patch finding down from panic status to scoped validation—while still treating confirmed Windows+PUT instances as urgent because CVE-2017-12615 is KEV-listed and has public exploit code.

"This is a noisy version-check finding: dangerous on a narrow subset, not estate-wide fire for every Tomcat 7 host."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Fingerprint an old Tomcat 7 target

Attackers start by identifying Tomcat 7 instances with banner grabs, error pages, manager app artifacts, or version inventory from scanners such as Nessus/Nmap. This is easy on exposed app servers, but a raw 7.0.x version alone does not prove exploitability for this plugin.
Conditions required:
  • Network reachability to the Tomcat HTTP/S listener
  • A version in the affected range
Where this breaks in practice:
  • Reverse proxies often strip Tomcat fingerprints
  • Distro-backported packages may report old lineage while already carrying fixes
  • Tenable 103329 itself is version-based and can overstate exposure
Detection/coverage: Very high scanner coverage for version detection; low confidence that this step alone distinguishes exploitable from non-exploitable systems.
STEP 02

Probe the RCE branch with PUT

For CVE-2017-12615, the attacker uses a simple curl/custom script or public PoCs such as EDB-42953 / breaktoprotect/CVE-2017-12615 to test whether the Default servlet accepts PUT uploads. If accepted on Windows, a crafted .jsp payload can be written into web content and prepared for execution.
Conditions required:
  • Target is Windows
  • Tomcat version is 7.0.0 to 7.0.79
  • HTTP PUT is enabled via dangerous configuration such as readonly=false
  • Uploaded content lands in an executable web path
Where this breaks in practice:
  • Default Tomcat deployments do not enable this path
  • Many enterprises terminate traffic through WAF/NGFW layers that block unusual methods
  • Windows Tomcat is materially less common than Linux in many estates
Detection/coverage: Method auditing, WAF logs, reverse-proxy logs, and IDS signatures for suspicious PUT to .jsp are usually good here; Tenable does not test the method-path combination.
STEP 03

Execute the uploaded JSP or fall back to source disclosure

If the PUT branch works, the attacker simply requests the uploaded JSP to get arbitrary code execution in the Tomcat process. If the PUT branch does not work but VirtualDirContext is configured, tooling such as CANVAS/Elliot-style checks can abuse CVE-2017-12616 to bypass constraints or read JSP source, exposing credentials, connection strings, and application logic for follow-on attacks.
Conditions required:
  • Successful file write for the RCE branch, or VirtualDirContext for the disclosure branch
  • Ability to request the uploaded JSP or the crafted disclosure path
Where this breaks in practice:
  • JSP source disclosure is not equivalent to immediate code execution
  • App-layer auth, segmented admin paths, and secret hygiene can limit blast radius after disclosure
  • Some VirtualDirContext usage is rare and highly app-specific
Detection/coverage: Web logs often show obvious .jsp upload-and-fetch sequences; source-disclosure probes are noisier but still visible in unusual path requests.
STEP 04

Turn app compromise into business impact

A successful JSP shell gives the attacker code execution as the Tomcat service account, which is commonly enough for credential theft, app tampering, lateral movement, or full host takeover when service permissions are weak. The disclosure branch is slower, but leaked JSP source frequently reveals hard-coded secrets and internal endpoints that collapse downstream controls.
Conditions required:
  • Tomcat service account has meaningful local or network privileges
  • Application stores secrets or trust material accessible to the process
Where this breaks in practice:
  • Least-privilege service accounts and EDR materially reduce post-exploitation success
  • Containerized or tightly sandboxed Tomcat limits host-level blast radius
Detection/coverage: EDR/process telemetry should catch child-process execution from java/Tomcat after a successful JSP shell; secret abuse may only appear in application and database logs.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusCVE-2017-12615 is KEV-listed by CISA, which is enough to treat confirmed Windows+PUT cases as actively relevant. I found no equivalent KEV listing for CVE-2017-12616.
KEV datesCVE-2017-12615 was added to the CISA KEV catalog on 2022-03-25 with a due date of 2022-04-15; CVE-2017-12617 was also added the same day, which often causes operator confusion because it is a related later PUT upload flaw.
Proof-of-concept availabilityPublic exploit material is abundant for the RCE path: NVD/CVE references include Exploit-DB 42953 and the GitHub PoC breaktoprotect/CVE-2017-12615. Tenable also marks the plugin as Exploit Available: true.
EPSSReviewed FIRST EPSS documentation confirms public scoring availability; a secondary CVE mirror currently shows CVE-2017-12615 at roughly 94.2% EPSS / 100th percentile. Treat that as supportive threat context, not primary severity truth, because the exploit still hinges on Windows + PUT.
CVSS interpretationCVE-2017-12615 is CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H = 8.1 High on NVD: network reachable and pre-auth, but the AC:H reflects the environmental setup needed. CVE-2017-12616 is 7.5 High for confidentiality loss, but only if VirtualDirContext is actually used.
Affected versionsUpstream Apache states CVE-2017-12615 affects Tomcat 7.0.0 to 7.0.79; CVE-2017-12616 affects 7.0.0 to 7.0.80. The Tenable plugin rolls both into a single <7.0.81 version check.
Fixed versionsUpstream fix point is Apache Tomcat 7.0.81. For distro-packaged Tomcat, rely on vendor backports rather than naive upstream string comparison; for example Ubuntu shows tomcat7 fixed in 7.0.68-1ubuntu0.4+esm3 on Xenial and 7.0.52-1ubuntu0.14 on Trusty for CVE-2017-12616.
Scanning / exposure realityThere is plenty of internet-facing Tomcat exposure in general, but the truly exploitable subset for this plugin is much narrower because the RCE branch requires Windows + PUT enabled and the disclosure branch requires VirtualDirContext. I did not find an authoritative internet-wide census of that narrowed subset in the reviewed sources, which is exactly why blanket severity inflation is a mistake.
Disclosure timelineApache fixed these issues in Tomcat 7.0.81 on 2017-08-16 and made them public on 2017-09-19. CISA published a contemporaneous alert on 2017-09-19 warning that exploitation of one of the vulnerabilities could allow remote takeover.
Reporting / discoveryApache attributes CVE-2017-12615 to iswin from 360-sg-lab and says CVE-2017-12616 was identified by the Tomcat Security Team.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (5.8/10)

The single biggest downgrading factor is that the dangerous branch most defenders care about—pre-auth remote RCE—requires a narrow and uncommon configuration: Windows Tomcat plus HTTP PUT enablement. This plugin is a broad version-only check, so for most enterprise fleets it does not prove an immediately exploitable condition even though one included CVE is KEV-listed.

HIGH Technical prerequisites for `CVE-2017-12615` and `CVE-2017-12616`
HIGH Tenable `103329` being version-based rather than exploit-condition-aware
MEDIUM How often your specific estate uses Windows Tomcat with `PUT` enabled or `VirtualDirContext`

Why this verdict

  • Downward pressure: Windows-only RCE pathCVE-2017-12615 is not a universal Tomcat 7 RCE; it only applies to Windows for the version range Apache lists.
  • Downward pressure: dangerous PUT config required — the attacker still needs HTTP PUT enabled, usually via readonly=false, which is not the normal secure deployment state and materially shrinks the reachable population.
  • Downward pressure: alternate flaw is app-specificCVE-2017-12616 needs VirtualDirContext, so many plugin hits on Linux/standard server builds collapse to non-exploitable noise.
  • Upward pressure: real exploitation evidence existsCVE-2017-12615 is in CISA KEV and public exploit code is easy to obtain, so any host that actually satisfies the prerequisites is high-priority in practice.
  • Downward pressure: scanner certainty is low — Tenable explicitly says it did not test the issues and relied on self-reported versioning, which is a bad basis for fleet-wide urgency.

Why not higher?

It is not HIGH or CRITICAL as a blanket estate verdict because the exploit chain assumes a configuration that many enterprises simply do not expose: Windows Tomcat with PUT enabled, or separately VirtualDirContext. That is compounding friction, not edge-case trivia. A 10,000-host patch program should score the reachable population, not the theoretical maximum damage of the best-case lab exploit.

Why not lower?

It is not LOW or IGNORE because one branch is still unauthenticated remote code execution with public PoCs and confirmed exploitation history via KEV. If you do have Windows Tomcat with PUT enabled, this finding stops being noisy instantly and becomes a very real shell-on-server problem.

05 · Compensating Control

What to do — in priority order.

  1. Disable PUT on DefaultServlet — For any unpatched Tomcat 7 on Windows, verify the Default servlet readonly init-param is not false and block HTTP PUT at the app server and reverse proxy. Because CVE-2017-12615 is KEV-listed, deploy this immediately, within hours for any system you cannot patch today.
  2. Block dangerous methods upstream — Enforce GET/POST/HEAD only at the WAF, load balancer, or reverse proxy unless a business case explicitly requires other verbs. This is the fastest blast-radius reduction and, due to KEV status, should be in place immediately, within hours for exposed legacy Tomcat.
  3. Hunt for VirtualDirContext — Search server.xml, context.xml, and app context fragments for VirtualDirContext; if present on affected versions, treat the host as exposed to CVE-2017-12616 and remove that dependency or isolate the app. Because there is active relevance in the plugin bundle, complete this validation immediately, within hours on internet-facing or high-value internal apps.
  4. Constrain Tomcat service privileges — Run Tomcat with a least-privilege service account, deny interactive logon, and restrict write/execute paths so a JSP upload cannot trivially become host takeover. This does not fix the bug, but it cuts post-exploitation blast radius and should be enforced immediately, within hours on any confirmed exposed instance.
  5. Alert on JSP upload-and-fetch patterns — Detect PUT or MOVE to .jsp, .jspx, or suspicious content types followed by a request to the same path, and alert on child processes launched by java/Tomcat. Stand this up immediately, within hours where patching will lag.
What doesn't work
  • A pure version string allowlist does not solve the prioritization problem here, because downstream backports and Tenable's version-only logic can both mislead you.
  • Relying on perimeter segmentation alone does not help much for internal app tiers; once an attacker has foothold on the inside, this becomes a straightforward post-initial-access exploit if the config preconditions exist.
  • MFA is irrelevant to the primary exploit path because the RCE branch is unauthenticated and rides HTTP method handling, not user login.
06 · Verification

Crowdsourced verification payload.

Run this on the target Tomcat host or against an offline copy of its installation directory. Invoke it as python3 tomcat_103329_check.py /opt/tomcat or py tomcat_103329_check.py "C:\Tomcat7"; it only needs read access to the Tomcat install and conf/ files, not admin rights.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# tomcat_103329_check.py
# Checks likely exploitability for Tenable plugin 103329 on a local Tomcat install.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=USAGE/ERROR

import os
import re
import sys
from pathlib import Path


def read_text(path):
    try:
        return Path(path).read_text(encoding='utf-8', errors='ignore')
    except Exception:
        return None


def parse_version(text):
    if not text:
        return None
    patterns = [
        r'Apache Tomcat Version\s+([0-9]+\.[0-9]+\.[0-9]+)',
        r'Server version:\s*Apache Tomcat/([0-9]+\.[0-9]+\.[0-9]+)',
        r'Implementation-Version:\s*([0-9]+\.[0-9]+\.[0-9]+)',
        r'Specification-Version:\s*([0-9]+\.[0-9]+\.[0-9]+)'
    ]
    for pat in patterns:
        m = re.search(pat, text, re.IGNORECASE)
        if m:
            return m.group(1)
    return None


def version_tuple(v):
    try:
        return tuple(int(x) for x in v.split('.'))
    except Exception:
        return None


def find_version(base):
    candidates = [
        base / 'RELEASE-NOTES',
        base / 'RUNNING.txt',
        base / 'bin' / 'version.sh',
        base / 'bin' / 'version.bat',
        base / 'lib' / 'catalina.jar',
        base / 'lib' / 'catalina.jar.MF',
        base / 'lib' / 'MANIFEST.MF'
    ]

    for c in candidates:
        if c.is_file():
            txt = read_text(c)
            v = parse_version(txt)
            if v:
                return v, str(c)

    # Fallback: search a few likely text files under base
    for rel in ['RELEASE-NOTES', 'RUNNING.txt']:
        p = base / rel
        if p.exists():
            txt = read_text(p)
            v = parse_version(txt)
            if v:
                return v, str(p)

    return None, None


def is_put_enabled(base):
    webxml = base / 'conf' / 'web.xml'
    txt = read_text(webxml)
    if not txt:
        return None, str(webxml)

    # Conservative check: look for readonly=false anywhere in web.xml
    if re.search(r'<param-name>\s*readonly\s*</param-name>\s*<param-value>\s*false\s*</param-value>', txt, re.IGNORECASE | re.DOTALL):
        return True, str(webxml)

    # If readonly parameter is absent or not false, assume PUT is not enabled on default servlet.
    return False, str(webxml)


def has_virtualdircontext(base):
    conf_dir = base / 'conf'
    if not conf_dir.exists():
        return None, str(conf_dir)

    checked = []
    for p in conf_dir.rglob('*.xml'):
        checked.append(str(p))
        txt = read_text(p)
        if txt and 'VirtualDirContext' in txt:
            return True, ', '.join(checked)
    return False, ', '.join(checked)


def main():
    if len(sys.argv) != 2:
        print('UNKNOWN - usage: python3 tomcat_103329_check.py <CATALINA_BASE>')
        sys.exit(3)

    base = Path(sys.argv[1])
    if not base.exists() or not base.is_dir():
        print('UNKNOWN - path does not exist or is not a directory')
        sys.exit(3)

    version, source = find_version(base)
    if not version:
        print('UNKNOWN - could not determine Tomcat version from local files')
        sys.exit(2)

    vt = version_tuple(version)
    if not vt:
        print(f'UNKNOWN - unparsable Tomcat version: {version}')
        sys.exit(2)

    # Upstream fixed point for the bundled Tenable finding
    if vt >= (7, 0, 81):
        print(f'PATCHED - Tomcat {version} (>= 7.0.81) from {source}')
        sys.exit(0)

    put_enabled, put_source = is_put_enabled(base)
    vdc_enabled, vdc_source = has_virtualdircontext(base)
    on_windows = (os.name == 'nt')

    reasons = []
    if vdc_enabled is True:
        reasons.append('VirtualDirContext present (CVE-2017-12616 path)')

    if on_windows and vt < (7, 0, 80) and put_enabled is True:
        reasons.append('Windows host and DefaultServlet readonly=false / PUT enabled (CVE-2017-12615 path)')

    if reasons:
        print(f'VULNERABLE - Tomcat {version}; ' + '; '.join(reasons))
        sys.exit(1)

    # Not enough evidence for exploitability even though version is old.
    detail = []
    detail.append(f'Tomcat {version} < 7.0.81')
    detail.append(f'OS={"Windows" if on_windows else "Non-Windows"}')
    detail.append(f'PUT enabled={put_enabled} ({put_source})')
    detail.append(f'VirtualDirContext present={vdc_enabled} ({vdc_source})')
    print('UNKNOWN - affected version detected but required exploit conditions were not confirmed: ' + '; '.join(detail))
    sys.exit(2)


if __name__ == '__main__':
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning plan: do not mass-escalate every 103329 hit as equivalent. First, use host-side validation to split the fleet into three buckets: Windows + PUT enabled, VirtualDirContext present, and everything else. Because CVE-2017-12615 is KEV-listed, apply compensating controls or patch confirmed exposed systems immediately, within hours despite the overall MEDIUM verdict; for the rest, there is noisgate mitigation SLA override due to KEV evidence, and for the broader version-only population there is otherwise no mitigation SLA — go straight to the 365-day remediation window. Complete the actual Tomcat upgrade or distro-supported backport rollout for validated exposures inside the noisgate remediation SLA of ≤365 days, but do the scoping and emergency containment on confirmed exposed instances today.

Sources

  1. Tenable plugin 103329
  2. Apache Tomcat 7 security page
  3. CVE.org record for CVE-2017-12615
  4. NVD entry for CVE-2017-12615
  5. CISA Known Exploited Vulnerabilities Catalog
  6. CISA 2017 Tomcat alert
  7. Ubuntu CVE-2017-12616 status/backports
  8. FIRST EPSS API documentation
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.