← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:202577 · Disclosed 2024-07-18

Apache 2

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

This is less a crowbar at the front door and more a mislabeled master key left in an old side cabinet

tenable:202577 is really a *bundle* around Apache HTTP Server < 2.4.62, but for hosts specifically on 2.4.60 or 2.4.61 the live issues are narrower than the title suggests. The big one for most estates is CVE-2024-40725: a regression in the 2.4.61 fix path where legacy handler mapping via AddType can cause indirect requests to return local source code instead of executing it. The second is CVE-2024-40898: a *Windows-only* mod_rewrite SSRF issue in server/vhost context that can leak NTLM material to an attacker-controlled host. Upstream fixed both in 2.4.62, while distro backports shipped separate fixed package builds.

Tenable calling this MEDIUM is basically right. The raw CVSS picture looks scarier because both bugs are network-reachable and unauthenticated on paper, but the real-world attack surface narrows fast: 40725 needs legacy content-type handler wiring that many modern php-fpm/SetHandler deployments no longer use, and 40898 only matters on Windows Apache with specific rewrite placement. That is not a zero-day fire drill across a 10,000-host estate; it is a targeted cleanup item with a short list of high-risk exceptions.

"Patch it, but don't stop the line: real risk hinges on legacy AddType configs or Windows-only rewrite SSRF."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Fingerprint version and config style

An attacker starts with plain banner and behavior recon using tools like curl, httpx, or Nessus/Tenable version checks to find Apache 2.4.60 or 2.4.61. That only identifies *candidate* hosts; actual exploitability depends on config patterns such as legacy AddType handler mapping or Windows mod_rewrite in server/vhost context.
Conditions required:
  • HTTP(S) reachability to the target
  • Apache version in the affected range or banner disclosure
  • A way to infer or guess application routing paths
Where this breaks in practice:
  • Version scanners are mostly banner/package based and cannot prove the risky config exists
  • Many enterprise fleets run backported distro packages that look old but are patched
  • Modern stacks often use php-fpm/SetHandler instead of the legacy AddType path
Detection/coverage: Good scanner coverage for version-only detection; poor coverage for actual config-gated exploitability. Expect false positives from banner checks and package naming.
STEP 02

Trigger legacy handler disclosure with curl

For CVE-2024-40725, the attacker sends an indirect request that reaches a file normally meant to be handled, not served, and relies on legacy AddType behavior. If the site still wires handlers this old way, Apache can hand back source instead of invoking the interpreter, exposing PHP or similar application code.
Conditions required:
  • Target is 2.4.60 or 2.4.61
  • Legacy AddType or similar content-type handler config is present
  • A reachable indirect request path exists to the protected script/content
Where this breaks in practice:
  • Requires a very specific and aging configuration pattern
  • Many apps sit behind reverse proxies, frameworks, or routing layers that break the exploit path
  • Even vulnerable servers may expose only low-value files, not credential-bearing code
Detection/coverage: WAFs may log the probing URI, but there is no universal signature. Web access logs and unusual requests for script source paths are your best signal.
STEP 03

Abuse Windows rewrite SSRF with Responder

For CVE-2024-40898, the attacker uses crafted requests against Windows Apache where mod_rewrite is configured in server/vhost context, forcing outbound access to an attacker-controlled destination. A tool like Responder or an SMB/HTTP listener then captures NTLM authentication material leaked by the server.
Conditions required:
  • Target runs Apache on Windows
  • mod_rewrite is active in server/vhost context
  • Outbound SMB/HTTP from the server to attacker infrastructure is allowed
Where this breaks in practice:
  • Windows Apache is a minority footprint in most enterprise web estates
  • Egress filtering, NTLM hardening, and SMB restrictions often break the leak path
  • This is credential exposure, not immediate server RCE
Detection/coverage: Network controls can catch outbound SMB/UNC attempts; Windows eventing, proxy logs, and egress monitoring are better than web scanning here.
STEP 04

Turn disclosure into follow-on access

