← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:17694 · Disclosed 2006-08-14

Apache on Windows mod_alias URL Validation Canonicalization CG

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

This is a spare key hidden behind three locked doors

This issue tracks to CVE-2006-4110: Apache HTTP Server on Windows can disclose CGI script source code when a request uses different path casing to slip past a case-sensitive ScriptAlias match on a case-insensitive filesystem. In practice, the vulnerable condition is narrow: the server must be running Apache in the affected range cited by the CVE, must be on Windows, must expose CGI, and must have the CGI directory mapped in a way that leaves the same files reachable as ordinary web content.

Tenable's MEDIUM label is already conservative, and in enterprise reality I'd push it down to LOW. The biggest downward pressure is deployment friction: modern estates rarely run Apache CGI on Windows, and even fewer keep CGI content under DocumentRoot with the exact aliasing mistake this bug needs. If it does trigger, the impact can still matter because source disclosure can leak credentials, hard-coded paths, and business logic, but the reachable population is tiny.

"Real risk exists only on a narrow, nondefault Windows CGI setup; this is patch hygiene, not a fire drill."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find an Apache-on-Windows CGI target with curl or Nessus

The attacker first needs a public-facing Apache server running on Windows and serving CGI content. Tenable detects this remotely by probing web behavior rather than relying only on version banners, which matters because the bug is configuration-dependent.
Conditions required:
  • Public HTTP(S) reachability
  • Apache HTTP Server deployed on Windows
  • CGI content exposed through ScriptAlias or equivalent mapping
Where this breaks in practice:
  • Apache-on-Windows is a small minority of exposed Apache deployments
  • Many estates no longer use CGI at all
  • Version banners do not prove the misconfiguration exists
Detection/coverage: Nessus plugin 17694 performs remote detection for this pattern; generic inventory scanners usually cannot infer the dangerous ScriptAlias/filesystem layout from banners alone.
STEP 02

Send alternate-case path requests with curl or Burp

The exploit is trivial once the setup exists: request the CGI path using changed casing such as /CGI-BIN/script.cgi instead of /cgi-bin/script.cgi. On Windows, the filesystem still resolves the file, but the case-sensitive alias handling can fail to mark it for CGI execution.
Conditions required:
  • URL path must be case-variant but still map to the same file on disk
  • The CGI directory must be reachable as normal web content due to placement or mapping
Where this breaks in practice:
  • If CGI is outside DocumentRoot, the bug path usually dies immediately
  • If admins used <Directory> with SetHandler and ExecCGI, the bypass value collapses
Detection/coverage: Look for mixed-case requests to CGI paths in web logs, especially repeated probes against /cgi-bin/ variants. WAF coverage is inconsistent because the request is syntactically normal.
STEP 03

Receive source code instead of execution

Instead of executing the CGI, Apache returns the underlying script source as a file. That turns an execution endpoint into an information disclosure primitive, often exposing credentials, SQL queries, file paths, API keys, or helper routines that enable follow-on compromise.
Conditions required:
  • The target CGI script must contain material of operational value
  • The web server must return the file rather than deny access
Where this breaks in practice:
  • Some CGI scripts are thin wrappers with little secret material
  • Mature apps may store secrets outside script files
Detection/coverage: HTTP responses containing raw Perl, Python, or shell CGI source where normal execution should occur are strong evidence. Content inspection or proxy logs can catch unusually large text responses from CGI endpoints.
STEP 04

Pivot using the leaked code

The real damage is indirect: attackers mine the disclosed source for database credentials, internal endpoints, trust assumptions, and hidden admin functions. This is often a setup bug that makes later exploitation easier rather than a one-shot compromise by itself.
Conditions required:
  • Leaked source must contain reusable secrets or logic flaws
  • Attacker must have a second path to exploit what they learned
