Command Zero
Threat

Hunting PHP Exploitation: CVE-2026-109618 and CVE-2026-109619

Two Defender KQL hunts for PHP2Shell, one for evidence of exploitation in endpoint data and one for unpatched, internet-reachable hosts, chained into an investigation that ends in a verdict.

Princely Dmello — avatarPrincely DmelloOctober 31, 2026 · 10 min read
Hunting PHP Exploitation: CVE-2026-109618 and CVE-2026-109619 — cover image

What happened

Two memory-safety flaws in the PHP core runtime leaked on 20 October 2026, before the planned disclosure date. The PHP security team shipped an out-of-band release the next day:

CVE-2026-109618: "Out-of-memory handling can interrupt PHP while internal request data is only partially initialized. Request cleanup may then treat the invalid data as valid."

CVE-2026-109619: "Request-owned internal state can survive after its backing memory has been freed. A later request handled by the same worker may use that stale state before normal initialization resets it."

Both are rated CVSS 9.2 critical: unauthenticated remote code execution and memory disclosure across every PHP version from 5.4 through 8.5.11. PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 shipped on 21 October; 8.1 and earlier are end of life.

Exploitation predates the release. Proof-of-concept code leaked from escrow and circulates as “php2shell”, and researchers have demonstrated unauthenticated RCE against current WordPress, Drupal and Joomla images. Amazon detected an attempt on 17 October, four days before the release, though it is unclear whether it would have worked against a real system. Attempts in the wild have continued since, and the Canadian Centre for Cyber Security has issued an advisory.

A patch closes the exposure. It does not tell you whether something already came through. A compromised PHP process does things a healthy one never does: it spawns a shell, writes a .php file into web content, opens an outbound connection, registers a task.

Two hunts: exploitation and exposure

Two different questions, two different sources. One asks whether something already happened on the endpoint; the other asks where this could land at all.

The hunt for evidence of exploitation reads the endpoint event tables. Mehmet Ergene published a broad query for this. Rather than return every event PHP generates, it groups the window into distinct combinations of device, action, file, command line and remote address, and records when each was first seen.

KQL hunting query for PHP2Shell exploitation: searches Device*Events where the initiating process is PHP, filters out routine file, image-load, loopback and FPM worker noise, and summarizes first-seen activity per device, action, file, command line and remote address

Widen the lookback to cover 17 October, the earliest attempt reported publicly. Fourteen days will not reach it for long. On Advanced Hunting, swap TimeGenerated for Timestamp.

Validating the PHP hunting query as a custom question in Command Zero

The hunt for exposure reads the software inventory instead, and joins it to the exposure graph:

KQL hunting query for PHP2Shell exposure, part 1: finds PHP versions in DeviceTvmSoftwareInventory below the fixed patch for branches 8.2 to 8.5 and summarizes them per deviceKQL hunting query for PHP2Shell exposure, part 2: joins ExposureGraphNodes to show which unpatched non-workstation hosts are exposed to the internet, with public IP, ports, source CIDR and RCE exploitability

This returns hosts running an unpatched PHP and shows which of them are reachable from outside. The version test compares each branch against the patch that fixed it, so 8.2.4 is not mistaken for 8.2.35, and 8.1 and earlier count as unfixed because no patch exists for them.

Read the exposure columns rather than trusting the flag. exposedToInternet covers any reachability at all: a workstation with PHP on disk and RDP open to the world is exposed, but nothing is serving web requests through that runtime. Workstations are dropped for that reason, and ExposedPorts shows what the rest are reachable on.

Hosts that are not exposed still come back with the exposure columns empty. That is the patch backlog rather than the urgent list. Empty can also mean the graph has no record of the host, so read it as unknown. Use kind=inner for exposed hosts alone.

Both become custom questions, and the part that changes how they are used is field mapping: each output column is bound to a lead type.

Field mapping, binding DeviceName to Host Name, FileName and the initiating process names to File Name, and DeviceId to a Defender for Endpoint machine ID

DeviceId becomes a Defender machine ID, DeviceName a host name, and the file and process names become file names. Those are leads the next question can take directly, and they are what let the two hunts meet on the same device.

From a query to an investigation

A query returns rows; an investigation returns an assessment. Start with any device that appears in both hunts: unpatched, reachable, and showing activity PHP does not normally produce.

The investigation chains the applicable questions together. Command Zero ships a Web Server Compromise Investigation that takes a Defender machine ID, which is why both hunts return one. Two of its questions carry this scenario, and neither needs any knowledge of PHP internals:

  • What child processes were spawned by web server processes on this device? A web server spawning cmd.exe, powershell.exe or sh is the behaviour that follows a web-tier exploit.
  • What script files were written to web content directories on this device? A script in a web root is what a successful exploit leaves behind.
The machine ID fanning out into the investigation's questions against Defender for Endpoint

The rest fill in the background: machine properties, existing Defender alerts and antivirus detections, services installed, scheduled tasks, and logons reaching the host. That context tells you whether the first two findings stand alone.

It then chains deeper. The child processes feed what network connections were initiated by this process or its descendants, because the interesting connection is rarely made by the shell itself. Each process can then be pursued on its own (file actions, device events, registry changes, images loaded), turning one spawned shell into a full account of what it touched.

