New research How Rover caught a PAN-OS authentication bypass attempt (CVE-2025-0108) Baku · Dubai

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

Oct 22, 2026  /  Cypho Research Team  /  7 min read

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

  1. PHP is building request data

  2. Fails

    Out of memory: PHP stops while the data is only half-initialized

  3. Cleanup treats the half-built data as valid: memory corruption, code execution

CVE-2026-109619Stale state

  1. Request A: PHP keeps a pointer to request memory in a long-lived variable

  2. Fails

    The request fails: its memory is freed, the pointer is not cleared

  3. Request B on the same worker uses the stale pointer: leak, corruption, code execution

Figure 1. Simplified failure paths from PHP's advisories. Stale state can also be recreated by shutdown diagnostics; the article explains the worker-specific conditions.

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 tries wget, falls back to curl, and passes the retrieved script to sh with the argument php2shell.
  • 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_PROGRESS together 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, wget or curl, 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.

Unknown threats are unstoppable. Until we expose them.

Send us your company domain. We'll walk you through what's already out there about you and how Cypho would handle it, with one of our analysts on the call.

Or write to [email protected]

We'll use your details to respond to your request. See our privacy policy.