Blog
10.27.26

59 Reports, 1 Threat, 4 Detections - Solving PHP2Shell

Chris Macon
Product Manager

TL;DR

Between 20 and 25 October, PHP2Shell produced fifty-nine separate reports in one customer's threat intelligence feed. Fifty-nine reports describing one thing. Kai grouped and summarized them into a single threat view with twenty-three mapped techniques, assessed detection coverage for that environment as not covered, and then used the intel to generate four validated detections: two SIEM rules that watch for the attack from now on, and two threat hunts that sweep thirty days of history to answer whether it already happened. That second half is the part a patch cannot answer and the part most programs never get to. This is what the path from feed to deployed rule actually looked like.

Fifty-nine reports describing one thing

The feed did what feeds do under a major disclosure. PHP2Shell — CVE-2026-109618 and CVE-2026-109619, two unauthenticated remote code execution flaws in the PHP interpreter — broke on 20 October, and over the following five days the customer's intel provider filed fifty-nine separate reports on it.

None of those reports were wrong. They were updates, reconfirmations, vendor advisories, actor attributions, each one arriving as its own item demanding its own triage decision. This is the failure mode of a working intelligence program: the signal is genuinely there, and it arrives in a shape nobody can act on. An analyst reading fifty-nine reports learns roughly what an analyst reading three would have learned, several hours later.

Kai collapsed them into one threat record. One title — PHP critical security vulnerabilities exploited — with a single identifier, a first-reported and last-reported date, and a summary that carries the detail that actually changed decisions: the flaws affect PHP releases dating back to 5.4, the emergency update covers 8.5.12, 8.4.27, 8.3.36, 8.2.35, 8.1, 8.0.x and 7.4, end-of-life versions are excluded, and the actors preparing to exploit were linked to North Korea's Lazarus group.

Alongside it, two assessments that matter more than the summary. Relevance was graded Standard rather than critical, with the reasoning stated plainly — the exploitation involves a presumed enterprise platform and a high-risk actor, but does not directly target this customer's sector. And detection coverage for that environment was assessed as not covered.

That second line is the one that turns intelligence into work. It is not "here is a thing that happened." It is "here is a thing that happened, and you cannot currently see it."

‍

Exhibit A — Fifty-nine reports over five days, collapsed into one threat record with 23 mapped techniques and a coverage verdict.

‍

From intel to detection engineering

Most tooling stops at the summary. The summary is where the intel product ends and the detection engineering backlog begins, and the gap between them is measured in engineer-weeks.

Kai used the threat record to generate the detections directly. Four of them, written as KQL for Microsoft Sentinel and built on the Defender for Endpoint events that tenant already ingests — not a generic rule template, but something that runs against the telemetry the customer actually has.

The split is the important part. Two of the four look forward. Two look backward.

The two that watch from now on

The first SIEM rule covers process creation: a PHP worker spawning a shell or a download tool. The logic follows from how the attack has to proceed. Once an attacker can run code through a PHP worker — php-fpm, php-cgi, Apache mod_php, FrankenPHP, or PHP under IIS — every subsequent step is a process that worker should never start. A shell or script interpreter. Recon commands like whoami, id, uname. Download tooling such as curl, wget or certutil. Reverse-shell command lines using /dev/tcp, fsockopen or mkfifo. It catches chains through an intermediate shell too, so php-cgi → cmd.exe → whoami does not slip past.

The second covers network connections, and it exists because the first one has a blind spot. If the attacker never starts a process — a PHP-native reverse shell or beacon opened with fsockopen or stream_socket_client, straight out of the worker — there is no child process to catch. So the second rule watches for a PHP worker making an outbound connection to an unusual port, treating the common web, DNS, NTP, LDAP, database and cache ports as expected and leaving callbacks over 80 and 443 unflagged.

Both arrive carrying their own tuning guidance, which is the part that usually gets skipped and is the reason most generated rules get switched off within a week. Exclude CMS plugins, composer, wp-cli, image processing and PHP cron or backup scripts by host plus a job-specific command token, never by binary name alone. Expect more noise from IIS w3wp.exe parents than from PHP ones. Add the environment's own backend, SMTP and API ports to the expected list before alerting, including backend ports reached by Apache acting as a reverse proxy.

Both are mapped to MITRE ATT&CK — Execution (TA0002), Discovery (TA0007), Command and Control (TA0011) — and both carry a validated status, having been backtested against the customer's own history before anyone was asked to deploy them.

‍

Exhibit B — Why there are two rules. The process rule cannot see a PHP-native callback that starts no child process; the network rule can.

The two that look back

This is the half that distinguishes the exercise, and it exists because of a specific fact about this vulnerability: exploitation began before the patch did. The write-up leaked on 20 October; PHP shipped fixes on 21 October. Every organization running PHP had a window it could not defend, followed by however many more days it took to actually deploy and restart every worker pool.

A forward-looking rule deployed on 26 October says nothing about that window.

So Kai generated two hunts with a thirty-day lookback. The network hunt sweeps history for the same command-and-control behavior as the network rule, but ranks destinations by rarity rather than filtering them — so a port only one host has ever used, first seen this week, rises to the top, while the same worker talking to the same database every day sinks. Ranking rather than filtering means rare destinations still surface even on ports the filter would have called expected.

The process hunt does the equivalent over process history, scoring each parent-child chain on how many behavioral categories it triggered, whether a reverse-shell pattern appeared, how recently it was first seen, and how few days it spans. A chain that showed up once, this week, matching a reverse-shell pattern scores high. A nightly cron job that has run for a year scores near zero.

Both are validated, and both produce a retrohunt result over the last thirty days — the answer to a question the patch cannot address.

‍

Exhibit C — Four detections, two directions. Two SIEM rules watch forward from deployment; two hunts sweep thirty days back, because exploitation began before the fix shipped.

What this actually replaces

It is worth being concrete about the alternative, because the comparison is the whole argument.

Without this, a competent team reads some portion of fifty-nine reports, writes their own detection logic against whatever telemetry they happen to have, tunes it against their own traffic so the on-call engineer is not buried in alerts from legitimate shell-outs, validates it, deploys it, and then — if there is any time left, and there usually is not — writes a second set of queries to go back through history and check whether the thing already happened. That is a week of skilled engineering time per significant advisory, and significant advisories do not arrive one at a time.

The teams that skip a step almost always skip the same one. They deploy the forward-looking rule and never write the retrohunt, because the forward-looking rule is the one that feels like progress and the retrohunt is the one that might surface something nobody wants to find on a Friday.

Fifty-nine reports in, four validated detections out, with the backward-looking half included rather than deferred.

The feed told us what happened to the world. The detections tell you what happened to you.

‍

‍