← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:95874 · CWE-125 · Disclosed 2016-12-06

PHP 5

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

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.

"Severe bug, narrow real-world path: this is mostly a legacy PHP hygiene issue unless WDDX is actually reachable"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find a legacy PHP target

The attacker first identifies a host running old PHP, typically through headers, banners, error pages, or app fingerprinting. Tenable itself detects this plugin remotely from the reported PHP version, which is useful for inventory but says nothing about whether the dangerous parser path is reachable.
Conditions required:
  • Internet-facing or otherwise reachable web application
  • PHP version prior to 5.6.29
  • Version/banner disclosure or fingerprintable behavior
Where this breaks in practice:
  • Many sites suppress X-Powered-By or proxy PHP behind another stack
  • Banner detection overstates exploitability because it does not prove WDDX usage
  • Distro backports can complicate naive version-only triage
Detection/coverage: Nessus covers this as a remote version/banner finding. Credentialed package checks are better for separating true upstream version lag from distro-fixed builds.
STEP 02

Reach a WDDX deserialization sink

To turn version exposure into exploitability, the attacker needs an application path that passes attacker-controlled XML into 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.
Conditions required:
  • ext/wddx loaded in the target SAPI
  • Application accepts attacker-controlled WDDX/XML input
  • That input reaches the vulnerable parser
Where this breaks in practice:
  • WDDX is a niche, legacy feature and later became deprecated/unbundled
  • Most PHP applications never touch wddx_deserialize()
  • Even if WDDX is installed, there may be no reachable endpoint exposing it
Detection/coverage: Static code search for wddx_deserialize is high-signal. Dynamic scanners generally do not prove this sink exists.
STEP 03

Trigger the parser bug with crafted XML

The public PHP security bug report shows the trigger: a crafted 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.
Conditions required:
  • Attacker can submit crafted WDDX XML
  • Vulnerable parser path executes without prior sanitization
  • Target still runs an affected build
Where this breaks in practice:
  • 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
Detection/coverage: Look for crashes in 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.
STEP 04

Land impact: DoS in practice, possible worse on paper

If the parser path is reachable, the most defensible real-world outcome is denial of service through process crash or pool instability. The CVSS model allows for confidentiality and integrity impact because it is memory corruption, but public evidence of widespread reliable RCE chains for this exact bug is weak.
Conditions required:
  • PHP worker crash affects service availability
  • Target process privileges and memory layout permit further abuse
Where this breaks in practice:
  • 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
Detection/coverage: EDR can catch repeated worker crashes and anomalous child process behavior, but most orgs will see this first as app instability rather than a crisp exploit alert.
03 · Intelligence Metadata

The supporting signals.

Vendor severity reality checkTenable 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 scopeCVE-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 rangeUpstream 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 versionsUpstream 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 statusI 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 availabilityThere 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.
EPSSCVEDetails 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 telemetryPublic 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 qualityThis 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 contextPHP 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.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.8/10)

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.

HIGH Technical root cause and affected upstream versions
MEDIUM Real-world exploitability across a mixed enterprise estate
HIGH Assessment that vendor severity overstates broad operational risk

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 equivalent WDDX handling.
  • Deprecated feature, narrow population: WDDX was 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.

05 · Compensating Control

What to do — in priority order.

  1. Disable or remove WDDX where unused — If the application does not require ext/wddx, remove it from the active PHP SAPI or disable the code path using wddx_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.
  2. 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.
  3. 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.
  4. Search code for wddx_deserialize and 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.
What doesn't work
  • Hiding the X-Powered-By header 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.
06 · Verification

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.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, pull every host hit by plugin 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

  1. Tenable Nessus Plugin 95874
  2. PHP 5 ChangeLog - Version 5.6.29
  3. NVD - CVE-2016-9935
  4. PHP Security Bug #73631
  5. PHP Manual - WDDX
  6. PHP Supported Versions
  7. Debian DSA-3737-1
  8. Ubuntu CVE-2016-9935
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.