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

Apache Tomcat 8

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

This is a nail gun on the loading dock: deadly, but only if someone also left the trigger unlocked

Tenable plugin 103698 maps to CVE-2017-12617 for Tomcat 8.5.0 through 8.5.22, fixed in 8.5.23. The bug lets an unauthenticated attacker upload a JSP and then execute it as server-side code, but only when Tomcat accepts writable HTTP PUT to the DefaultServlet, typically because the readonly init parameter was changed to false or an equivalent writable configuration exists. Upstream also lists affected branches as 9.0.0.M1 to 9.0.0, 8.0.0.RC1 to 8.0.46, and 7.0.0 to 7.0.81.

In lab terms this is straightforward RCE; in enterprise reality it is not default-reachable on most Tomcat deployments. That friction keeps it out of CRITICAL for me. But it is still HIGH because the attack is unauthenticated, public exploit code and Metasploit support have existed for years, CISA has it in KEV, and exposed misconfigured servers have been used in opportunistic campaigns like cryptomining.

"Real unauth RCE, but only on Tomcat hosts that left HTTP PUT writable; KEV means the exposed stragglers get hit fast."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find a reachable Tomcat HTTP service

The attacker needs direct or proxied access to the Tomcat web endpoint over HTTP/S. Commodity recon can fingerprint Tomcat banners or application behavior, and version-based scanners will happily flag 8.5.0-8.5.22 whether or not the dangerous configuration is actually present.
Conditions required:
  • Tomcat HTTP/S listener is reachable from the attacker position
  • The service is running an affected build in the 8.5.0-8.5.22 range
Where this breaks in practice:
  • Many enterprise Tomcat instances sit behind reverse proxies, API gateways, or are internal-only
  • Version fingerprinting alone does not prove writable PUT is enabled
Detection/coverage: Nessus 103698 gives good version coverage, but it does not validate the decisive precondition: writable PUT to the DefaultServlet.
STEP 02

Confirm writable HTTP PUT path

The practical exploit step is to verify that Tomcat will accept a PUT for a JSP-capable path, usually due to DefaultServlet readonly=false. Tools seen around this bug include simple curl probes, Exploit-DB PoCs, and Rapid7's Metasploit module exploit/multi/http/tomcat_jsp_upload_bypass.
Conditions required:
  • HTTP PUT is allowed through any reverse proxy or WAF in front of Tomcat
  • Tomcat's DefaultServlet or equivalent target is writable
Where this breaks in practice:
  • This is not the common default; readonly=true is the normal state
  • Proxies and WAFs often block uncommon verbs like PUT even when the backend would accept them
Detection/coverage: Web logs can catch PUT requests to .jsp-like names; some IDS/WAF signatures exist, but false positives are common if you only look for the method.
STEP 03

Upload the JSP payload

Once the writable path exists, the attacker sends a specially crafted request that stores attacker-controlled JSP content on disk. The payload can be a web shell, a dropper, or a one-shot command runner; public PoCs have made this step routine for years.
Conditions required:
  • The target path maps to executable JSP content
  • The server can write the uploaded content to the webroot or equivalent location
Where this breaks in practice:
  • Some apps expose Tomcat but do not map writable locations to executable JSP paths
  • Filesystem permissions and hardened container images can break the drop
Detection/coverage: File integrity monitoring, EDR, and web access logs can catch new .jsp creation or suspicious writes under webapps/.
STEP 04

Trigger server-side code execution

The attacker simply requests the uploaded JSP and gets code execution in the Tomcat service context. From there the outcome depends on the runtime account, local privileges, network adjacency, and what secrets or trust relationships that application server already holds.
Conditions required:
  • The uploaded JSP is web-accessible
  • Tomcat can execute JSPs in that location
Where this breaks in practice:
  • Blast radius is often limited to the application tier account first, not instant domain compromise
  • Modern EDR on the host may catch child-process execution, shell drops, or miner deployment
Detection/coverage: High-signal detections include Tomcat spawning shells, curl/wget, Java child processes, or sudden outbound connections after a PUT followed by a GET to the same object.
03 · Intelligence Metadata

The supporting signals.

