PHP2Shell: Two Critical PHP Vulnerabilities (CVE-2026–109618 and CVE-2026–109619) — Are Your…

PHP2Shell: Two Critical PHP Vulnerabilities (CVE-2026–109618 and CVE-2026–109619) — Are Your Servers Ready? ( + KQL Queries)

Two critical vulnerabilities affecting PHP have been disclosed ahead of their scheduled security release.

The vulnerabilities, tracked as CVE-2026–109618 and CVE-2026–109619 and commonly referred to as PHP2Shell, have received a CVSS v4.0 score of 9.2 from the PHP security team.

An emergency security release is scheduled for October 21, 2026, at 14:00 UTC. At the time of writing, the official affected version ranges and complete technical details have not yet been published. Initial reports suggest that older PHP versions may also be affected.

While waiting for the official advisory, I wanted to explore what we can already investigate using Microsoft Defender XDR and KQL. The objective is not to detect these two vulnerabilities directly. Without confirmed exploitation details, that would be premature. Instead, we can identify PHP installations, investigate suspicious process execution, review network connections, and establish a baseline of PHP-related activity.

Here are a few hunting queries worth exploring.

1. Identifying PHP installations and versions

Before investigating potential exploitation, we need to understand where PHP is installed. Microsoft Defender Vulnerability Management provides software inventory information through the DeviceTvmSoftwareInventory table.

One important detail: searching for every software name containing php will also return PHP libraries and packages such as php-json, php-symfony or php-psr-http-message. Their software versions are not PHP runtime versions.

For this reason, I prefer to start with packages that are more likely to represent the PHP interpreter.

DeviceTvmSoftwareInventory
| where SoftwareName matches regex
@"(?i)^php([0-9]+(\.[0-9]+)?)?(_for_linux)?$"
or SoftwareName matches regex
@"(?i)^php[0-9]+(\.[0-9]+)?-(cli|fpm|cgi|common)$"
| extend VersionFromName =
extract(@"(?i)^php([0-9]+(?:\.[0-9]+)?)",
1, SoftwareName)
| extend VersionFromPackage =
extract(@"^(?:\d+:)?(\d+\.\d+(?:\.\d+)?)",
1, SoftwareVersion)
| extend PHPVersion = iff(
isnotempty(VersionFromName),
VersionFromName,
VersionFromPackage
)
| extend Major = toint(split(PHPVersion, ".")[0]),
Minor = toint(split(PHPVersion, ".")[1])
| extend Priority = case(
Major < 8, "Legacy PHP",
Major == 8 and Minor <= 1, "End of Life",
Major == 8 and Minor >= 2, "Verify security updates",
"Unknown"
)
| summarize
Devices = dcount(DeviceId),
DeviceList = make_set(DeviceName, 100)
by SoftwareName, SoftwareVersion,
PHPVersion, Priority
| order by Devices desc

This query helps identify legacy installations and prioritize further investigation. Keep in mind that software inventory is not always complete. PHP can also be bundled with third-party applications, installed in containers, or deployed outside standard package managers. Additionally, Linux distributions may backport security fixes without changing the upstream PHP version. The version alone does not always tell the complete story.

2. PHP spawning suspicious processes

One of the first things I would investigate is PHP or web server processes spawning operating system commands. Under normal circumstances, depending on the application, a PHP worker may not need to launch shells or system utilities. Examples worth investigating include:

  • php-fpm → sh
  • apache2 → bash
  • php-cgi.exe → cmd.exe
  • w3wp.exe → powershell.exe
  • httpd → curl

We can investigate these relationships using DeviceProcessEvents:

let WebProcesses = dynamic([
"php", "php.exe",
"php-cgi", "php-cgi.exe",
"php-fpm",
"apache2", "httpd",
"nginx", "w3wp.exe"
]);
let SuspiciousProcesses = dynamic([
"sh", "bash", "dash", "zsh",
"cmd.exe", "powershell.exe", "pwsh.exe",
"curl", "curl.exe", "wget",
"python", "python3", "python.exe",
"perl", "nc", "ncat", "socat",
"certutil.exe", "bitsadmin.exe"
]);
DeviceProcessEvents
| where Timestamp > ago(30d)
| where InitiatingProcessFileName in~ (WebProcesses)
or InitiatingProcessFileName startswith "php-fpm"
| where FileName in~ (SuspiciousProcesses)
| project
Timestamp,
DeviceName,
AccountName,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
FileName,
ProcessCommandLine,
FolderPath,
SHA1
| order by Timestamp desc

The interesting part is the relationship between the parent process and the child process.

Finding bash or curl on a Linux server is not particularly interesting. Finding bash launched by a PHP worker handling external requests deserves more attention. Of course, legitimate applications can execute system commands. Results should be reviewed against the application’s expected behavior. Also, not every PHP-FPM or web server process will have one of these exact names. The query may need to be adapted to the environment.

3. Looking for reconnaissance command

After obtaining command execution on a server, attackers may try to understand the environment. Common commands include:

whoami, id, uname, hostname, ipconfig, ifconfig and systeminfo.

Rather than searching for these commands across every process, we can focus on processes started by PHP or web server components.

DeviceProcessEvents
| where Timestamp > ago(30d)
| where InitiatingProcessFileName has_any (
"php", "apache", "httpd", "nginx", "w3wp"
)
| where FileName in~ (
"whoami", "whoami.exe",
"id", "uname", "hostname", "hostname.exe",
"ifconfig", "ipconfig.exe",
"systeminfo.exe"
)
| project
Timestamp,
DeviceName,
AccountName,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
FileName,
ProcessCommandLine
| order by Timestamp desc

This is a relatively simple query, but it can help identify early post-exploitation activity. The parent-process filter is important. Running whoami from an interactive administrative shell is different from running it through a web server process.

4. PHP creating files in suspicious locations

Another behavior worth investigating is PHP creating files in temporary directories or web application folders. Huntress recently documented a separate PHP abuse case involving temporary PHP files that were created, executed and subsequently removed. That incident was not attributed to PHP2Shell, but the behavior is relevant when investigating possible web application compromise. Using DeviceFileEvents, we can look for PHP files created or modified by web-related processes:

DeviceFileEvents
| where Timestamp > ago(30d)
| where ActionType in~ (
"FileCreated",
"FileModified",
"FileRenamed"
)
| where FileName endswith ".php"
or FileName endswith ".phtml"
| where InitiatingProcessFileName has_any (
"php", "apache", "httpd", "nginx", "w3wp"
)
| where FolderPath contains "/tmp/"
or FolderPath contains "/var/tmp/"
or FolderPath contains "/dev/shm/"
or FolderPath contains "/var/www/"
or FolderPath contains "wwwroot"
| project
Timestamp,
DeviceName,
ActionType,
FileName,
FolderPath,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
SHA1
| order by Timestamp desc
A PHP file created in a web directory is not necessarily malicious. However, unexpected file creation by a web server process, particularly in a temporary directory, is worth investigating.

For more advanced analysis, I would also look at files created and deleted within a short period of time. That can help identify temporary payload execution.

5. Investigating outbound network connections

If an attacker obtains code execution through a vulnerable PHP application, one possible next step is establishing an outbound connection. This could involve downloading additional payloads, contacting external infrastructure or establishing a reverse shell.

Using DeviceNetworkEvents, we can identify outbound connections initiated by PHP and web server processes.

let WebProcesses = dynamic([
"php", "php.exe",
"php-cgi", "php-cgi.exe",
"php-fpm",
"apache2", "httpd",
"nginx", "w3wp.exe"
]);
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where ActionType == "ConnectionSuccess"
| where RemoteIPType == "Public"
| where InitiatingProcessFileName in~ (WebProcesses)
or InitiatingProcessFileName startswith "php-fpm"
| summarize
Connections = count(),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp),
Ports = make_set(RemotePort, 30),
URLs = make_set(RemoteUrl, 20)
by DeviceName,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
RemoteIP
| order by Connections asc