The attacker monetizes what they got: source code from 40725 can reveal secrets, database credentials, internal URLs, or admin paths; NTLM material from 40898 can feed relay or cracking workflows. The vulnerability itself is rarely the finish line; it is a springboard into the app or adjacent infrastructure.
Conditions required:
  • Exposed source contains reusable secrets or sensitive logic, or leaked NTLM is usable
  • The organization lacks secret rotation or network segmentation that contains follow-on abuse
Where this breaks in practice:
  • Well-managed apps store secrets off-box or in managed identity systems
  • NTLM material may be protected by signing, EPA, or simply be low-value service creds
  • Leaked code without credential reuse often yields only reconnaissance value
Detection/coverage: Look for immediate secret-use anomalies, auth attempts using service accounts, and outbound connections to unusual internal resources after web probing.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo solid evidence of active exploitation found. CISA KEV does not list CVE-2024-40725 or CVE-2024-40898, and a Censys advisory said there was no known active exploitation at publication time.
Proof-of-concept availabilityPublic code exists at TAM-K592/CVE-2024-40725-CVE-2024-40898. Treat it as a capability signal, not trusted analysis; the repo text misstates portions of the bugs, but it confirms public attacker interest.
EPSSGitHub’s advisory for CVE-2024-40898 shows EPSS from FIRST at 0.735% (73rd percentile): GHSA-f6mg-hq7f-jw2j. That is not nothing, but it is nowhere near the threat profile of routinely weaponized edge bugs.
KEV status and datesAs of 2025-06-01, neither CVE appears in the CISA KEV catalog. No federal emergency patch signal here.
CVSS reality checkCVE-2024-40725 is NVD 5.3 / CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N: confidentiality-only source disclosure. CVE-2024-40898 is NVD 7.5, with GitHub showing the CISA-ADP-style 9.1 view, but it is *Windows-only* and still mainly a credential-leak path, not direct code execution.
Affected version rangesUpstream says 40725 affects 2.4.60 through 2.4.61, while 40898 affects 2.4.0 through 2.4.61 on Windows. For this Tenable finding, your practical focus is hosts on 2.4.60 or 2.4.61.
Fixed versions and backportsUpstream fix is 2.4.62. Backported distro fixes exist, including Ubuntu 24.04 2.4.58-1ubuntu8.4, 22.04 2.4.52-1ubuntu4.12, 20.04 2.4.41-4ubuntu3.21 and Debian bullseye 2.4.62-1~deb11u1, bookworm 2.4.67-1~deb12u2.
Scanning and exposure dataCensys published hunt queries for public-facing Apache 2.4.0-2.4.61. Useful for exposure scoping, but internet visibility alone overstates risk because exploitability depends on local config, OS, and egress posture.
Disclosure and attributionApache shipped 2.4.62 on 2024-07-17 per the ASF vulnerability page. CVE-2024-40725 was reported on 2024-07-09 as a regression from CVE-2024-39884; CVE-2024-40898 was reported on 2024-07-12 by Smi1e and xiaojunjie of DBAPPSecurity.
Detection caveatThis Tenable plugin is fundamentally a version match. It will not tell you whether the host actually uses legacy AddType, whether a Windows host has mod_rewrite in the risky context, or whether a distro package has backported the fix.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (5.4/10)

The decisive factor is configuration friction. The highest-risk paths require either aging legacy AddType handler behavior or the much smaller Windows Apache footprint with specific mod_rewrite placement, so the reachable population is materially smaller than the product’s install base.

HIGH Affected upstream version mapping and fixed version `2.4.62`
MEDIUM Real-world exploitability across mixed enterprise Apache deployments
MEDIUM Absence of broad in-the-wild exploitation evidence