Where this breaks in practice:
  • No direct code execution from this CVE alone
  • Impact varies wildly with script quality and secret handling
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo evidence of active exploitation found in authoritative sources reviewed; not listed in CISA KEV.
Proof-of-concept availabilityPublic details have existed since August 2006 via Bugtraq/SecurityFocus, and exploitation is mechanically simple with curl once the misconfiguration exists.
EPSSA Vulners mirror of FIRST EPSS data reports 0.17318. Treat that cautiously here: EPSS models internet exploitation likelihood, but this CVE's real limiter is rare deployment shape, not exploit complexity.
KEV statusAbsent from the official CISA Known Exploited Vulnerabilities Catalog.
CVSS viewNVD carries CVSS v2 4.3 / Medium AV:N/AC:M/Au:N/C:P/I:N/A:N; Tenable also shows CVSS v3 5.6 / Medium with high attack complexity. Either way, the scoring already signals this is *not* broadly weaponizable.
Affected versionsAuthoritative CVE text says Apache 2.2.2 on Windows. Third-party aggregation also associates Windows 2.0.58/2.2.3 records, but the safest read is: trust the CVE description and verify locally before broad scoping.
Fixed / safe configurationTenable's remediation is reconfigure so CGI is outside DocumentRoot. Apache's own docs also say that if CGI must live under web-accessible paths, use a proper <Directory> block with SetHandler/ExecCGI rather than relying on ScriptAlias alone.
Exposure populationShodan's generic apache server report shows only about 3,853 Windows systems among a much larger Apache population. That still overstates this CVE, because internet-wide search engines cannot see the required ScriptAlias-inside-web-root misconfiguration.
Disclosure timelineBugtraq discussion landed in August 2006; NVD shows published 2006-08-14.
Reporter / researcherThe public discussion is attributed to Susam Pal; VulDB ties the disclosure to Susam Pal / Infosys Technologies Ltd.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to LOW (2.8/10)

The decisive factor is deployment narrowness: this needs Apache on Windows, CGI enabled, and a specific aliasing/layout mistake that many enterprises simply do not have. Even where present, the CVE is source disclosure, so business impact depends on what secrets happen to be embedded in the exposed scripts rather than delivering immediate code execution on its own.

HIGH Attack preconditions are unusually narrow and nondefault
MEDIUM Affected version scoping beyond `2.2.2 on Windows` is inconsistent across secondary sources

Why this verdict

  • Requires a rare platform/config combo: Apache on Windows is already a minority case, and this bug further requires CGI plus a ScriptAlias layout that leaves the same files reachable as ordinary content.
  • Post-exploit value is variable: the CVE itself discloses source; it does not directly grant code execution, auth bypass, or system compromise.
  • No modern threat signal: no KEV listing and no current exploitation evidence materially reduce urgency compared with internet-facing Apache bugs that are being mass-scanned today.

Why not higher?

This is not a broad unauthenticated RCE on a mainstream exposed service. Every extra prerequisite compounds downward pressure: Windows-only, CGI-dependent, and configuration-dependent means the reachable population collapses fast, and the direct impact is limited to source disclosure.

Why not lower?

I would not mark this IGNORE because when the bad layout exists, exploitation is straightforward and can leak real secrets from production CGI scripts. Source code disclosure on an internet-facing app can still become the first domino for credential theft or secondary app compromise.

05 · Compensating Control

What to do — in priority order.

  1. Move CGI outside DocumentRoot — This kills the bug at its root by preventing alternate URL mappings from reaching the same script as static content. For a LOW finding there is no mitigation SLA; handle it as backlog hygiene in the next normal web-server maintenance cycle.
  2. Replace ScriptAlias-only handling with explicit <Directory> controls — If you must keep CGI under a web-accessible tree, use <Directory>, SetHandler cgi-script, and Options ExecCGI so execution policy is tied to filesystem location, not just URL mapping. Again, this is backlog hygiene rather than an emergency change.
  3. Hunt for mixed-case CGI requests — Review web logs and reverse-proxy logs for requests like /CGI-BIN/ or other case-flipped CGI paths. This is cheap validation that helps separate theoretical exposure from actual probing.
  4. Retire Apache-on-Windows CGI where possible — The best long-term control is to eliminate the small but brittle legacy pattern this CVE lives in. Fold this into normal platform modernization work rather than emergency patching.
What doesn't work
  • A banner-only version check does not prove vulnerability, because exposure depends on filesystem behavior and local alias configuration.
  • A generic WAF rule for 'bad characters' is weak here, because the exploit request can be a normal-looking alternate-case path.
  • Simply upgrading unrelated app code does nothing if the Apache layout still exposes CGI files as ordinary content.
