This finding is a smoke alarm for an old engine, not proof the building is already on fire
Tenable plugin 34460 is not a CVE and does not prove a working exploit on its own. It remotely fingerprints a web service, largely from the HTTP Server response header and related web fingerprinting dependencies, then flags versions or product families Tenable considers obsolete or unsupported. The affected range is therefore product-specific and generic at the same time: anything the plugin maps to an end-of-support branch, including examples shown in the NASL logic such as legacy IIS (7.0/7.5), Oracle Application Server 9.x/10.1.2.x, and older legacy server families; Apache handling was later split into separate end-of-life plugins.
Tenable's Critical 10.0 label is a policy score for unsupported software, not a measurement of exploitability for a concrete flaw. In real operations, that overstates urgency because the attack chain still requires a second step: an attacker must find a real, applicable vulnerability for the exact server build, and banner-based version checks can be wrong in environments using distro backports, reverse proxies, or sanitized headers. That said, the finding is still worth fixing because an internet-facing EOL web server is a standing invitation for opportunistic follow-on exploitation.
4 steps from start to impact.
Reach the HTTP service
- Target web service is reachable from the attacker's network position
- Port is exposed directly or through a load balancer/reverse proxy
- Internal-only web servers already imply post-initial-access
- WAFs, reverse proxies, or CDNs may front the origin and hide the actual server
Fingerprint the server family and version
34460 uses http_version.nasl, www_fingerprinting_hmap.nasl, and banner parsing to infer the web server type and version. If the Server header advertises an obsolete branch, Tenable raises the finding. This is reconnaissance, not proof of a reachable bug.- Server reveals a banner or enough fingerprinting traits
- Tenable's mapping includes that product/version family
- Hidden or rewritten headers produce
UNKNOWN, not certainty - Reverse proxies can expose the proxy version instead of the origin
- Linux distro backports can leave an old-looking upstream version string while still shipping security fixes
Match a real exploit to the exact platform
- The flagged product is genuinely EOL and not merely banner-noisy
- A usable vulnerability exists for that exact branch and feature set
- No single exploit or PoC maps to this plugin because it is not a single vulnerability
- Feature-dependent bugs may require specific modules, request paths, or auth states
- EDR, WAF, and application logging may catch exploit attempts even if the server is old
Exploit follow-on weakness for impact
- A reachable, unmitigated server flaw exists
- The web server has meaningful trust or data access
- Segmentation, secret management, and least privilege can sharply reduce blast radius
- Containerization or isolated service accounts may keep compromise local to one tier
The supporting signals.
| What this actually is | A Tenable unsupported-software detection, not a single software flaw. The plugin page shows no CVE mapping and explicitly says the score is based on Tenable's standard unsupported software rationale. |
|---|---|
| Vendor severity baseline | Official Tenable page currently labels plugin 34460 as Critical / CVSS 10.0 with vector CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H, which is a generic policy score rather than exploit-specific evidence. |
| Detection method | Remote-only fingerprinting. Tenable lists dependencies http_version.nasl, peercast_installed.nasl, and www_fingerprinting_hmap.nasl; the mirrored NASL shows matching against the HTTP Server response header and related fingerprints. |
| Affected version ranges | There is no single version range. The NASL contains product-specific mappings for legacy server families, including examples like Microsoft-IIS/7.0 and 7.5, Oracle Application Server 9.0.2.x, 9.0.3.x, 9.0.4.x, 10.1.2.x, and multiple dead product lines such as Netscape/iPlanet/CERN/Sambar/Sami/Savant. |
| Apache caveat | The mirrored NASL explicitly states Apache was removed in favor of new SEoL plugins, so 34460 is already a coarse legacy umbrella detector rather than the authoritative source for all web-server EOL conditions. |
| Fixed version | There is no universal patched version. Remediation is to move each affected server to a vendor-supported branch or decommission it; distros may also ship supported backported packages that retain older upstream version strings. |
| Backport / false-positive risk | Official Ubuntu and Red Hat guidance both document security backports. That means a scanner doing simple version matching can overstate risk if it does not understand distro release metadata or if the banner reflects upstream versioning rather than package release state. |
| In-the-wild / KEV status | No KEV-applicable entry for this plugin itself because it is not tied to a CVE. Unsupported status can still shelter old exploitable bugs, but KEV evidence must be evaluated against the underlying real product/CVE after validation. |
| PoC availability | There is no single PoC for plugin 34460. Public exploits may exist for specific obsolete server products or modules, but that is a second-stage assessment after you confirm the exact product and branch. |
| Disclosure / maintenance | Plugin published 2008-10-21 and updated 2023-02-10. That long lifespan is another sign this is a standing hygiene detector, not an emergent zero-day. |
noisgate verdict.
The decisive factor is that this finding requires a follow-on exploit that is not identified by the plugin. Unsupported status matters, but a generic banner-based EOL detection is not the same thing as a remotely weaponized vulnerability with known exploitation evidence.
Why this verdict
- Not a CVE: the plugin identifies unsupported software condition, not a named exploitable flaw.
- Attack path requires a second win: an attacker still needs reachability, accurate fingerprinting, and a real product-specific exploit for the exact build and modules.
- Reachability narrows reality fast: internal-only web servers are already post-initial-access, and internet-facing ones may still be hidden behind CDNs, reverse proxies, or WAFs.
- Scanner logic is coarse: the plugin relies heavily on remote version/banner inference, which is exactly where distro backports and proxy headers create noise.
- Why not ignore it entirely: if the origin really is EOL and exposed, the future bug pipeline is effectively permanent because the vendor has stopped shipping fixes.
Why not higher?
There is no confirmed exploit path, no KEV evidence for the finding itself, and no proof that the origin service—not just a fronting proxy—actually runs an unsupported branch. A Critical label only makes sense once you can tie the host to a concrete, reachable CVE or active exploitation signal.
Why not lower?
This is still a public-attack-surface hygiene problem, especially for externally reachable web tiers. Unsupported web servers tend to accumulate unfixed exposure over time, and once a real bug appears there may be no vendor patch path at all.
What to do — in priority order.
- Validate the banner finding — Confirm whether the flagged
Serverheader belongs to the origin server or a proxy/CDN and whether the package is truly unsupported versus distro-backported. For a LOW verdict there is no SLA; treat this as backlog hygiene and close false positives before escalating engineering effort. - Inventory the real web stack — Map each hit to the actual product, package source, and support contract state, including extended support where applicable. For LOW, there is no SLA; fold this into normal asset hygiene and lifecycle management rather than incident-style response.
- Reduce origin exposure — Keep legacy origins behind reverse proxies, CDNs, or internal-only network paths where possible so unsupported software is not directly internet-reachable. For LOW, there is no SLA; do this as part of standard surface-reduction work.
- Harden the web tier account — Limit service-account privileges, strip local admin/root, rotate embedded credentials, and isolate backend access so a future web-server exploit does not become instant domain-wide blast radius. For LOW, there is no SLA; schedule it with normal platform hardening.
- Plan lifecycle replacement — Move confirmed EOL products onto supported branches or supported vendor channels, including distro-supported packages if that is your standard. For LOW, there is no SLA; keep it in backlog hygiene unless a concrete CVE or exploitation signal appears.
- Simply hiding the
Serverheader does not solve the underlying support-status problem; it only reduces one fingerprinting signal. - Treating the Tenable
10.0as if it were a real exploit score does not help prioritization; it inflates generic lifecycle debt above active, weaponized vulnerabilities. - Relying on upstream version strings alone does not work on RHEL/Ubuntu-style backported packages; you need distro package release metadata or vendor support evidence.
Crowdsourced verification payload.
Run this from an auditor workstation or scanner host with network access to the target URL. Invoke it as python3 verify_34460.py https://app.example.com or python3 verify_34460.py --server-header "Microsoft-IIS/7.5"; no privileges are required.
#!/usr/bin/env python3
# verify_34460.py
# Purpose: sanity-check Tenable plugin 34460 by looking at a remote HTTP Server header
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=USAGE/ERROR
import argparse
import re
import sys
import ssl
import urllib.request
LEGACY_PATTERNS = [
(r'^Microsoft-IIS/7\.0$', 'IIS 7.0 is EOL with its underlying OS lifecycle'),
(r'^Microsoft-IIS/7\.5$', 'IIS 7.5 is EOL with its underlying OS lifecycle'),
(r'^Oracle-Application-Server-9i/9\.0\.2', 'Oracle Application Server 9.0.2.x is legacy/EOL'),
(r'^Oracle-Application-Server-9i/9\.0\.3', 'Oracle Application Server 9.0.3.x is legacy/EOL'),
(r'^Oracle-Application-Server-10g/9\.0\.4', 'Oracle Application Server 9.0.4.x is legacy/EOL'),
(r'^Oracle-Application-Server-10g/10\.1\.2', 'Oracle Application Server 10.1.2.x is legacy/EOL'),
(r'^(CERN httpd |CERN/)', 'CERN httpd is obsolete'),
(r'(Apache|Mod_)JServ/', 'Apache JServ is obsolete'),
(r'^NCSA/[1-9]', 'NCSA HTTPd is obsolete'),
(r'^SAMBAR', 'Sambar Server is obsolete'),
(r'Sami HTTP Server', 'Sami HTTP Server is obsolete'),
(r'^Savant/', 'Savant Web Server is obsolete'),
(r'iPlanet|Netscape|Sun-Java-System-Web-Server/|Sun Java System Web Server/|Sun-ONE-Web-Server/|SunONE WebServer ', 'Legacy Netscape/iPlanet/Sun ONE family is obsolete'),
]
SUPPORTED_HINTS = [
(r'^Microsoft-IIS/(8\.0|8\.5|10\.0)$', 'Header advertises a supported-or-newer IIS family than the ones explicitly flagged in plugin 34460'),
(r'^nginx/', 'NGINX header seen; plugin 34460 is generic and cannot prove unsupported status from this alone'),
(r'^Apache/', 'Apache header seen; Apache support status is handled by separate Tenable SEoL plugins, not reliably by 34460 alone'),
]
def fetch_server_header(url: str, timeout: int = 10):
ctx = ssl.create_default_context()
req = urllib.request.Request(url, method='HEAD', headers={'User-Agent': 'verify_34460/1.0'})
try:
with urllib.request.urlopen(req, timeout=timeout, context=ctx) as resp:
return resp.headers.get('Server')
except Exception:
try:
req = urllib.request.Request(url, method='GET', headers={'User-Agent': 'verify_34460/1.0'})
with urllib.request.urlopen(req, timeout=timeout, context=ctx) as resp:
return resp.headers.get('Server')
except Exception:
return None
def assess(header: str):
if not header:
return ('UNKNOWN', 'No Server header obtained; banner-based validation is inconclusive')
header = header.strip()
for pattern, reason in LEGACY_PATTERNS:
if re.search(pattern, header, re.IGNORECASE):
return ('VULNERABLE', f'{reason}; observed header: {header}')
for pattern, reason in SUPPORTED_HINTS:
if re.search(pattern, header, re.IGNORECASE):
return ('PATCHED', f'{reason}; observed header: {header}')
return ('UNKNOWN', f'Header observed but not in this plugin-specific legacy map: {header}')
def main():
parser = argparse.ArgumentParser(description='Sanity-check Tenable plugin 34460 using a remote Server header or a supplied header string.')
parser.add_argument('url', nargs='?', help='Target URL, e.g. https://app.example.com')
parser.add_argument('--server-header', dest='server_header', help='Server header string to test directly, e.g. "Microsoft-IIS/7.5"')
args = parser.parse_args()
if not args.url and not args.server_header:
print('UNKNOWN - provide a URL or --server-header')
sys.exit(3)
header = args.server_header
if not header:
header = fetch_server_header(args.url)
status, detail = assess(header)
print(f'{status} - {detail}')
if status == 'PATCHED':
sys.exit(0)
elif status == 'VULNERABLE':
sys.exit(1)
else:
sys.exit(2)
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.