Why this verdict

  • Downgrade pressure: CVE-2024-40898 is Windows-only. In most enterprise Apache estates, Windows httpd is a minority slice, so the scarier NTLM-leak path simply does not apply to most flagged servers.
  • Downgrade pressure: CVE-2024-40725 needs legacy handler wiring. You need AddType-style content-type handlers plus an indirect request path. That is old-school Apache plumbing, not the default shape of many modern php-fpm or reverse-proxied apps.
  • Downgrade pressure: this is mostly post-exposure enablement, not one-shot takeover. Source disclosure and NTLM leakage matter, but they still need follow-on abuse to become full compromise.
  • Why it stays MEDIUM: exploitation is still unauthenticated and remote. If the risky config exists on an internet-facing host, an attacker can pull code or coerce outbound auth without credentials.
  • Why it stays MEDIUM: Apache is common enough that niche configs still exist at scale. In a 10,000-host estate, even a low single-digit percentage of legacy setups is operationally meaningful.
  • Operational adjustment: banner-only findings overstate urgency. Start from Tenable’s MEDIUM baseline, then discount for Windows-only applicability, config prerequisites, and backport noise; that lands in the middle, not the top, of the patch queue.

Why not higher?

There is no confirmed KEV listing, no broad active exploitation signal, and no default-path unauthenticated RCE here. The exploit chain narrows quickly once you ask the practical questions: attacker position is remote, but the reachable population collapses around specific legacy or Windows-only configurations, and modern egress controls often blunt the SSRF/NTLM branch.

Why not lower?

I am not dropping this to LOW because the bugs are still remotely reachable and unauthenticated when the bad config is present. Source disclosure from a public app can expose secrets, framework internals, and credential material that convert into real incidents, and public PoC code means attackers do not need to invent the workflow from scratch.

05 · Compensating Control

What to do — in priority order.

  1. Audit for legacy AddType handlers — Search Apache configs for AddType or similar content-type-based handler mappings and replace them with explicit SetHandler/FilesMatch patterns where possible. There is no mitigation SLA for a MEDIUM verdict, but this is the right immediate control when patching has to wait; still aim to finish the actual patch inside the 365-day remediation window.
  2. Constrain Windows Apache egress — On Windows Apache hosts, block or tightly restrict outbound SMB/UNC and unnecessary outbound HTTP from the web tier so CVE-2024-40898 cannot leak NTLM to arbitrary destinations. Again, there is no mitigation SLA here; use this as a targeted risk reduction while you move those hosts to the patched build within the 365-day remediation window.
  3. Review mod_rewrite in server/vhost context — Identify Windows vhosts using mod_rewrite at server or virtual-host scope and verify no rewrite rules can trigger outbound fetches or UNC resolution. This is a small-population hardening task, not a fleet-wide emergency, but it closes the exact prerequisite that makes 40898 matter.
  4. Validate package backports before scheduling outages — For Debian/Ubuntu/SUSE/RHEL-style fleets, confirm whether your installed package already includes a vendor backport instead of trusting the bare upstream version string. That keeps you from burning change windows on hosts that are already fixed by distro packaging.
What doesn't work
  • A generic WAF policy does not reliably solve this because 40725 is about local handler mapping semantics and 40898 is about server-side rewrite/egr ess behavior; the control point is the server config, not just request filtering.
  • Version-only exception handling is dangerous in both directions: old-looking distro packages may already be fixed, while a clean 2.4.60 or 2.4.61 banner says nothing about whether the risky config is actually enabled.
  • MFA is irrelevant to the initial bug path because both issues are unauthenticated network attacks against the web tier, not user-login abuse.
06 · Verification

Crowdsourced verification payload.

Run this on the target Apache host, not from an auditor workstation. Invoke it as python3 apache_2462_check.py on Linux/macOS or py apache_2462_check.py on Windows; local admin/root is recommended so the script can read Apache config trees and execute httpd/apachectl introspection commands. It outputs exactly one of VULNERABLE, PATCHED, or UNKNOWN.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# Apache 2.4.60/2.4.61 check for Tenable plugin 202577 context
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

import os
import re
import sys
import glob
import shutil
import platform
import subprocess
from pathlib import Path

EXIT_PATCHED = 0
EXIT_VULN = 1
EXIT_UNKNOWN = 2


