Files
php2shell/bypass/FINDINGS.md
T
neko e58bb493af PHP session upload progress RCE exploits (CVE-2026-109618, CVE-2026-109619)
Full RCE exploit chain for two critical PHP vulnerabilities in the multipart
parser and session upload progress handler, plus three bypass exploits that
defeat the official security patch (PHP 8.4.27) and all recommended mitigations.

Core exploits:
- CVE-2026-109618: OOM in multipart parser → session persistence → LFI → RCE
- CVE-2026-109619: Session poisoning via upload progress (direct + race) → RCE
- WordPress-targeted wrapper with LFI auto-detection

Patch bypass exploits (confirmed RCE on PHP 8.4.27):
- Race condition: TOCTOU inherent to upload progress feature design
- RLIMIT_AS: mmap() failure bypasses the patched OOM handler
- /proc/PID/fd: temp file inclusion bypasses ALL mitigations
2026-10-21 11:29:40 -05:00

4.2 KiB

PHP 8.4.27 Patch Bypass Findings

Summary

The PHP security patch released 2026-10-21 (PHP 8.4.27, 8.3.36, 8.2.35, 8.5.12) for CVE-2026-109618 and CVE-2026-109619 has three confirmed bypass paths that achieve Remote Code Execution on fully patched systems.

The advisory's recommended mitigation session.upload_progress.enabled=0 blocks two of the three bypasses but is itself defeated by the third.

Bypass #1: Race Condition (TOCTOU)

File: race_bypass_patched.py Confirmed RCE: Yes, first attempt Patches bypassed: PHP 8.4.27 OOM fix Mitigations bypassed: session.upload_progress.cleanup=1

The session upload progress feature writes attacker-controlled data to the session file on disk during the multipart upload. Cleanup only runs at MULTIPART_EVENT_END. A concurrent LFI request can race to include the session file while the upload is still in progress.

This is a TOCTOU (Time-of-Check-Time-of-Use) issue inherent to the feature's design — the data must exist on disk for the feature to work, creating a window that cannot be eliminated without removing the feature.

Blocked by: session.upload_progress.enabled=0

Bypass #2: RLIMIT_AS / mmap() Failure

File: rlimit_bypass_patched.py Confirmed RCE: Yes Patches bypassed: PHP 8.4.27 OOM fix (different code path) Mitigations bypassed: Standard memory_limit-based OOM handling

The patch intercepts OOM from PHP's memory_limit (via zend_mm allocator). When memory_limit=-1 and the OS enforces address space limits via RLIMIT_AS (or cgroup memory.max), mmap() fails through a different code path that the patch does not cover.

  • Worker exits with code 1 (not the patched exit code 70)
  • Session file persists on disk with attacker-controlled PHP code
  • New worker spawns → LFI includes poisoned session → RCE

Relevant in production:

  • Docker/k8s containers with cgroup memory limits
  • Shared hosting with per-tenant RLIMIT_AS
  • Admins using memory_limit=-1 trusting OS-level limits

Blocked by: session.upload_progress.enabled=0

Bypass #3: /proc/PID/fd Temp File Inclusion

File: procfd_bypass_hardened.py Confirmed RCE: Yes, first attempt Patches bypassed: ALL patches Mitigations bypassed: ALL mitigations including upload_progress=0

During a multipart file upload, PHP creates a temporary file with attacker- controlled contents. This file is visible via /proc/<pid>/fd/<N> to any process that can read procfs. A concurrent LFI request from a different FPM worker can include this file directly.

This attack does NOT use session poisoning at all — it bypasses every session-related mitigation.

Blocked by:

  • Fixing the LFI vulnerability
  • hidepid=2 on /proc mount (hides other processes' FDs)
  • open_basedir restricting /proc access
  • Disabling file uploads entirely (impractical)

Mitigation Effectiveness Matrix

Mitigation Race RLIMIT /proc/fd
PHP 8.4.27 patch alone FAIL FAIL FAIL
+ upload_progress=0 OK OK FAIL
+ hidepid=2 on /proc FAIL FAIL OK
+ upload_progress=0 + hidepid OK OK OK
Fix the LFI OK OK OK

Tested Vectors That Did NOT Bypass the Patch

  • Multipart part header flood: OOM triggered but the patch handles it correctly (exit code 70, session file cleaned up)
  • WAF bypass via PUT/PATCH: Passes POST-only WAF rules but PHP's session.upload_progress only fires on POST requests
  • Content-Type comma tricks: Pass WAF matching but PHP doesn't parse as multipart/form-data
  • Access log poisoning: Works conceptually but fragile (previous log entries may cause PHP parse errors)

Recommendations

  1. Immediate: Set session.upload_progress.enabled=0 in php.ini
  2. Immediate: Mount /proc with hidepid=2 (or hidepid=invisible on newer kernels)
  3. Critical: Fix any Local File Inclusion vulnerabilities in applications
  4. Defense in depth: Set open_basedir to restrict filesystem access
  5. Do NOT rely on the patch alone — it leaves two bypass paths open