This is a loaded nail gun locked inside a dusty closet, not a grenade rolling across the lobby
Tenable plugin 95874 flags PHP 5.6.x < 5.6.29 by banner and anchors on CVE-2016-9935, an out-of-bounds read / memory-corruption bug in PHP's ext/wddx parser when it handles an empty boolean element in a wddxPacket XML document. The same release also fixed an openssl_pbkdf2() crash bug (bug #72776, tied to CVE-2016-7132). Upstream fixed these in PHP 5.6.29 on 2016-12-08.
The vendor-style severity is inflated for most estates because the scary 9.8 score assumes the attacker can directly hit a vulnerable parsing path, but in reality they usually need a reachable application endpoint that feeds attacker-controlled XML into the deprecated WDDX extension. That extension was later deprecated and unbundled, which tells you how niche it became. So yes, old internet-facing PHP deserves attention, but this specific plugin is not a universal drop-everything critical unless you confirm real WDDX exposure.
4 steps from start to impact.
Find a legacy PHP target
- Internet-facing or otherwise reachable web application
- PHP version prior to
5.6.29 - Version/banner disclosure or fingerprintable behavior
- Many sites suppress
X-Powered-Byor proxy PHP behind another stack - Banner detection overstates exploitability because it does not prove
WDDXusage - Distro backports can complicate naive version-only triage
Reach a WDDX deserialization sink
wddx_deserialize() or equivalent ext/wddx functionality. Practical weaponization here is usually a custom curl/Python/XML PoC, not an off-the-shelf mass exploit kit.ext/wddxloaded in the target SAPI- Application accepts attacker-controlled WDDX/XML input
- That input reaches the vulnerable parser
WDDXis a niche, legacy feature and later became deprecated/unbundled- Most PHP applications never touch
wddx_deserialize() - Even if
WDDXis installed, there may be no reachable endpoint exposing it
wddx_deserialize is high-signal. Dynamic scanners generally do not prove this sink exists.Trigger the parser bug with crafted XML
wddxPacket containing an empty boolean element causes stack handling to go wrong inside php_wddx_push_element() / php_wddx_pop_element(). That can crash the PHP process and, in worst-case theory, open memory-corruption conditions.- Attacker can submit crafted WDDX XML
- Vulnerable parser path executes without prior sanitization
- Target still runs an affected build
- Crash reliability is easier than controlled code execution
- Memory-corruption exploitation quality varies by platform, build flags, and runtime layout
- Modern hardening can reduce practical exploit reliability
php-fpm, Apache worker logs, or core dumps around XML/WDDX parsing. Web logs may only show odd XML payloads, not a clear exploit signature.Land impact: DoS in practice, possible worse on paper
- PHP worker crash affects service availability
- Target process privileges and memory layout permit further abuse
- No strong public record of modern in-the-wild weaponization
- Attacker still needs the rare parser sink, not just an old PHP banner
- Blast radius is usually one app pool / host, not instant fleet compromise
The supporting signals.
| Vendor severity reality check | Tenable currently shows plugin 95874 as Critical with CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H and VPR 5.9 Medium; the user's HIGH (?) guess is outdated or from another view. |
|---|---|
| Primary bug in scope | CVE-2016-9935 is a WDDX parser memory-corruption issue in PHP < 5.6.29 and 7.0.x < 7.0.14; NVD maps it to CWE-125 Out-of-bounds Read. |
| Affected version range | Upstream affected range is PHP 5.6.0 through 5.6.28; the Tenable plugin specifically keys on 5.6.x < 5.6.29 by remote banner. |
| Fixed versions | Upstream fix is 5.6.29. Distro backports exist, including Debian Jessie 5.6.29+dfsg-0+deb8u1; Ubuntu tracked fixes separately for older distro packages rather than upstream-style versioning. |
| In-the-wild status | I found no KEV listing and no credible public record of current broad exploitation campaigns for CVE-2016-9935. CISA has an old vulnerability bulletin entry, but not a Known Exploited Vulnerabilities catalog listing. |
| Proof-of-concept availability | There is a public trigger and patch context in PHP bug #73631, including sample WDDX XML and crash details from [email protected]. I did not find a mainstream Metasploit module or widely cited modern weaponized repo for this bug. |
| EPSS | CVEDetails currently mirrors CVE-2016-9935 at about 4.39% EPSS and roughly the 89th percentile. Treat that as *moderate at most*, not emergency exploitation pressure. |
| Exposure telemetry | Public attack-surface tools can fingerprint old PHP banners, but they cannot tell you whether WDDX is enabled or whether a reachable wddx_deserialize() sink exists. CVEDetails shows coarse scanner telemetry claiming many affected IPs, but that is exposure noise, not proof of exploitability in your app. |
| Detection quality | This plugin is a version-only remote finding: useful for finding stale PHP, weak for proving exploit path. The decisive validation step is a host-level check for PHP version plus whether the deployed codebase and active SAPI actually use WDDX. |
| Lifecycle context | PHP 5.6 is long end-of-life. Even if this specific parser bug is hard to reach, staying on 5.6 means you're betting production uptime on a dead runtime branch. |
noisgate verdict.
The decisive friction is the reachable WDDX parser requirement: an attacker usually needs more than a vulnerable banner; they need an actual endpoint that feeds attacker-controlled XML into a deprecated extension. That sharply narrows the exposed population versus the vendor's 9.8, but the finding still matters because old internet-facing PHP 5.6 estates are fragile and this bug can still crash services wherever that path exists.
Why this verdict
- Start from 9.8, then cut for the sink requirement: vendor scoring assumes direct unauthenticated remote reachability to the vulnerable parser, but the real exploit needs attacker-controlled input to hit
wddx_deserialize()or equivalentWDDXhandling. - Deprecated feature, narrow population:
WDDXwas later deprecated and unbundled, which is strong evidence this is a legacy niche, not a core PHP path most modern apps exercise. - No strong exploitation pressure: no KEV entry, no strong modern campaign evidence, and only moderate EPSS means this is not behaving like a must-stop-everything edge-RCE despite the memory-corruption label.
Why not higher?
This is not higher because most estates with old PHP still will not expose a reachable WDDX parser sink to unauthenticated users. Also, public evidence leans much more toward crashability than toward a clean, repeatable, widely used RCE chain for this exact bug.
Why not lower?
This is not lower because the attacker needs no auth and no user interaction once the vulnerable parser path exists. Also, any externally reachable PHP 5.6 server is legacy debt with poor safety margin, so a pure backlog-only rating would understate operational risk.
What to do — in priority order.
- Disable or remove
WDDXwhere unused — If the application does not requireext/wddx, remove it from the active PHP SAPI or disable the code path usingwddx_deserialize(). For a MEDIUM finding there is no formal mitigation SLA, but this is the highest-value temporary control because it removes the decisive exploit sink while you work toward remediation within the 365-day remediation window. - Constrain internet reachability to legacy PHP pools — Put legacy PHP 5.6 apps behind tighter reverse-proxy ACLs, VPN-only access, or origin restrictions if they do not need broad public reach. There is no noisgate mitigation deadline for MEDIUM, but use this as a same-change-window hardening step for externally reachable systems while planning the actual upgrade inside the 365-day remediation window.
- Verify package backports before declaring exposure — For distro-managed hosts, confirm package fix level with credentialed checks instead of trusting a remote banner alone. This avoids burning patch bandwidth on false positives while still meeting the MEDIUM remediation expectation.
- Search code for
wddx_deserializeand adjacent XML handlers — A quick code and config sweep tells you whether the scary CVSS path is real in your estate. Prioritize apps that are internet-facing and actually deserialize untrusted XML, then drive those first through the remediation window.
- Hiding the
X-Powered-Byheader does not fix the parser bug; it only makes banner-based fingerprinting noisier. - A generic WAF rule is not a reliable answer because the risky condition is application-specific deserialization into
WDDX, not one universal URI or signature. - Upgrading Apache or nginx alone does nothing if the vulnerable PHP runtime behind it is unchanged.
Crowdsourced verification payload.
Run this on the target host that actually executes PHP, not on your scanner. Invoke it as bash check_php_95874.sh /usr/bin/php (or point it at the exact php binary used by the affected pool/container); no root is required for a basic version/module check, but you may need shell access inside the container or VM.
#!/usr/bin/env bash
# check_php_95874.sh
# Determine likely exposure for Tenable plugin 95874 (PHP 5.6.x < 5.6.29).
# Usage: bash check_php_95874.sh /path/to/php
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
set -u
PHPBIN="${1:-php}"
if ! command -v "$PHPBIN" >/dev/null 2>&1; then
echo "UNKNOWN: PHP binary not found: $PHPBIN"
exit 2
fi
VER="$($PHPBIN -r 'echo PHP_VERSION;' 2>/dev/null || true)"
if [ -z "$VER" ]; then
echo "UNKNOWN: Unable to read PHP version from $PHPBIN"
exit 2
fi
MODS="$($PHPBIN -m 2>/dev/null || true)"
WDDX_STATE="not-loaded"
if printf '%s
' "$MODS" | grep -qi '^wddx$'; then
WDDX_STATE="loaded"
fi
# Normalize version: handle values like 5.6.28-1ubuntu4.21 or 5.6.29
BASE_VER="$(printf '%s' "$VER" | sed -E 's/[^0-9.].*$//')"
version_lt() {
# returns 0 if $1 < $2
[ "$(printf '%s
%s
' "$1" "$2" | sort -V | head -n1)" != "$2" ]
}
if printf '%s' "$BASE_VER" | grep -Eq '^5\.6\.[0-9]+$'; then
if version_lt "$BASE_VER" "5.6.29"; then
echo "VULNERABLE: PHP $VER detected (< 5.6.29); WDDX is $WDDX_STATE"
exit 1
else
echo "PATCHED: PHP $VER is not in the affected upstream range; WDDX is $WDDX_STATE"
exit 0
fi
fi
# If it's not PHP 5.6.x, this specific Tenable plugin does not apply.
echo "PATCHED: PHP $VER is outside Tenable 95874's affected range (5.6.x < 5.6.29); WDDX is $WDDX_STATE"
exit 0
If you remember one thing.
95874 into two buckets: internet-facing and internal-only, then validate which ones actually run PHP 5.6.x < 5.6.29 and whether WDDX is present or used. For this MEDIUM reassessment there is no noisgate mitigation SLA — go straight to the 365-day remediation window for routine cases, but don't treat external legacy PHP as harmless: remove unused WDDX, reduce exposure during normal ops, and complete the runtime upgrade or platform migration within the noisgate remediation SLA of ≤365 days.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.