Home›Blog›PHP2Shell: Reproducing the Exploit

PHP2Shell: Reproducing the Exploit

Published:
Share this article
Terminal clip showing PHP2Shell code execution and retrieval of a test flag and fictional records

A PHP application can be exposed to PHP2Shell before its own request-handling code runs. We reproduced the exploit against a small café application to examine what that means in practice, including where the memory leak comes from and what a failed exploit test can tell a defender.

This is a reproduction of 9bie’s exploit, adapted by Octane for our test webapp, The Corner Café. The PHP Foundation’s disclosure account documents the original reports and researcher credits.

Remediation first: install the PHP security updates or your vendor’s fixed packages, restart affected workers, and review the October 23 session-handling follow-up. Details below reflect guidance available on October 23, 2026.

The two advisories describe broader failure modes

PHP2Shell covers two related vulnerability classes. CVE-2026-109618 concerns allocation failures that interrupt work while internal data is incompletely initialized. PHP’s shutdown path can subsequently act on that invalid data. CVE-2026-109619 concerns state that outlives the request memory it references and can be used by a later request before initialization resets it.

That distinction matters when reading an exploit walkthrough. A particular use-after-free is an instance of a wider problem involving initialization, cleanup and memory ownership. Blocking one trigger does not establish that every affected path has been removed.

An upload form is not a prerequisite

The café application has a menu and a booking form. The recorded demonstration shows code execution as the web-server account and access to a test flag and fictional booking records outside the web root. There is no application file-upload feature in that workflow.

The relevant boundary is inside the runtime. PHP can process a multipart body and update session upload progress before control reaches the application script. A website’s interface tells you little about whether those operations are reachable through a crafted request.

For an exposure assessment, trace the request through the proxy, web server and PHP integration. Determine whether the affected runtime handles the input before application validation or authentication. A missing upload button, or application code that never uses the uploaded file, does not answer that question.

The chain provides its own memory disclosure

The chain we adapted does not need a separate information-disclosure bug in the café application. Vulnerable PHP session handling supplies the leak.

In this chain, stale session state causes PHP to treat attacker-controlled memory as a string. The cookie-writing path then reads beyond the intended string and returns roughly 800 KiB of heap contents through Set-Cookie. Pointers in that data allow the exploit to recover the loaded PHP library’s base address and relevant heap addresses. The later memory-corruption stage uses that information to reach code execution.

Three-second demo excerpt showing memory disclosure and recovery of PHP library addresses
The chain obtains heap data and recovers PHP library addresses.

Address space layout randomization, or ASLR, makes addresses unpredictable. It does not prevent an exploit from learning those addresses through another primitive in the same chain. For this demonstration, searching the application for an unrelated leak would miss where the address information actually comes from.

A failed proof of concept does not establish patch status

The implementation documents a particular PHP build, Apache configuration and session handler. It also accounts for worker reuse across requests. Those assumptions matter when interpreting a test result.

Our reading of the reproduction is that three outcomes need to be kept separate. A successful run establishes a working attack path in the tested environment. A failed run establishes that this attempt did not complete. Confirmation that a service is patched requires evidence about the build and configuration actually serving requests.

Record the runtime, architecture, effective configuration and worker behavior alongside a reproduction result. If a known exploit stops working after an update, retain that as a regression test while separately verifying that the running service contains the fixes.

Verify the serving runtime and the deployment image

PHP’s first fixed releases for the October 21 advisories are 8.2.35, 8.3.36, 8.4.27 and 8.5.12. Use those or a later fixed release in the appropriate branch. Distribution packages may carry backported fixes under an older version string. Check the vendor’s advisory and package revision.

Build the inventory from both outside and inside the deployment. HTTP headers can help identify PHP services, but missing headers leave uncertainty, and version banners can obscure vendor backports. Check the hosts and deployment definitions as well, including secondary sites, appliances and containers.

Check which runtime receives web traffic. The executable reported by php -v may be different from the Apache module or PHP-FPM pool handling requests. For containers, check both the deployed instance and the image that future deployments will use.

Close those gaps by identifying the package or image behind each serving process, checking its fix status, then restarting workers or redeploying containers. Update the image definition as well. Record the deployed image digest or package revision so a later rollout does not restore the vulnerable build.

The October 23 PHP notice adds a specific qualification. An application configured with php_binary or php_serialize that switches to php using ini_set() before session_start(), while upload progress is enabled, needs session.upload_progress.enabled=0 pending the next bugfix release. PHP tracks this follow-up as CVE-2026-115560.

Set request-parsing mitigations in configuration that takes effect before parsing, and restart the workers. A setting changed inside the application can be too late. Treat temporary mitigations as controls for particular paths and follow the current PHP advisory when deciding which ones to retain.

Review possible compromise separately from remediation

Installing the fix does not undo an earlier compromise. Correlate request and error logs with process, filesystem and network activity. Useful leads include multipart traffic around memory failures or worker crashes, abnormal session-cookie responses, unexpected processes launched by the web server, unexplained file changes and outbound connections.

These signals are leads for investigation, not proof by themselves. Where compromise is suspected, scope the data and credentials accessible to the PHP process and handle containment and credential rotation through the incident-response process. Passing the demonstration’s patch test does not resolve that separate question.

AI reduces the work needed to turn a flaw into an exploit

Exploit adaptation is a substantial part of the work. A chain can fail when the target’s build, configuration or memory layout changes. AI can help investigate those failures and propose adjustments, but each proposed explanation still needs to survive a test. That makes the ability to build and observe realistic test environments central to evaluating a model’s security work.

The history also matters. The PHP Foundation says signs of the out-of-memory problem were identified during work on a 2024 audit. A concrete remote-code-execution report arrived in August 2026. Fixing the issue also involved difficult compatibility and implementation trade-offs. “AI found a bug nobody had noticed for decades” leaves out that history.

Our takeaway is that difficulty reproducing an issue can be a temporary limit on research effort. It should not become a permanent assumption in a threat model. Defenders can use the same testing loop to revisit failure paths and turn uncertain findings into evidence that helps engineers prioritize a fix.

After the immediate response

There is value in applying that work to mature code before an emergency. In our separate VirtualBox investigation, Octane identified a heap overflow in logic dating to October 2010, assigned CVE-2026-60161. We reproduced heap corruption and crashes. It is one example of why longstanding code still merits investigation.

Once the PHP response is complete, we can help examine similarly consequential paths in your own software. If that would be useful, talk with our research team about a focused review.

Written by
Share this article

Subscribe to our newsletter

By subscribing you agree to with our Privacy Policy.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.