This is a cracked engine block that only matters if the attacker can also reach the right pedals
tenable:101525 is a version-based finding for PHP 5.6.x before 5.6.31, published on 2017-07-06. The bundle includes multiple bugs across core PHP and bundled libraries: Oniguruma regex compilation/searching (CVE-2017-9224/9226/9227/9228/9229), unserialize() handling (CVE-2017-12933), INI parsing (CVE-2017-11628), WDDX parsing (CVE-2017-11143/11145), GD/PCRE memory issues, and a large-POST CPU DoS (CVE-2017-11142). The important catch: most of these are not generic “send one HTTP request to any PHP site and get RCE” bugs; they need a reachable application sink such as attacker-controlled regex compilation, unsafe deserialization, WDDX parsing, or unusual parser exposure.
The vendor baseline is inflated for enterprise patch triage because Tenable anchors on the worst-case CVSS from CVE-2017-9228 and explicitly says it did not test exploitability, only the self-reported PHP version. In real fleets, the decisive friction is that an attacker usually needs both an old runtime and a specific insecure app behavior; add distro backports and the version-only signal gets even noisier. That makes this a solid MEDIUM for most 10,000-host programs: fix it, but don’t let it jump ahead of proven one-click edge RCEs.
4 steps from start to impact.
Fingerprint old PHP
X-Powered-By: PHP/5.6.x or a package-derived response fingerprint. Tools here are boring: Nessus for defenders, Shodan-style header collection or simple curl/Burp for attackers. This step only proves an old runtime string, not a reachable exploit primitive.- Public or internal HTTP reachability to the web tier
- Version leakage via headers, error pages, or package telemetry
- Many stacks suppress
X-Powered-Byor sit behind reverse proxies - Distro backports make an old-looking version string a weak exploitability signal
Find a vulnerable sink in the app
mb_ereg* with attacker-controlled patterns, unserialize() on untrusted data, parse_ini_string()/INI parsing on user input, wddx_deserialize(), or large POST handling. Burp Suite, source review, and SAST rules are the real weaponized tools here; the PHP version alone is not enough.- Ability to supply crafted input to a PHP function that touches one of the affected parser/library paths
- Application-specific feature exposing regex, deserialization, WDDX, or parser behavior
- Most PHP apps use static regexes, not attacker-supplied regex compilation
WDDXis rare in modern deployments- Unsafe
unserialize()is common historically but still requires a distinct application flaw, not just old PHP
unserialize() and some parser sinks; weak DAST coverage for mbstring/Oniguruma regex-compilation exposure.Trigger memory corruption or parser failure
CVE-2017-9228) showing a reproducible heap write during regex compilation, but that PoC is at library level and still has to be translated into the target app’s request format.- Exact vulnerable code path reached
- Payload can survive app validation and input normalization
- Turning a library-level reproducer into a stable web exploit is non-trivial
- Modern hardening, worker recycling, ASLR, and crash-only behavior often collapse impact from theoretical RCE to DoS
php-fpm, Apache, or nginx upstream logs can reveal failed attempts; network scanners cannot validate this step remotely.Convert crash potential into business impact
- Target process handles the crafted request
- Service architecture allows repeated requests against the same vulnerable path
- Pool isolation limits blast radius to one app or one worker set
- Process supervision restarts crashed workers quickly
- WAF/body limits can blunt oversized POST DoS cases
php-fpm crash logs, and EDR on the web tier provide the best evidence; remote version scans do not measure impact.The supporting signals.
| In-the-wild status | No public active-exploitation signal found in the consulted primary sources, and no CISA KEV listing found for the cited high-end CVEs in this bundle. |
|---|---|
| Proof-of-concept availability | Yes, but mostly library-level. NVD links GitHub issue material for CVE-2017-9228, and the Oniguruma issue includes a reproducible crash harness rather than a turnkey web exploit. |
| EPSS | For CVE-2017-9228, Tenable surfaces EPSS 0.00474. The exact percentile was not surfaced in the consulted primary sources. |
| KEV status | Not KEV-listed in the consulted CISA catalog sources for the representative RCE-class bugs in this advisory. |
| CVSS vector | Vendor/NVD worst-case anchor is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8 for CVE-2017-9228. That is technically valid for the library bug in isolation, but it overstates fleet risk when the application never exposes attacker-controlled regex compilation. |
| Affected versions | Upstream affected range for this Tenable check is PHP 5.6.0 through 5.6.30. NVD also tracks adjacent fixed branches 7.0.21 and 7.1.7 for several bundled issues. |
| Fixed versions | Upstream fix is PHP 5.6.31. Distro backports exist: Debian fixed php5 in 5.6.33+dfsg-0+deb8u1 for Jessie, Ubuntu fixed php5 in 5.5.9+dfsg-1ubuntu4.22 for Trusty, and Red Hat shipped bundled fixes in later package errata rather than matching upstream version strings. |
| Scanner/detection notes | Tenable states it relies only on the application's self-reported version number and has not tested the vulnerable code paths. Treat internet-scale exposure numbers for this plugin as coarse inventory, not exploitability proof. |
| Exposure reality | Reachable population is far smaller than 'all PHP 5.6 sites' because most exploit paths require a second condition: an app that reflects user input into mb_ereg*, unserialize(), parse_ini_string(), WDDX, or oversized POST processing. |
| Disclosure and researchers | Upstream PHP shipped the security release on 2017-07-06. One representative high-severity underlying bug, CVE-2017-9228, was published on 2017-05-24; the public Oniguruma issue shows it was reported by GitHub user lxxxxfdh on 2017-05-23. |
noisgate verdict.
The single biggest downgrade factor is code-path friction: an attacker usually needs a vulnerable application behavior on top of the old PHP runtime, not merely network reachability to a PHP banner. Without that second condition, the practical outcome trends toward crashes or no exploit path at all, which is not how a true edge-critical issue behaves in a large fleet.
Why this verdict
- Requires an app sink, not just old PHP — most serious paths need attacker-controlled regex compilation, unsafe
unserialize(), WDDX, or INI parsing. That means the vulnerability is usually post-discovery, pre-exploitation research work, not a one-request edge compromise. - Version-only detection is noisy — Tenable says the plugin relies only on self-reported version. In real estates with Debian/Ubuntu/RHEL backports, that creates meaningful false urgency.
- Threat intel is cold — no KEV signal found and the representative EPSS exposed by Tenable for
CVE-2017-9228is only0.00474. Public reproducers exist, but they are not the same thing as mass exploitation evidence.
Why not higher?
This is not a clean internet-edge RCE against every host running PHP 5.6.30. The attack almost always needs a second vulnerable condition inside the app, and several included bugs are more realistically DoS or memory-disclosure crashes than reliable code execution in hardened production workers.
Why not lower?
You still have an old PHP branch with real memory-corruption bugs and public technical reproducers. If one of your exposed apps feeds user input into the affected functions, the score moves from 'legacy noise' to 'legit incident material' quickly, so this does not belong in ignore/backlog limbo.
What to do — in priority order.
- Suppress version leakage — Remove or mask
X-Powered-Byand related PHP banners so commodity scanners and opportunistic attackers lose the cheap fingerprint. At MEDIUM, there is no noisgate mitigation SLA; do this in the next normal hardening cycle while you work toward patching within the 365-day remediation window. - Hunt risky PHP sinks — Search code and configs for
unserialize(,wddx_deserialize(,parse_ini_string(, andmb_ereg/mb_eregiusage with user-controlled patterns. This is the highest-value control because it tells you which hosts are merely old versus actually reachable; at MEDIUM, fold this into routine engineering work and complete it within the same remediation window. - Enforce request-size limits — Clamp oversized POST bodies at the reverse proxy and app server to reduce exposure to the large-POST CPU exhaustion bug (
CVE-2017-11142). Use nginxclient_max_body_size, ApacheLimitRequestBody, and upstream timeouts; there is no mitigation SLA at this severity, so apply as part of normal web-tier hygiene. - Isolate and monitor PHP workers — Run apps in separate
php-fpmpools or equivalent worker boundaries with sane restart policies, low privileges, and tight file permissions. That turns most failed parser exploitation into a contained worker recycle instead of a multi-app outage; again, no mitigation SLA at MEDIUM, but it should land before the patch deadline.
- MFA doesn't help; these are parser/runtime issues, not account-takeover paths.
- Network segmentation alone doesn't solve it for internet-facing apps because the vulnerable surface is the web request itself.
- A generic WAF signature will not reliably catch library-level regex or deserialization edge cases unless you already know the exact app endpoint and payload shape.
- Closing the ticket because the package version looks old but 'the distro backports fixes' is not enough; verify the actual package errata or host package build before suppressing.
Crowdsourced verification payload.
Run this on the target PHP host as a local validation check, not from your scanner. Invoke it as bash verify_php_5_6_31.sh with no special privileges required for the basic version test; package backport checks for Debian/Ubuntu use local package metadata if available.
#!/usr/bin/env bash
# verify_php_5_6_31.sh
# Purpose: determine whether the local PHP runtime is vulnerable to the upstream
# PHP < 5.6.31 bundle represented by Tenable plugin 101525.
#
# Output:
# VULNERABLE - upstream PHP 5.6.x earlier than 5.6.31 and no known distro backport match found
# PATCHED - PHP not in affected range, or known distro-fixed package build detected
# UNKNOWN - PHP missing, version unreadable, or distro backport status cannot be determined confidently
#
# Exit codes:
# 0 PATCHED
# 1 VULNERABLE
# 2 UNKNOWN
set -u
ver_lt() {
# returns 0 if $1 < $2
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" != "$2" ]
}
command -v php >/dev/null 2>&1 || { echo "UNKNOWN: php binary not found"; exit 2; }
PHP_VER_RAW="$(php -r 'echo PHP_VERSION;' 2>/dev/null)"
if [ -z "$PHP_VER_RAW" ]; then
echo "UNKNOWN: unable to read PHP_VERSION"
exit 2
fi
PHP_VER="${PHP_VER_RAW%%-*}"
# Fast path: unaffected upstream versions
case "$PHP_VER" in
5.6.*)
if ver_lt "$PHP_VER" "5.6.31"; then
:
else
echo "PATCHED: upstream PHP version $PHP_VER >= 5.6.31"
exit 0
fi
;;
5.*)
# Older non-5.6 branches are outside this specific plugin's affected range.
echo "PATCHED: PHP version $PHP_VER is not in the plugin's 5.6.x < 5.6.31 range"
exit 0
;;
*)
echo "PATCHED: PHP version $PHP_VER is newer than the plugin's affected branch"
exit 0
;;
esac
# At this point, upstream-reported PHP is 5.6.x < 5.6.31.
# Check common distro backport cases before declaring vulnerable.
if command -v dpkg-query >/dev/null 2>&1; then
PKG_VER="$(dpkg-query -W -f='${Version}\n' php5 2>/dev/null | head -n1)"
if [ -n "$PKG_VER" ]; then
case "$PKG_VER" in
5.6.33+dfsg-0+deb8u1*|5.6.33+dfsg-0+deb8u2*|5.6.33+dfsg-0+deb8u3*|5.6.40+*)
echo "PATCHED: Debian php5 package $PKG_VER includes fixes beyond upstream 5.6.31"
exit 0
;;
5.5.9+dfsg-1ubuntu4.22*|5.5.9+dfsg-1ubuntu4.23*|5.5.9+dfsg-1ubuntu4.24*)
echo "PATCHED: Ubuntu php5 package $PKG_VER is a known fixed backport level"
exit 0
;;
esac
echo "UNKNOWN: php reports $PHP_VER but distro package $PKG_VER may be backported; verify vendor errata"
exit 2
fi
fi
if command -v rpm >/dev/null 2>&1; then
# Generic RPM check: many vendors backport without changing the upstream PHP_VERSION.
RPM_PKG="$(rpm -q php php-cli php-common 2>/dev/null | tr '\n' ' ' | sed 's/ */ /g')"
if [ -n "$RPM_PKG" ]; then
echo "UNKNOWN: php reports $PHP_VER and RPM packages were found ($RPM_PKG). RPM-based distros often backport fixes; verify against local vendor errata before calling this vulnerable."
exit 2
fi
fi
echo "VULNERABLE: upstream PHP version $PHP_VER is in 5.6.x < 5.6.31 and no known backport match was detected"
exit 1
If you remember one thing.
unserialize() / mb_ereg* / parser sinks, and schedule the actual PHP update or platform retirement under the noisgate remediation SLA of ≤365 days. If any exposed app is confirmed to compile attacker-controlled regexes or deserialize untrusted data, pull that host forward ahead of the general queue.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.