06 · Verification

Crowdsourced verification payload.

Run this on the target Windows host that has Apache installed. Invoke it from an elevated PowerShell prompt with an explicit config path, for example: powershell -ExecutionPolicy Bypass -File .\check-cve-2006-4110.ps1 -ConfigPath 'C:\Apache2\conf\httpd.conf'; local read access to Apache config files is required, and elevation helps if the install is under protected paths.

noisgate-verify.ps1
POWERSHELLREAD-ONLYSAFE
# check-cve-2006-4110.ps1

# Detect likely exposure to CVE-2006-4110 on Apache/Windows.

# Logic:

#  - confirm Windows host

#  - parse Apache version from httpd.exe if available

#  - read httpd.conf and simple Include files if they exist beside it

#  - extract DocumentRoot and ScriptAlias / ScriptAliasMatch targets

#  - flag VULNERABLE when Apache version is 2.2.2 and a ScriptAlias target resolves under DocumentRoot

# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN


param(
    [Parameter(Mandatory=$true)]
    [string]$ConfigPath
)

function Out-Result {
    param([string]$State, [int]$Code, [string]$Message)
    Write-Output $State
    if ($Message) { Write-Output $Message }
    exit $Code
}

function Normalize-PathString {
    param([string]$PathValue)
    if ([string]::IsNullOrWhiteSpace($PathValue)) { return $null }
    $p = $PathValue.Trim().Trim('"').Trim("'")
    $p = $p -replace '/', '\\'
    return $p.TrimEnd('\\')
}

function Try-Resolve-FullPath {
    param([string]$BaseDir, [string]$PathValue)
    try {
        $p = Normalize-PathString $PathValue
        if (-not $p) { return $null }
        if ([System.IO.Path]::IsPathRooted($p)) {
            return [System.IO.Path]::GetFullPath($p)
        }
        return [System.IO.Path]::GetFullPath((Join-Path $BaseDir $p))
    } catch {
        return $null
    }
}

if (-not $IsWindows) {
    Out-Result -State 'UNKNOWN' -Code 2 -Message 'This check is intended for Windows Apache hosts only.'
}

if (-not (Test-Path -LiteralPath $ConfigPath)) {
    Out-Result -State 'UNKNOWN' -Code 2 -Message "Config file not found: $ConfigPath"
}

$configDir = Split-Path -Parent $ConfigPath
$serverRoot = Split-Path -Parent $configDir

# Load main config plus simple Include / IncludeOptional entries.

$files = New-Object System.Collections.Generic.List[string]
$files.Add((Resolve-Path -LiteralPath $ConfigPath).Path)

try {
    $seedContent = Get-Content -LiteralPath $ConfigPath -ErrorAction Stop
    foreach ($line in $seedContent) {
        $trim = $line.Trim()
        if ($trim -match '^(?i)\s*Include(?:Optional)?\s+(.+)$') {
            $incRaw = $Matches[1].Trim().Trim('"').Trim("'")
            $incRaw = $incRaw -replace '/', '\\'
            $incPath = $incRaw
            if (-not [System.IO.Path]::IsPathRooted($incPath)) {
                $incPath = Join-Path $serverRoot $incPath
            }
            $expanded = Get-ChildItem -Path $incPath -File -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName
            foreach ($f in $expanded) {
                if (-not $files.Contains($f)) { $files.Add($f) }
            }
        }
    }
} catch {
    Out-Result -State 'UNKNOWN' -Code 2 -Message "Unable to read config: $($_.Exception.Message)"
}

$allLines = foreach ($f in $files) {
    try { Get-Content -LiteralPath $f -ErrorAction Stop } catch { }
}

$allLines = $allLines | Where-Object { $_ -notmatch '^\s*#' }

# Extract DocumentRoot.

$documentRootRaw = $null
foreach ($line in $allLines) {
    if ($line -match '^(?i)\s*DocumentRoot\s+(.+)$') {
        $documentRootRaw = $Matches[1]
        break
    }
}

if (-not $documentRootRaw) {
    Out-Result -State 'UNKNOWN' -Code 2 -Message 'DocumentRoot not found in config.'
}

