PHP2Shell in the wild: the PHP bugs and the attacks Cypho captured

Cypho's Siren sensors captured PHP2Shell-related attack traffic on 22 October 2026. One request carried 149 identical binary payload parts, each containing a downloader command. Another placed PHP code inside an upload-progress field, with instructions to retrieve a script and pass it to a shell.
The requests put concrete behavior behind the PHP2Shell advisories: attackers were sending crafted multipart bodies, manipulating session-related input and embedding commands for the next stage. For security teams, those details help connect an urgent PHP update to activity they can investigate in their own environment.
PHP2Shell covers CVE-2026-109618 and CVE-2026-109619, two critical memory-safety flaws in PHP's handling of request state. PHP released fixes on 21 October 2026. This post explains the bugs, examines the traffic we captured and turns the findings into patching and hunting priorities. PHP security announcement
How the PHP bugs work
A PHP worker typically handles many requests during its lifetime. Memory belonging to one request must be initialized safely, used, then released without leaving references behind. PHP2Shell targets failures in that lifecycle.
CVE-2026-109618: cleanup reaches partially initialized memory. When an allocation fails, PHP can interrupt an operation before its internal structures are ready. Request shutdown then reaches that incomplete state. Crafted input can turn the resulting memory corruption into unauthenticated code execution. PHP's out-of-memory advisory
CVE-2026-109619: one request leaves state for the next. A worker can retain a pointer to memory that belonged to a finished request. A subsequent request on the same worker accesses that pointer before normal initialization clears it. Session upload-progress processing is one confirmed way to reach the stale state. Fatal errors can leave it behind; shutdown diagnostics can also recreate state after cleanup. PHP's stale-state advisory
Two ways request memory becomes unsafe
PHP2Shell targets request memory and cleanup. An interrupted request can expose two different flaws.
CVE-2026-109618Out-of-memory corruption
-
PHP is building request data
-
Fails
Out of memory: PHP stops while the data is only half-initialized
-
Cleanup treats the half-built data as valid: memory corruption, code execution
CVE-2026-109619Stale state
-
Request A: PHP keeps a pointer to request memory in a long-lived variable
-
Fails
The request fails: its memory is freed, the pointer is not cleared
-
Request B on the same worker uses the stale pointer: leak, corruption, code execution
Multipart forms give an attacker considerable control over the work PHP performs. Calif demonstrated that empty file parts and nested field names can cause PHP to allocate much more memory than the request's size on the wire suggests. A body can fit within post_max_size while its internal representation exhausts memory_limit. Calif's technical research
The request lifecycle determines the path to exploitation. Apache mod_php can process invalid state during shutdown after request startup fails, before application code runs. PHP-FPM terminates a worker when startup fails; its documented stale-state path involves state created during application execution and consumed by a later request on that worker. These differences make the PHP build, configuration and worker behavior relevant to an investigation. PHP's out-of-memory advisory, PHP's stale-state advisory
The impact also includes memory disclosure. Wiz demonstrated a path that returns worker-memory contents, potentially exposing credentials and tokens. That makes response behavior and secret access part of the investigation alongside process execution. Wiz Research
What Cypho captured
Our review identified three distinct request patterns around the disclosure. The table separates the upload-progress probe from the requests carrying execution payloads. All times are UTC.
| Observed | Request pattern | Evidence in the capture |
|---|---|---|
| 21 October, 20:44 | Upload-progress probe | A multipart POST / with an upload-progress marker and a one-byte file containing a null byte |
| 22 October, 13:54 | PHP2Shell-style exploit attempt | Session fields, 149 repeated binary parts and an embedded shell downloader |
| 22 October, 20:59 | PHP2Shell-themed upload-progress injection | PHP downloader code inside PHP_SESSION_UPLOAD_PROGRESS, with a php2shell argument passed to the shell |
The distinction is useful when prioritizing alerts. A small request that tests upload-progress behavior calls for different analysis from a body carrying repeated binary structures and an execution command. The payload provides that context.
Repeated binary structures and a downloader
At 13:54 on 22 October, a request from 85.11.167[.]243 arrived with a declared body length of 62,929 bytes. Its headers included the User-Agent php2shell-109618 and a PHPSESSID cookie. The multipart body supplied the same session identifier and the field PHP_SESSION_UPLOAD_PROGRESS.
The most distinctive feature was 149 t[] fields containing identical 288-byte binary values. Each value included the string system and a command to retrieve /s from 92.118.112[.]100 using wget, then pipe the response to sh.
Repeated binary values are consistent with an allocation spray: an attempt to populate memory with structures an exploit expects to encounter. Here, the embedded function name and downloader command also show the intended execution step.
The following is a structural summary of the captured request. Binary values and session identifiers are abbreviated, and the destination is masked.
POST /lib/phpunit/phpunit/Util/PHP/eval-stdin.php
Host: [sensor]
User-Agent: php2shell-109618
Content-Type: multipart/form-data; boundary=B7kQpoc618
Content-Length: 62929
Cookie: PHPSESSID=[session]
Multipart fields:
PHPSESSID [same session]
PHP_SESSION_UPLOAD_PROGRESS x
f file part with repeated A bytes
t[] 149 identical 288-byte binary values
g file part with repeated C bytes
Strings inside each binary value:
system
[wget retrieves a script from 92.118.112[.]100/s and pipes it to sh]
The URL resembles a familiar PHPUnit exploit target. The body supplies the more specific evidence: session upload-progress input, a repeated binary layout and a downloader embedded throughout the spray. This is why our analysis follows the request contents as well as the path.
The same principle applies to the User-Agent. Its CVE number is a label chosen by the sender. The combination of body structure and execution content supports the PHP2Shell assessment; attributing a particular memory-corruption path requires analysis of the vulnerable runtime.
PHP code inside the upload-progress field
At 20:59 on 22 October, a request from 77.90.185[.]20 targeted /index.php. It used a multipart body and a PHPSESSID cookie, but carried its execution content directly in the value of PHP_SESSION_UPLOAD_PROGRESS.
The field contained PHP code with three observable behaviors:
- Print the marker
__START__. - Call
system()with a downloader that trieswget, falls back tocurl, and passes the retrieved script toshwith the argumentphp2shell. - Print the marker
__END__.
Both download alternatives referenced hxxps://217.60.102[.]5/sh. The surrounding body included numbered filler fields and a file-upload part.
This is a PHP2Shell-themed upload-progress injection attempt. The response markers give the sender recognizable output to look for if execution occurs. The downloader fallback reveals an effort to accommodate different server environments. These details give defenders useful search terms for request inspection and follow-on process or network activity.
Taken together, the two requests show different payload constructions aimed at a similar next step: retrieving a script and handing it to a shell on the target server.
Indicators from the captured requests
These indicators come from the two execution attempts described above. Addresses and URLs are defanged. The download destinations were embedded in the inbound payloads.
| Indicator | Observed role | Date |
|---|---|---|
85.11.167[.]243 |
Source of the request carrying the repeated binary payload | 22 October 2026 |
hxxp://92.118.112[.]100/s |
Script download destination embedded in that payload | 22 October 2026 |
77.90.185[.]20 |
Source of the upload-progress PHP injection request | 22 October 2026 |
hxxps://217.60.102[.]5/sh |
Script download destination in the injected PHP code | 22 October 2026 |
php2shell-109618 |
User-Agent on the binary-payload request | 22 October 2026 |
B7kQpoc618 |
Multipart boundary on the same request | 22 October 2026 |
Use address matches as starting points for investigation. The more durable hunting pattern is the combination of multipart input, session upload-progress fields, repeated binary data or executable PHP, and a script-download command.
Turn the observations into action
Update the PHP runtime and restart its workers. The PHP2Shell fixes shipped in 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Install those fixes or a later supported release containing them. For distribution packages, verify the vendor's fixed package version. Check the runtime serving web requests, including bundled PHP and container images. PHP release guidance
Apply the 23 October upload-progress guidance. PHP subsequently advised setting session.upload_progress.enabled=0 until the next regular bugfix release for the separate CVE-2026-115560. It concerns an unusual setup that switches the session serializer from php_binary or php_serialize to php at runtime while upload progress remains enabled. Review that configuration alongside the PHP2Shell update. PHP follow-up advisory
Hunt across the request, response and host. Start with the patterns in the captures:
- Inspect multipart requests containing
PHP_SESSION_UPLOAD_PROGRESStogether with repeated binary fields, PHP code or downloader commands. - Correlate those requests with PHP memory errors, worker restarts and unusual response cookies or output markers.
- Look for PHP or web-server workers launching
sh,wgetorcurl, and for outbound connections to the embedded download destinations. - Review unexpected files and scheduled tasks around matching activity. Where investigation identifies credential exposure, rotate the affected secrets.
Keep the request body with the alert wherever possible. In the binary-payload capture, the body explains the attempt far more clearly than the endpoint name alone.
Attack intelligence that supports the next decision
Cypho's Attack Intelligence uses Siren sensors to record incoming attack traffic and preserve the requests behind the findings. PHP2Shell shows the practical value: a security team can examine how an attempt was constructed, identify the intended download destination and build searches around observed behavior.
Alongside Attack Surface Management, that evidence helps teams prioritize exposed PHP services and focus investigation on the infrastructure they operate. The advisory identifies what needs fixing. The captured request gives the team concrete details to investigate while the update is deployed.
Explore Cypho Attack Intelligence or book a demo to see how captured attack evidence supports your team's investigations.