Mapped issueTenable plugin 103698 maps to CVE-2017-12617.
In-the-wild statusCISA KEV-listed. NVD now embeds the KEV reference, and CISA's catalog marks it as actively exploited.
KEV datesAdded to KEV on 2022-03-25 with a federal due date of 2022-04-15.
PoC / weaponizationPublic exploit code has been available for years via Exploit-DB 42966 / 43008 and Rapid7's Metasploit module exploit/multi/http/tomcat_jsp_upload_bypass.
EPSSCurrent public mirrors of FIRST EPSS show this CVE at roughly 94% probability and around the 99th percentile; treat that as supportive signal, not the core reason for urgency.
CVSS meaningNVD scores it 8.1 HIGH with CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H. The AC:H is the tell: the bug is nasty, but only after the uncommon writable-PUT precondition is met.
Affected versionsUpstream affected ranges are 9.0.0.M1-9.0.0, 8.5.0-8.5.22, 8.0.0.RC1-8.0.46, and 7.0.0-7.0.81. This specific Tenable finding is the 8.5.x slice.
Fixed versionsUpstream fix for this branch is Tomcat 8.5.23. Distro users may instead see backported package fixes from Ubuntu and Red Hat errata, so package version strings can matter more than the upstream banner.
Exposure realityInternet search engines can find Tomcat, but they generally cannot prove writable DefaultServlet PUT without active probing. Raw Tomcat counts from Shodan/Censys therefore overstate the truly exploitable population.
Disclosure / reportingApache fixed 8.5.23 on 2017-10-01 and NVD published the CVE on 2017-10-03. Follow-on reporting and incident writeups documented opportunistic abuse, including cryptomining activity.
04 · The Call

noisgate verdict.

Final Verdict
UPGRADED to HIGH (8.8/10)

The single biggest downward pressure is that exploitation usually requires a non-default writable PUT configuration, which sharply narrows the reachable population versus a default-on internet RCE. It stays HIGH anyway because this is still unauthenticated remote code execution on exposed servers, it is KEV-listed, and public weaponization has been mature for years.

HIGH CVE mapping, affected range, and fixed version
HIGH Primary exploitation friction: writable HTTP PUT is required
MEDIUM Current EPSS percentile from public mirrors of FIRST data

Why this verdict

  • Start at vendor HIGH: if the preconditions line up, this is unauthenticated network RCE with full CIA impact.
  • Downward adjustment for attacker position reality: the attacker needs not just remote reachability, but a Tomcat deployment that also left PUT writable to the DefaultServlet or equivalent path; that is a meaningful narrowing of the exposed population.
  • Upward adjustment for threat evidence: KEV listing, long-lived public PoCs, Metasploit support, and observed opportunistic abuse mean the remaining exposed hosts are attractive and quickly targeted.

Why not higher?

This is not a default-on Tomcat catastrophe. The exploit chain assumes external reachability plus a writable PUT path that many mature deployments do not expose, and reverse proxies or WAFs frequently kill that verb before it reaches Tomcat. Those compounding prerequisites are exactly why I won't call it CRITICAL across a 10,000-host estate.

Why not lower?

Dropping this to MEDIUM would underweight two things that matter in the real world: unauthenticated RCE and known exploitation. Once you do have the bad configuration, this is easy to weaponize and the impact is immediate application-server compromise, not a theoretical edge case.

05 · Compensating Control

What to do — in priority order.

  1. Block HTTP PUT now — At reverse proxies, load balancers, WAFs, and Tomcat itself, deny PUT to JSP-capable paths and default-servlet targets. Because this CVE is KEV-listed, deploy this immediately, within hours, not on the normal HIGH timeline.
  2. Restore readonly=true — Review conf/web.xml and any application-specific WEB-INF/web.xml overrides for the DefaultServlet readonly parameter and force it back to the safe default. Do this immediately, within hours anywhere the affected version range is still present.
  3. Constrain Tomcat exposure — Move direct Tomcat access behind vetted reverse proxies, restrict source IPs, and keep app-tier listeners off the open internet where possible. For KEV-listed exposure, enforce this immediately, within hours on internet-facing systems.
  4. Hunt for JSP drops and child processes — Search webroots for recently created .jsp files, correlate PUT followed by GET to the same object, and alert on Tomcat spawning shells, downloaders, or miners. Start the hunt immediately, within hours for exposed servers in the vulnerable range.