$documentRoot = Try-Resolve-FullPath -BaseDir $serverRoot -PathValue $documentRootRaw
if (-not $documentRoot) {
    Out-Result -State 'UNKNOWN' -Code 2 -Message 'Could not resolve DocumentRoot path.'
}

# Extract ScriptAlias targets.

$scriptTargets = New-Object System.Collections.Generic.List[string]
foreach ($line in $allLines) {
    if ($line -match '^(?i)\s*ScriptAlias\s+"?[^"]+"?\s+(.+)$') {
        $target = $Matches[1].Trim().Split()[0]
        $resolved = Try-Resolve-FullPath -BaseDir $serverRoot -PathValue $target
        if ($resolved) { $scriptTargets.Add($resolved) }
    } elseif ($line -match '^(?i)\s*ScriptAliasMatch\s+"?[^"]+"?\s+(.+)$') {
        $target = $Matches[1].Trim().Split()[0]
        $resolved = Try-Resolve-FullPath -BaseDir $serverRoot -PathValue $target
        if ($resolved) { $scriptTargets.Add($resolved) }
    }
}

if ($scriptTargets.Count -eq 0) {
    Out-Result -State 'PATCHED' -Code 0 -Message 'No ScriptAlias or ScriptAliasMatch directives found; this specific CVE pattern is not present.'
}

# Try to identify Apache version.

$httpdExe = $null
$binCandidate = Join-Path $serverRoot 'bin\httpd.exe'
if (Test-Path -LiteralPath $binCandidate) { $httpdExe = $binCandidate }

$versionString = $null
if ($httpdExe) {
    try {
        $vout = & $httpdExe -v 2>$null
        foreach ($line in $vout) {
            if ($line -match 'Apache/([0-9]+\.[0-9]+\.[0-9]+)') {
                $versionString = $Matches[1]
                break
            }
        }
    } catch { }
}

$underDocRoot = @()
foreach ($t in $scriptTargets | Select-Object -Unique) {
    if ($t.ToLowerInvariant().StartsWith($documentRoot.ToLowerInvariant() + '\\') -or $t.ToLowerInvariant() -eq $documentRoot.ToLowerInvariant()) {
        $underDocRoot += $t
    }
}

if ($underDocRoot.Count -eq 0) {
    Out-Result -State 'PATCHED' -Code 0 -Message 'ScriptAlias targets do not resolve under DocumentRoot; the known source-disclosure layout was not found.'
}

if (-not $versionString) {
    $msg = 'ScriptAlias target(s) under DocumentRoot detected, but Apache version could not be confirmed. Review manually. Paths: ' + ($underDocRoot -join ', ')
    Out-Result -State 'UNKNOWN' -Code 2 -Message $msg
}

if ($versionString -eq '2.2.2') {
    $msg = 'Apache 2.2.2 on Windows with ScriptAlias target(s) under DocumentRoot detected. Paths: ' + ($underDocRoot -join ', ')
    Out-Result -State 'VULNERABLE' -Code 1 -Message $msg
}

$msg = "Apache version $versionString detected. Risky layout exists (ScriptAlias under DocumentRoot), but the canonical CVE text points to 2.2.2 on Windows. Treat config as unsafe even if the precise CVE may not apply. Paths: " + ($underDocRoot -join ', ')
Out-Result -State 'PATCHED' -Code 0 -Message $msg
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, do not burn an emergency patch window on this one unless you already know you still run legacy Apache CGI on Windows. For a LOW finding there is no noisgate mitigation SLA and no formal noisgate remediation SLA; treat it as backlog hygiene: inventory any Apache-on-Windows instances, run the config check, and if you find CGI paths under DocumentRoot, clean up the layout in the next normal web-server maintenance cycle or retire the stack entirely.

Sources

  1. Tenable Nessus Plugin 17694
  2. NVD CVE-2006-4110
  3. Apache mod_alias documentation
  4. CISA Known Exploited Vulnerabilities Catalog
  5. FIRST EPSS overview
  6. FIRST EPSS API documentation
  7. Vulners CVE-2006-4110 entry
  8. Shodan generic Apache exposure report
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.