Each process the investigation surfaces fanning out again into its own file, network, registry and child-process questions

That second fan-out is the part that does not scale by hand: every process becomes its own branch, each asking the same six questions.

Applying the verdicting engine

All of that still leaves an analyst reading eight result sets. An investigation can carry conclusions: statements evaluated automatically against the results beneath them, each with a confidence rating, a severity and a MITRE mapping.

Web server spawned a shell: high confidence, high severity, T1059. Raised when the child-process question returns a command interpreter.

Script written to web root: medium confidence, high severity, T1505.003. Medium is deliberate. A script in a web root is far more often a deployment file than a webshell, and a verdict that overstates its case teaches analysts to ignore it.

The engine then writes the case up: verdict, impact, severity, confidence, and a narrative of what happened in order. The example below comes from a lab host running a vulnerable PHP server. This activity did not exploit CVE-2026-109618 or CVE-2026-109619, but what followed is the shape this hunt looks for:

PHP Application Server Remote Code Execution via Command Injection

Verdict: Compromised · Impact: High · Severity: Critical · Confidence: High

The PHP runtime php.exe, serving an application through Apache, ran reconnaissance commands via shell_exec(), whoami, net user, systeminfo, tasklist) across 13 invocations. It also spawned cmd.exe children running ping injection tests, network enumeration, Base64-encoded PowerShell, and a file download into the web root. Network telemetry confirms the download reached an external address. No controls blocked the activity and no alerts fired.

Confidence is High rather than Confirmed because: the download reached an external address but the endpoint data does not confirm the file reached disk; whether the commands came from inbound HTTP or an interactive session is inferred from the process chain, not observed in web server logs; and how the actor obtained a shell in the first place is not evidenced at all.

That last paragraph is the part worth having: the engine states what it could not establish, so the verdict can be argued with rather than simply accepted.

Exploits change, the behaviour does not

Sooner or later the next critical web-tier bug will land, likely in a different language, reached through a different parser, triggered by a payload that looks nothing like php2shell. A hunting query written against the exploit expires with it. One written against the behaviour that follows does not, and that behaviour is neither PHP- nor platform-specific, so the same hunt still applies whatever the next web-tier bug and stack turn out to be.

What happens after the exploit lands has changed little in a decade. Struts, Log4Shell, ProxyShell, MOVEit and php2shell are different flaws with the same sequence on the host: a web server becomes the parent of a process it has no business parenting, and that child orients itself, often reaching back out. A web-tier exploit gives the attacker a way to run commands, not a ready-made session, so the first thing they do is get their bearings: which account, which host, what else is reachable.

The parent-child relationship is the constant, and the Command Zero catalog includes a hunting question that keys on it:

What devices have a web server process launching anomalous child processes according to Microsoft Defender for Endpoint?

It looks across web server processes and surfaces those spawning an anomalous child (a command shell, reconnaissance or execution tooling, a living-off-the-land binary) rather than matching any one exploit's signature.

What makes it a hunt rather than an alert feed is how it is tuned: it separates the handful of devices that stand out from the routine automation every estate runs, so what comes back is a short list of machine IDs to feed into the per-device investigation above.

What to do now

  • Patch now, internet-facing first. Upgrade to 8.5.12, 8.4.27, 8.3.36 or 8.2.35. On 8.1 or earlier there is no fix coming, and the upgrade is the remediation.
  • Put WAF coverage in front of what you cannot patch today. Major WAF and CDN providers shipped rules for the known exploit vectors on 21 October. Virtual patching buys time; it does not close the flaw.
  • Run both hunts. The exposure hunt scopes the estate, and the exploitation hunt reads the endpoint across the window your retention allows. Feed the hosts they name into the investigation.
  • Rotate secrets on exposed hosts. The memory-disclosure path returns worker memory to the client without running code, so it leaves nothing for EDR to see. If an exposed host held session tokens, API keys or passwords, assume they may be out, rotate them, and check where they were used next.
  • Record what an empty result means. No findings from a host with no sensor is an absence of telemetry, not evidence.

What to look for

Signal

Where

PHP process spawning cmd.exe, powershell.exe, sh, bash, python

DeviceProcessEvents

New .php file written under a web content directory

DeviceFileEvents

Executable written by a PHP process

DeviceFileEvents

Outbound connection from a PHP process or its descendants

DeviceNetworkEvents

Scheduled task or service created by a web server process

DeviceEvents

Web server worker crashes (SIGSEGV) around failed exploit attempts

Web server and OS logs

PHP 5.4 – 8.5.11 on any internet-facing host

Defender Vulnerability Management

That crash signal is the one most likely to be sitting unread in web server logs rather than in EDR.


Related reading: The Patch Window Is Gone: What PHP2Shell and Storm-0940 Tell Us About the Investigation Clock, Eric Hulse on why the window between disclosure and exploitation has closed, and what that means for how fast investigations have to run.

Credit to Mehmet Ergene for the original hunting query.

Keep reading

More from Threat.

Get Started

See what your team can achieve.

Live in under an hour. No migration. No friction.

Book a Demo
No training data requiredSOC 2 CompliantDirect-to-data