def run(cmd):
    try:
        p = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
        return p.returncode, (p.stdout or '') + (p.stderr or '')
    except Exception:
        return 999, ''


def find_httpd_binary():
    candidates = []
    if platform.system().lower().startswith('win'):
        candidates += [
            'httpd.exe',
            r'C:\\Apache24\\bin\\httpd.exe',
            r'C:\\Apache2\\bin\\httpd.exe',
        ]
    else:
        candidates += ['apache2ctl', 'apachectl', 'httpd', 'apache2']
        candidates += ['/usr/sbin/apache2ctl', '/usr/sbin/apachectl', '/usr/sbin/httpd', '/usr/sbin/apache2']

    for c in candidates:
        if os.path.isabs(c) and os.path.exists(c):
            return c
        found = shutil.which(c)
        if found:
            return found
    return None


def parse_version(text):
    m = re.search(r'Apache/(\d+)\.(\d+)\.(\d+)', text)
    if not m:
        return None
    return tuple(int(x) for x in m.groups())


def get_httpd_info(bin_path):
    version_out = ''
    v_out = ''
    for args in ([bin_path, '-v'], [bin_path, '-V']):
        rc, out = run(args)
        if args[-1] == '-v':
            version_out = out
        else:
            v_out = out
    return version_out, v_out


def parse_httpd_root(v_out):
    m = re.search(r'HTTPD_ROOT="([^"]+)"', v_out)
    return m.group(1) if m else None


def gather_config_candidates(v_out):
    paths = set()
    sysname = platform.system().lower()

    m = re.search(r'SERVER_CONFIG_FILE="([^"]+)"', v_out)
    server_cfg = m.group(1) if m else None
    httpd_root = parse_httpd_root(v_out)

    if server_cfg:
        p = Path(server_cfg)
        if not p.is_absolute() and httpd_root:
            p = Path(httpd_root) / server_cfg
        paths.add(str(p))

    if sysname.startswith('win'):
        roots = [httpd_root] if httpd_root else []
        roots += [r'C:\\Apache24', r'C:\\Apache2']
        for root in roots:
            if not root:
                continue
            for pat in [
                os.path.join(root, 'conf', 'httpd.conf'),
                os.path.join(root, 'conf', 'extra', '*.conf'),
                os.path.join(root, 'conf', 'vhosts', '*.conf'),
                os.path.join(root, 'conf', '**', '*.conf'),
            ]:
                for f in glob.glob(pat, recursive=True):
                    paths.add(f)
    else:
        pats = [
            '/etc/httpd/conf/httpd.conf',
            '/etc/httpd/conf.d/*.conf',
            '/etc/httpd/conf.modules.d/*.conf',
            '/etc/apache2/apache2.conf',
            '/etc/apache2/httpd.conf',
            '/etc/apache2/conf-enabled/*.conf',
            '/etc/apache2/mods-enabled/*.conf',
            '/etc/apache2/sites-enabled/*.conf',
            '/usr/local/etc/apache2/httpd.conf',
            '/usr/local/etc/apache2/extra/*.conf',
        ]
        for pat in pats:
            for f in glob.glob(pat, recursive=True):
                paths.add(f)

    # Expand include patterns from top-level files where possible.
    final_paths = set()
    to_process = list(paths)
    seen = set()
    include_re = re.compile(r'^\s*Include(?:Optional)?\s+(.+?)\s*$', re.I)

    while to_process:
        p = to_process.pop()
        if p in seen:
            continue
        seen.add(p)
        if os.path.isfile(p):
            final_paths.add(p)
            try:
                with open(p, 'r', encoding='utf-8', errors='ignore') as fh:
                    for line in fh:
                        m = include_re.match(line)
                        if not m:
                            continue
                        inc = m.group(1).strip().strip('"\'')
                        inc = os.path.expandvars(inc)
                        base = os.path.dirname(p)
                        if not os.path.isabs(inc):
                            inc = os.path.join(base, inc)
                        for g in glob.glob(inc, recursive=True):
                            if os.path.isfile(g):
                                to_process.append(g)
            except Exception:
                pass
    return sorted(final_paths)