Here I would pay particular attention to destinations that are rarely contacted, unusual ports and connections that occur shortly after suspicious process execution. One limitation is that some PHP applications legitimately communicate with external APIs, payment gateways, update services and other Internet resources.

6. Finding new child processes: PHP execution baseline

This is probably the hunting approach I find most interesting. Instead of looking only for a predefined list of suspicious executables, we can compare recent PHP-related process execution with historical activity.

For example, suppose a PHP server has been running for several weeks and has never launched python3. Suddenly, php-fpm starts executing python3. That does not automatically mean compromise, but it is a change worth reviewing. We can use a 28-day baseline and compare it against the last two days.

let WebProcesses = dynamic([
"php", "php.exe",
"php-cgi", "php-cgi.exe",
"php-fpm",
"apache2", "httpd",
"nginx", "w3wp.exe"
]);
let Baseline =
DeviceProcessEvents
| where Timestamp between (ago(30d) .. ago(2d))
| where InitiatingProcessFileName in~ (WebProcesses)
or InitiatingProcessFileName startswith "php-fpm"
| distinct
DeviceId,
InitiatingProcessFileName,
FileName;
DeviceProcessEvents
| where Timestamp > ago(2d)
| where InitiatingProcessFileName in~ (WebProcesses)
or InitiatingProcessFileName startswith "php-fpm"
| join kind=leftanti Baseline
on DeviceId,
InitiatingProcessFileName,
FileName
| summarize
Executions = count(),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp),
Commands = make_set(ProcessCommandLine, 10)
by DeviceName,
InitiatingProcessFileName,
FileName
| order by Executions asc

This approach is not specific to PHP2Shell. It can also help identify unexpected behavior resulting from other web application vulnerabilities. There are some limitations: the historical baseline depends on telemetry retention, endpoint coverage and the stability of the application. New deployments and legitimate maintenance activities can introduce new process relationships. Still, comparing behavior before and after a vulnerability disclosure is something I find useful during threat hunting investigations.

7. What about HTTP requests and web server logs?

Endpoint telemetry is only one part of the investigation. If Apache, Nginx, IIS or WAF logs are available in Microsoft Sentinel, I would also investigate:

  • Unusual HTTP POST requests targeting PHP applications.
  • Repeated HTTP 5xx responses from the same source.
  • Unexpected PHP worker crashes or restarts.
  • Suspicious HTTP requests followed by new process execution.
  • Changes in request volume or behavior around the disclosure date.

Some preliminary technical discussions mention multipart requests and PHP session upload handling. However, until the technical details are officially confirmed, I would treat these as research leads rather than validated exploitation indicators.

For me, the most useful investigation would be correlating an unusual HTTP request with subsequent process execution or network activity on the same server.

The exact KQL will depend on the web server and WAF log schema being ingested into Sentinel.

Final notes

These queries are starting points for threat hunting in Microsoft Defender XDR, not validated detections for CVE-2026–109618 or CVE-2026–109619. They depend on endpoint telemetry being available, particularly on Linux servers where PHP is commonly deployed.

I would start by identifying PHP installations, prioritizing Internet-facing servers, and reviewing unexpected process execution. For unsupported PHP versions, upgrading or restricting exposure should be considered while the affected versions and available patches are confirmed.

References

PHP2Shell: Two Critical PHP Vulnerabilities (CVE-2026–109618 and CVE-2026–109619) — Are Your… was originally published in Detect FYI on Medium, where people are continuing the conversation by highlighting and responding to this story.

Introduction to Malware Binary Triage (IMBT) Course

Looking to level up your skills? Get 10% off using coupon code: MWNEWS10 for any flavor.

Enroll Now and Save 10%: Coupon Code MWNEWS10

Note: Affiliate link – your enrollment helps support this platform at no extra cost to you.

Article Link: https://detect.fyi/php2shell-two-critical-php-vulnerabilities-cve-2026-109618-and-cve-2026-109619-are-your-3f0a0c08f6ec?source=rss----d5fd8f494f6a---4