Skip to content

Releases: Anton-Barinov/php2shell-patches

v1.4 — every EOL branch (5.6–8.1) at official PHP 8.2.35 fix parity

Choose a tag to compare

@Anton-Barinov Anton-Barinov released this 22 Oct 10:59

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 stops php_session_rfc1867_update()/_cleanup(), the destroyed record stays gone, exactly one warning — ported from the 7.4 patch (PHP 5.6 php_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-1 vs sizeof) so the branch was dead code; now fixed and gated on php_var_serialize_set_incomplete_classes_only() so a plain serialize() of a forged payload property still emits O:.
  • Serializer reset moved from php_rshutdown_session_globals() into PHP_RSHUTDOWN_FUNCTION(session) — never from destroy/cleanup (ikow finding kept).
  • Per-file bytes_processed written at event time (stock relied on shared zvals; sync_counters only 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's if (progress->data) backport.
  • Validated end-to-end on pristine php-5.6.40 and on Remi's PHP-5.6-security-backports: subset 1162/1164 pass, only the pre-existing parse_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)

Choose a tag to compare

@Anton-Barinov Anton-Barinov released this 21 Oct 18:15

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, no unserialize_callback_func, no __wakeup — __PHP_Incomplete_Class only, lossless C: raw-payload round-trip. (CVE-2026-109619 attack chains from ikow/php2shell-poc.)
  • post_max_size bypass fixed (GHSA-2cv3-554h-jpmh): fill_buffer stops reading at post_max_size when Content-Length is absent/lying, plus the official Actual POST length does not match Content-Length warning at fileupload_done — exactly as in PHP 8.2.35. The urlencoded side of the upstream fix already exists in stock 5.6 SAPI.c.
  • Compile fix: (*var_hash)->field dereference (stale copies of the patch before a6c3d04 do not build — always git pull).

Validation (Ubuntu 22.04, PHP 5.6.40)

  • patch -p1 applies cleanly to both the official php.net tarball and the GitHub tag archive; buildconf --force + configure + make OK.
  • 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; __wakeup never fires.

Also

  • tests/feedpost/ — verification harness (phpize ext) with README and expected numbers.
  • README: build troubleshooting (re2c regeneration, 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)

Choose a tag to compare

@Anton-Barinov Anton-Barinov released this 21 Oct 16:05

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.

⚠️ Community patches — not affiliated with or endorsed by the PHP Group. Test before production. Migrating off EOL PHP is the real fix.