def read_configs(paths):
    blobs = []
    for p in paths:
        try:
            with open(p, 'r', encoding='utf-8', errors='ignore') as fh:
                blobs.append((p, fh.read()))
        except Exception:
            pass
    return blobs


def has_legacy_addtype_risk(blobs):
    # High-signal but intentionally conservative.
    risky = []
    addtype_re = re.compile(r'^\s*AddType\s+\S+\s+.*\.(php\d*|phtml|phar|cgi|pl|py)(\s|$)', re.I | re.M)
    for p, text in blobs:
        if addtype_re.search(text):
            risky.append(p)
    return risky


def has_windows_rewrite_risk(blobs):
    risky = []
    load_rewrite = False
    for _p, text in blobs:
        if re.search(r'LoadModule\s+rewrite_module', text, re.I):
            load_rewrite = True
            break
    if not load_rewrite:
        return risky
    rewrite_re = re.compile(r'^\s*Rewrite(?:Engine|Rule|Cond)\b', re.I | re.M)
    vhost_re = re.compile(r'<VirtualHost\b', re.I)
    for p, text in blobs:
        if rewrite_re.search(text) and (vhost_re.search(text) or p.lower().endswith('httpd.conf')):
            risky.append(p)
    return risky


def main():
    httpd = find_httpd_binary()
    if not httpd:
        print('UNKNOWN')
        sys.exit(EXIT_UNKNOWN)

    version_out, v_out = get_httpd_info(httpd)
    version = parse_version(version_out + '\n' + v_out)
    if not version:
        print('UNKNOWN')
        sys.exit(EXIT_UNKNOWN)

    # For this plugin context:
    # >= 2.4.62 upstream is patched.
    # 2.4.60 / 2.4.61 need config review.
    # < 2.4.60 may still have other Apache CVEs, but falls outside this specific version gate.
    if version >= (2, 4, 62):
        print('PATCHED')
        sys.exit(EXIT_PATCHED)

    if version < (2, 4, 60):
        print('UNKNOWN')
        sys.exit(EXIT_UNKNOWN)

    configs = gather_config_candidates(v_out)
    blobs = read_configs(configs)
    if not blobs:
        print('UNKNOWN')
        sys.exit(EXIT_UNKNOWN)

    addtype_hits = has_legacy_addtype_risk(blobs)
    if addtype_hits:
        print('VULNERABLE')
        sys.exit(EXIT_VULN)

    if platform.system().lower().startswith('win'):
        rewrite_hits = has_windows_rewrite_risk(blobs)
        if rewrite_hits:
            print('VULNERABLE')
            sys.exit(EXIT_VULN)

    # Vulnerable version but no clear risky config found.
    print('UNKNOWN')
    sys.exit(EXIT_UNKNOWN)


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

If you remember one thing.

TL;DR
Monday morning, do not treat every 202577 hit as equal. First separate true upstream 2.4.60/2.4.61 from distro-backport noise, then split the remainder into two exception buckets: internet-facing hosts with legacy AddType handler mappings, and Windows Apache hosts with mod_rewrite plus outbound NTLM/SMB exposure. For this MEDIUM finding there is no noisgate mitigation SLA — go straight to the 365-day remediation window; use that window to move to 2.4.62+ or the vendor-backported fixed package, while cleaning up the small number of risky configs immediately in your normal change process.

Sources

  1. Tenable plugin 202577
  2. Apache HTTP Server 2.4 vulnerability page
  3. NVD CVE-2024-40725
  4. NVD CVE-2024-40898
  5. GitHub Advisory GHSA-f6mg-hq7f-jw2j / CVE-2024-40898
  6. Public PoC / checker repository
  7. Ubuntu CVE-2024-40725 fixed package matrix
  8. Debian tracker CVE-2024-40725
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.