What doesn't work
  • Relying on banner hiding does nothing; attackers can still probe behaviorally for writable PUT.
  • Assuming EDR alone is enough is weak; EDR may catch post-exploitation, but it does not stop the JSP from landing.
  • Blocking only the Tomcat Manager app misses the point; this bug abuses writable PUT to the servlet path, not manager credentials.
06 · Verification

Crowdsourced verification payload.

Run this on the Tomcat host with read access to the Tomcat installation and configuration. Invoke it as sudo bash check_cve_2017_12617.sh /opt/tomcat or set CATALINA_BASE; root is not strictly required, but you need permission to read conf/web.xml, app web.xml files, and the Tomcat version data.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2017_12617.sh
# Local check for Apache Tomcat CVE-2017-12617 on the 8.5.x branch.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 3=UNKNOWN

set -u

BASE="${1:-${CATALINA_BASE:-${CATALINA_HOME:-}}}"
if [[ -z "$BASE" ]]; then
  for d in /opt/tomcat /usr/local/tomcat /usr/share/tomcat* /var/lib/tomcat*; do
    if [[ -d "$d" ]]; then
      BASE="$d"
      break
    fi
  done
fi

if [[ -z "$BASE" || ! -d "$BASE" ]]; then
  echo "UNKNOWN - could not determine Tomcat base directory; pass it as the first argument"
  exit 3
fi

version=""
if [[ -x "$BASE/bin/version.sh" ]]; then
  out="$($BASE/bin/version.sh 2>/dev/null || true)"
  version="$(printf '%s\n' "$out" | sed -n 's/^Server version: .*\/\([0-9][0-9.]*\).*$/\1/p' | head -n1)"
fi

if [[ -z "$version" && -f "$BASE/RELEASE-NOTES" ]]; then
  version="$(sed -n 's/^Apache Tomcat Version \([0-9][0-9.]*\).*$/\1/p' "$BASE/RELEASE-NOTES" | head -n1)"
fi

if [[ -z "$version" ]]; then
  echo "UNKNOWN - could not determine Tomcat version under $BASE"
  exit 3
fi

verlte() {
  [[ "$1" == "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" ]]
}

vergte() {
  [[ "$1" == "$(printf '%s\n%s\n' "$1" "$2" | sort -V | tail -n1)" ]]
}

# This check is intentionally scoped to the Tenable 8.5.x finding.
if ! vergte "$version" "8.5.0" || ! verlte "$version" "8.5.22"; then
  echo "PATCHED - Tomcat version $version is outside the vulnerable 8.5.0-8.5.22 range for this finding"
  exit 0
fi

check_readonly_false() {
  local f
  for f in "$BASE/conf/web.xml" "$BASE"/webapps/*/WEB-INF/web.xml; do
    [[ -f "$f" ]] || continue
    if awk 'BEGIN{RS="</servlet>"; IGNORECASE=1}
      /<servlet-name>[[:space:]]*default[[:space:]]*<\/servlet-name>/ &&
      /<param-name>[[:space:]]*readonly[[:space:]]*<\/param-name>/ &&
      /<param-value>[[:space:]]*false[[:space:]]*<\/param-value>/ {found=1}
      END{exit(found?0:1)}' "$f"; then
      echo "$f"
      return 0
    fi
  done
  return 1
}

if hit="$(check_readonly_false)"; then
  echo "VULNERABLE - Tomcat $version is in range and writable DefaultServlet configuration was found in $hit"
  exit 1
fi

echo "UNKNOWN - Tomcat $version is in the affected range, but writable DefaultServlet PUT was not confirmed in scanned web.xml files"
exit 3
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, pull every Tomcat host in 8.5.0-8.5.22, then separate internet- or proxy-reachable instances from internal-only ones and verify whether PUT is actually writable. Because this CVE is KEV-listed, the normal HIGH mitigation window is overridden: apply a temporary block or config kill-switch immediately, within hours under the noisgate mitigation SLA, then move all confirmed affected systems to Tomcat 8.5.23 or a vendor backport within the noisgate remediation SLA of ≤180 days; any exposed host with writable PUT should be treated as an emergency change and hunted for JSP web shells the same day.

Sources

  1. Tenable plugin 103698
  2. Apache Tomcat 8 security page
  3. NVD CVE-2017-12617
  4. CISA KEV catalog (print view)
  5. Ubuntu CVE page for backports
  6. Security Risk Advisors analysis
  7. Alphabot analysis
  8. LAC JSOC report discussing attacks and mining activity
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.