Repository navigation
Releases: Anton-Barinov/php2shell-patches
Release list
v1.4 — every EOL branch (5.6–8.1) at official PHP 8.2.35 fix parity
What's new since v1.3
PHP 5.6 enhanced (universal + Remicollet security tree) — v4 parity
- Chain-C refusal guard (
rfc1867_decode_refused): a decode refused during the upload-progress window stopsphp_session_rfc1867_update()/_cleanup(), the destroyed record stays gone, exactly one warning — ported from the 7.4 patch (PHP 5.6php_session_initialize()is void, so the flag carries the refusal). - Reserved-props rejection in
var_unserializer: a record carrying the incomplete-class bookkeeping names (__PHP_Incomplete_Class_Name/__PHP_Incomplete_Class_Serialized) is refused, not silently overwritten. - Lossless
C:write-back fixed and gated: the var.c look-up used the wrong PHP 5 hash-key length (sizeof-1vssizeof) so the branch was dead code; now fixed and gated onphp_var_serialize_set_incomplete_classes_only()so a plainserialize()of a forged payload property still emitsO:. - Serializer reset moved from
php_rshutdown_session_globals()intoPHP_RSHUTDOWN_FUNCTION(session)— never from destroy/cleanup (ikow finding kept). - Per-file
bytes_processedwritten at event time (stock relied on shared zvals;sync_countersonly refreshes the last file). - Bundled adapted 8.2.35 tests:
rfc1867_no_user_code.phpt,rfc1867_incomplete_class_reserved_props.phpt,incomplete_class_raw_payload_markers.phpt(regression control). The Remicollet patch carries the same v4 content, adapted to Remi'sif (progress->data)backport. - Validated end-to-end on pristine
php-5.6.40and on Remi'sPHP-5.6-security-backports: subset 1162/1164 pass, only the pre-existingparse_ini_*fails (stock-identical); discriminators 3/3 PASS on the patched builds, the two rfc1867 tests FAIL on stock.
Also in this release
- PHP 7.1.33: enhanced-universal + minimal + Remicollet security-tree patches (full CI build matrix).
- PHP 7.2.34 / 7.3.33: enhanced patches at the same refusal parity (23/25 files), Remicollet variants in sync; validated subsets 0 fail, discriminators 6/6.
- PHP 7.4.33 / 8.0.30 / 8.1.34: enhanced patches at 8.2.35 parity (v1.3 validation, still green in CI).
CI
Every push now dry-runs all patches (including the Remicollet variants against remicollet/php-src-security trees) and builds the full 5.6–8.1 matrix.
v1.2 — PHP 5.6 enhanced patch completed & fully validated (GHSA-2cv3-554h-jpmh + Chain C)
What's new since v1.1
PHP 5.6 enhanced-universal patch — completed to official-fix parity
- Chain-C decode window closed (
incomplete_classes_only): during the session upload-progress decode (before user code/classes exist) no class lookup, no autoload, nounserialize_callback_func, no__wakeup—__PHP_Incomplete_Classonly, losslessC:raw-payload round-trip. (CVE-2026-109619 attack chains from ikow/php2shell-poc.) post_max_sizebypass fixed (GHSA-2cv3-554h-jpmh):fill_bufferstops reading atpost_max_sizewhen Content-Length is absent/lying, plus the officialActual POST length does not match Content-Lengthwarning atfileupload_done— exactly as in PHP 8.2.35. The urlencoded side of the upstream fix already exists in stock 5.6SAPI.c.- Compile fix:
(*var_hash)->fielddereference (stale copies of the patch beforea6c3d04do not build — alwaysgit pull).
Validation (Ubuntu 22.04, PHP 5.6.40)
patch -p1applies cleanly to both the official php.net tarball and the GitHub tag archive;buildconf --force+configure+makeOK.make test(1373 tests: ext/session, serialize, file, general_functions, main): 1106 pass / 245 skip / 20 fail / 2 warn — results identical to the pre-enhancement build (same 20 pre-existing failures, zero regressions).- Bypass reproduced & blocked via the new
tests/feedpost/harness (1 MB multipart, missing Content-Length,post_max_size=100K): pre-patch accepts 1 048 576 bytes; patched truncates to 102 381 + official warning. - Upload-progress window discriminator: pre-patch runs user code during upload (
string(5) "Evill"×2 in the response); patched build emits nothing, still writes the progress key (progress bars keep working) and re-encodes the seeded payload losslessly;__wakeupnever fires.
Also
tests/feedpost/— verification harness (phpize ext) with README and expected numbers.- README: build troubleshooting (
re2cregeneration, stale-patch errors), complete fix list, validation results.
Upgrade notes
Always take the latest patch from main — copies of php-5.6-enhanced-universal.patch older than a6c3d04 do not compile, older than 7f24333 are missing the post_max warning.
v1.1 — Enhanced-universal patches (root-cause UAF fix, keeps file uploads)
What's new in v1.1
Enhanced-universal patches for PHP 5.6 and 7.4 — combine the best community research into one universal fix that **keeps multipart/form-data uploads and session upload progress working** (unlike the official minimal backports which force-disable upload progress).
Combined from community research
| Fix | Source | Impact |
|---|---|---|
| Root-cause UAF fix (zend_long counters + sync_counters) | eness | Fixes CVE-2026-109619 at the root — upload_progress stays functional |
| Session-fixation fix (use_only_cookies) | PR #22113 | Blocks POST-body PHPSESSID bypass |
| Filename sanitization | ikow | Blocks session-file injection / LFI→RCE |
| PS(serializer) reset between requests | ikow | Blocks FPM cross-request handler mismatch |
Plus everything from the official PHP-group minimal backport (OOM bailout → _exit(1), multipart header limiting, global resets).
Two flavors now available
- minimal (official PHP-group): safest, force-disables upload progress
- enhanced-universal (community): root-cause fix, keeps forms + progress bars — recommended for OpenCart / e-commerce / any app with file uploads
Test results (Ubuntu 22.04, HestiaCP 1.10.5)
- PHP 7.4.33 enhanced: patch applies clean, make OK, multipart POST with fields+file works ($_POST/$_FILES/is_uploaded_file), upload_progress functional
- PHP 5.6.40 enhanced: patch applies clean (GitHub tag + buildconf), make OK, multipart works, session.upload_progress.enabled stays On
PHP 5.6 build fixes
- Removed ZEND_COLD/ZEND_NORETURN (PHP 7-only macros) — both 5.6 patches fixed
- zend_long → long in progress struct
- Build troubleshooting documented in README (museum.php.net timeout, buildconf, libcurl)
For old OpenCart / HestiaCP / VestaCP hosts
This repo targets legacy stacks (OpenCart 1.x/2.x/3.x, WordPress, custom CMS on PHP 5.6/7.x) that cannot jump to PHP 8.2+ immediately. See README for hardening scripts and fleet inventory tool.