Skip to content

Add detection rule for PHP worker shell-spawn (post-exploitation, generic) - #15377

Open
rjmendez wants to merge 19 commits into
Azure:masterfrom
rjmendez:phpup-2026-detection-rules
Open

rjmendez wants to merge 19 commits into
Azure:masterfrom
rjmendez:phpup-2026-detection-rules

Conversation

@rjmendez

@rjmendez rjmendez commented Oct 21, 2026 •

Copy link
Copy Markdown

Summary

Adds one Microsoft Sentinel Analytics Rule template:
Detections/DeviceProcessEvents/phpup2026-PHPShellSpawn.yaml - a shell
or reconnaissance tool spawned directly under a PHP worker process
(php-fpm, lsphp, or Apache mod_php). Generic PHP child-process-monitoring
indicator; CVE attribution is explicitly unvalidated (see the rule's own
description).

History (why this PR shrank from three rules to one)

This PR went through several rounds of review and rewrite:

  1. Original submission: three rules built on a single-request
    multipart-stall heap-spray mechanism taken from a leaked PoC
    artifact's own claims.

  2. First rewrite: VulnCheck independently reported that public PoCs
    reviewed (plausibly including the one this analysis started from) do
    not have the correct mechanism, and a real lab reproduction of the
    old mechanism's documented precondition produced a clean 200 OK,
    not a crash. Rewrote all three rules around the actual PHP fix
    commit (php/php-src 82f8f31b16a, "Avoid state corruption via
    bailout") instead of the PoC's claims.

  3. Second rewrite (prompted by Ofer Inbar (@oferInbar)'s review): fixed an
    under-inclusive literal "Content-Disposition" string match in the
    two AzureDiagnostics-based rules with a generic duplicate-header
    check.

  4. This round, removing two of the three rules entirely: Ofer Inbar (@oferInbar)'s
    follow-up review reported that both AzureDiagnostics rules fail
    KQL compilation against a live workspace (SEM0100: Failed to resolve scalar expression named 'requestBody_s'), and separately have a
    structural logic flaw (matching across MIME part boundaries rather
    than within one part, so any legitimate multi-field form submission
    would match). I independently verified against Microsoft's own schema
    reference
    (https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/agwfirewalllogs)
    that AzureDiagnostics/AGWFirewallLogs does not expose a raw
    request-body field at all - the closest column, DetailedData, only
    contains a snippet when a managed ruleset rule has already matched
    something, not a general-purpose field a custom query can pattern-match
    against. This isn't fixable by renaming a field; the data this
    detection needs isn't exposed by the log source at all. Removed
    phpup2026-UploadProgressOversizedPost.yaml and
    phpup2026-WorkerCrashPattern.yaml rather than attempt a further
    patch.

    Also fixed the remaining rule, phpup2026-PHPShellSpawn.yaml, per
    the same review round: added Apache mod_php coverage (the SAPI the
    advisory actually names for confirmed RCE, where PHP runs in-process
    inside the Apache worker rather than as a separate php-fpm binary),
    switched short substring matches ("sh", "id", "nc") to exact
    matching to stop false hits on unrelated binaries like openssh or
    cloud-init, and led the description with [Unvalidated] since CVE
    attribution for this rule was never independently confirmed (the
    reference capture used a direct shell_exec() test endpoint, not
    either CVE's actual mechanism).

Rule

File Table Signal
Detections/DeviceProcessEvents/phpup2026-PHPShellSpawn.yaml DeviceProcessEvents Shell/recon process spawned under a PHP worker (php-fpm, lsphp, or Apache mod_php) - generic post-exploitation indicator, CVE attribution explicitly unvalidated

Background on the underlying PHP vulnerability pair this started from
(CVE-2026-109618 / CVE-2026-109619, php/php-src commit 82f8f31b16a):
https://github.com/rjmendez/phpup-2026

🤖 Generated with Claude Code

@rjmendez
rjmendez requested review from a team as code owners October 21, 2026 07:10
Copilot AI balanced review requested due to automatic review settings October 21, 2026 07:10
@rjmendez
rjmendez marked this pull request as draft October 21, 2026 07:12
@rjmendez

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@v-atulyadav v-atulyadav added the Detection Detection specialty review needed label Oct 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The DeviceProcessEvents rule splits the username-only AccountName column on backslash (breaking the Account entity) and maps the FileHash Algorithm identifier to the hash-value column, both of which produce incorrect entity data.

2 open issues
What changed in this PR

This PR adds four standalone Microsoft Sentinel Analytic Rule templates under Detections/ that detect exploitation of the (community-reported) PHP session.upload_progress heap use-after-free pair CVE-2026-109618/109619. Three rules target IIS access logs (W3CIISLog) for POC-specific indicators and a worker-crash behavioral pattern, and one targets DeviceProcessEvents for post-RCE shell spawns under PHP worker processes. The rules fit the repository's convention for community-contributed standalone detections (valid GUIDs, required metadata block, valid connectorIds, MITRE mappings).

Changes:

  • Add two "exact/zero-FP" IOC rules (hardcoded POC User-Agent strings and multipart boundaries) on W3CIISLog.
  • Add one behavioral W3CIISLog rule correlating large multipart POSTs + PHPSESSID cookie + 200/502/503 crash ratio.
  • Add one behavioral DeviceProcessEvents rule for shell/recon processes spawned under php-fpm/lsphp/php.
File Description
Detections/​W3CIISLog/​phpup2026-POCUserAgent.yaml Flags POC User-Agent IOCs; column refs and entity mappings valid.
Detections/​W3CIISLog/​phpup2026-POCBoundary.yaml Flags POC multipart boundary IOCs; column refs and entity mappings valid.
Detections/​W3CIISLog/​phpup2026-WorkerCrashPattern.yaml Behavioral worker-crash correlation; scStatus-as-string usage consistent with existing W3CIISLog rules.
Detections/​DeviceProcessEvents/​phpup2026-PHPShellSpawn.yaml Post-RCE shell spawn detection; contains a broken Account entity mapping (AccountName split) and a malformed FileHash Algorithm mapping.

Review effort: Balanced

Comment thread Detections/DeviceProcessEvents/phpup2026-PHPShellSpawn.yaml Outdated
Comment thread Detections/DeviceProcessEvents/phpup2026-PHPShellSpawn.yaml Outdated
@rjmendez

Copy link
Copy Markdown
Author

Fixed in the latest commit.

Account entity — AccountName in DeviceProcessEvents is a plain username with no domain component; splitting on \ was wrong. Switched to InitiatingProcessAccountName / InitiatingProcessAccountDomain / InitiatingProcessAccountSid, which are the correct dedicated columns (matching the pattern in existing rules like SolarWinds_SUNBURST_Process-IOCs.yaml).

FileHash entity — Algorithm expects a literal string, not a hash-value column. Added | extend HashAlgorithm = "SHA256" in the query and mapped Algorithm -> HashAlgorithm, Value -> SHA256.

Version bumped to 1.0.1. Note: the two exact-string IOC rules visible in the review summary (POCUserAgent, POCBoundary) were intentionally removed from this PR prior to submission — only the two behavioral rules remain.

POCBoundary.yaml and POCUserAgent.yaml keyed on one released tool's
hardcoded multipart boundary and User-Agent strings — trivial to change,
won't survive a rewritten exploit. Replace with a structural proxy using
only standard W3C extended log fields (POST + PHPSESSID cookie + oversized
body), which complements WorkerCrashPattern.yaml by also catching a
one-shot exploit that never crashes a worker.
CI's NonAsciiValidations test requires detection YAML to be pure ASCII.
WorkerCrashPattern.yaml and PHPShellSpawn.yaml (U+2014 em-dash) and the
new UploadProgressOversizedPost.yaml (same) all had one. Replaced with
a plain hyphen in each.
…o this PR, not a modification to master, so the version-check script won't actually require this, but keeping version metadata consistent with PHPShellSpawn.yaml's bump)
@rjmendez
rjmendez marked this pull request as ready for review October 21, 2026 08:58
…remise

Both CVEs were originally treated as the same session.upload_progress
UAF. PHP's official 2026-10-21 advisory splits them: CVE-2026-109619 is
this bug; CVE-2026-109618 is a separate, unrelated OOM-corruption issue.
Corrected tags/descriptions to CVE-2026-109619 only across all three
rules.

Also flags that WorkerCrashPattern.yaml's 502/503 worker-crash signal is
unvalidated: a real PHP 8.3.6 lab given the documented trigger
precondition (a multi-second stall between multipart file parts)
returned a clean 200 OK, not a crash. See
https://github.com/rjmendez/phpup-2026 ANALYSIS.md's mechanism finding.
…remise

Both CVEs were originally treated as the same session.upload_progress
UAF. PHP's official 2026-10-21 advisory splits them: CVE-2026-109619 is
this bug; CVE-2026-109618 is a separate, unrelated OOM-corruption issue.
Corrected tags/descriptions to CVE-2026-109619 only across all three
rules.

Also flags that WorkerCrashPattern.yaml's 502/503 worker-crash signal is
unvalidated: a real PHP 8.3.6 lab given the documented trigger
precondition (a multi-second stall between multipart file parts)
returned a clean 200 OK, not a crash. See
https://github.com/rjmendez/phpup-2026 ANALYSIS.md's mechanism finding.
…remise

Both CVEs were originally treated as the same session.upload_progress
UAF. PHP's official 2026-10-21 advisory splits them: CVE-2026-109619 is
this bug; CVE-2026-109618 is a separate, unrelated OOM-corruption issue.
Corrected tags/descriptions to CVE-2026-109619 only across all three
rules.

Also flags that WorkerCrashPattern.yaml's 502/503 worker-crash signal is
unvalidated: a real PHP 8.3.6 lab given the documented trigger
precondition (a multi-second stall between multipart file parts)
returned a clean 200 OK, not a crash. See
https://github.com/rjmendez/phpup-2026 ANALYSIS.md's mechanism finding.
@rjmendez

Copy link
Copy Markdown
Author

Pushed a correction based on PHP's official advisory (published 2026-10-21, after this PR was opened) and a real lab reproduction:

CVE attribution fix. The advisory splits what this PR originally treated as one bug class into two unrelated CVEs: CVE-2026-109619 ("RCE via stale global state") is this session.upload_progress UAF; CVE-2026-109618 ("RCE via OOM corruption") is a separate, unrelated bug with a different root cause and no connection to session.upload_progress. Updated all three rules' tags/descriptions to CVE-2026-109619 only.

WorkerCrashPattern.yaml's premise is unvalidated. Built a real PHP 8.3.6 + nginx lab and reproduced the documented trigger precondition exactly — a multi-second stall between two multipart file parts, meant to force the second php_session_rfc1867_update() call and the UAF. Real result: a clean 200 OK, not a 502/503. Traced it in php-src too: progress->data is Z_TRY_ADDREF'd before being inserted into $_SESSION, so it's never owned only by the session array, and the refcount never actually hits zero when php_session_track_init() tears down the old session. Added an UNVALIDATED note to the rule's description rather than pulling it, since the other two rules (feature-presence precondition, oversized-body heuristic) don't depend on this premise and still look sound — but please don't merge WorkerCrashPattern.yaml as a working crash detector until/unless this is actually reproduced.

Full writeup: https://github.com/rjmendez/phpup-2026 (see ANALYSIS.md's 2026-10-21 correction notes and README.md's "Official status" section).

@oferInbar Ofer Inbar (oferInbar) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address the detection-quality and validation concerns below before these templates are presented as validated CVE detections. Please start each affected detection description with the literal [Unvalidated] until representative testing supports its CVE-specific claim. For the shell-spawn rule, this qualification concerns CVE attribution, not the general usefulness of PHP child-process monitoring. I acknowledge the existing UNVALIDATED paragraph in WorkerCrashPattern; the request is to make that status explicit at the beginning of the description and consistent across unsupported CVE-specific claims.

PHP's official advisory describes stale state crossing request boundaries, with a producer, an interruption/reset failure, and a later consumer on the same worker. It does not validate the community write-up's ordinary multipart-stall/dangling-counter explanation: GHSA-6wmf-4rv5-p3rp . The community analysis itself now disclaims that mechanism: https://github.com/rjmendez/phpup-2026/blob/bb1dee82e31d35daad4fdb0b60cec8fb83ef38e8/ANALYSIS.md#L20-L33 .

Please also align the PR title and summary with the corrected CVE scope. The current title/body still group CVE-2026-109618 and CVE-2026-109619 together, whereas the rule files now reference 109619 only. These comments are based on static review and published evidence, not execution against a live Sentinel workspace.

Comment thread Detections/DeviceProcessEvents/phpup2026-PHPShellSpawn.yaml Outdated
Comment thread Detections/W3CIISLog/phpup2026-UploadProgressOversizedPost.yaml Outdated
Comment thread Detections/W3CIISLog/phpup2026-WorkerCrashPattern.yaml Outdated
Comment thread Detections/W3CIISLog/phpup2026-WorkerCrashPattern.yaml Outdated
Moved the unvalidated caveat to the start of each description instead
of mid-paragraph, per review request. Independently verified both
advisories (GHSA-6wmf-4rv5-p3rp, GHSA-w8hw-w9fx-j79w) against the
primary source: CVE-2026-109619 is a cross-request, cross-worker UAF
(a fatal-error-interrupted request leaves a stale global pointer; a
later, different request on the same worker consumes it during
early-init -- upload-progress handling is one confirmed consumer path
among others), not the within-one-request heap-spray-via-multipart-
stall mechanism this repo's rules were built around. That changes the
scope of what's unvalidated:

- WorkerCrashPattern.yaml: the 502/503 crash premise specifically
  (already disproven in a real lab) plus the broader mechanism mismatch.
- UploadProgressOversizedPost.yaml: the heap-spray rationale behind the
  oversized-body heuristic doesn't match the real mechanism either --
  the correlation with actual exploitation is unconfirmed, not just the
  crash angle.
- PHPShellSpawn.yaml: scoped the qualifier to CVE attribution only, per
  review -- the rule's general value as a PHP child-process-spawn
  indicator doesn't depend on which mechanism caused the RCE.
@rjmendez rjmendez changed the title Add detection rules for CVE-2026-109618/109619 (PHP session.upload_progress UAF, RCE) Add detection rules for CVE-2026-109619 (PHP session.upload_progress UAF, RCE) Oct 21, 2026
@rjmendez

Copy link
Copy Markdown
Author

Both addressed, and independently verified against the primary source (not just taken on your word or the repo's):

[Unvalidated] now leads each description, not mid-paragraph. I fetched both advisories directly (GHSA-6wmf-4rv5-p3rp, GHSA-w8hw-w9fx-j79w) to confirm the correction myself. That changed the scope slightly from what was already in the repo: the real CVE-2026-109619 mechanism is cross-request/cross-worker (a fatal-error-interrupted request leaves a stale global pointer; a different, later request on the same worker consumes it during early-init -- upload-progress handling is one confirmed path among others), not the within-one-request multipart-stall heap-spray this repo's rules and write-up were built around. So I applied [Unvalidated] to all three rules, not just the crash one:

  • WorkerCrashPattern.yaml -- crash premise (already disproven in a real lab) + the broader mechanism mismatch.
  • UploadProgressOversizedPost.yaml -- the heap-spray rationale behind the size heuristic doesn't match the real mechanism either; the correlation with actual exploitation is unconfirmed, not just the crash angle.
  • PHPShellSpawn.yaml -- scoped the qualifier to CVE attribution only, per your note. The rule's value as a PHP child-process-spawn indicator doesn't depend on which mechanism caused the RCE.

PR title/body updated to scope to CVE-2026-109619 only, with both advisories linked directly and the mechanism correction stated up front rather than left implicit.

…rtifact

Same correction pushed to github:rjmendez/phpup-2026 (commit f99b300).
The prior revision keyed on a single-request multipart-stall heap-spray
mechanism derived from the leaked PoC artifact's own claims; that does
not match the real fix (php/php-src 82f8f31b16a, 'Avoid state corruption
via bailout') and VulnCheck independently reports none of the public
PoCs they reviewed have the correct mechanism.

- UploadProgressOversizedPost.yaml: oversized-body heuristic replaced
  with the real, fix-confirmed duplicate-Content-Disposition-header
  OOM-amplification signal (requires AzureDiagnostics/WAF body
  inspection, not W3CIISLog -- standard access logs don't carry body
  content). Doesn't require session.upload_progress at all, since the
  amplification vector works on any multipart endpoint.
- WorkerCrashPattern.yaml: the unvalidated 502/503 crash-ratio premise
  is retired, not kept with a caveat. Repurposed into the burst-over-time
  complement to the above (repeated amplification attempts from one
  source), on the real signal instead of a disproven one.
- PHPShellSpawn.yaml: description updated to the confirmed mechanism
  (cross-request bailout state corruption, session.upload_progress as
  one confirmed consumer proven by the PHP-8.0 EOL branch's outright
  disable of that function) instead of the dead spray-chain claim. Rule
  logic unchanged -- still generically valid regardless of mechanism.
@rjmendez

Copy link
Copy Markdown
Author

Update since the last round: PHP's official fix commit (php/php-src 82f8f31b16a) is now in, and it confirms the real mechanism is different from what this PR (and the community write-up it cited) assumed -- not just that the crash premise was unvalidated, but that the whole single-request spray/stall trigger doesn't match the fix. VulnCheck's independent review ("none of the public PoCs we reviewed have the correct mechanism") lines up with that.

Rewrote all three rules around the actual fix diff rather than keep caveating the old theory:

  • UploadProgressOversizedPost.yaml is now a duplicate-Content-Disposition-header detector -- the real, fix-confirmed OOM-amplification vector (main/rfc1867.c previously let one multipart part carry unlimited headers; the fix caps it to 2 header types + dedup). Switched from W3CIISLog to AzureDiagnostics/WAF body inspection, since this needs actual body content.
  • WorkerCrashPattern.yaml's 502/503 crash-ratio premise is retired outright, not kept [Unvalidated] -- repurposed into the burst-over-time complement to the rule above.
  • PHPShellSpawn.yaml description updated to the confirmed mechanism; query/entity-mappings unchanged since it was already generically valid.

PR title/body updated to match. Full writeup (and the same rewrite applied to the private research repo) at https://github.com/rjmendez/phpup-2026/blob/master/ANALYSIS.md.

…nt-Disposition

Same under-inclusivity bug caught and fixed in the sibling private-repo
Suricata rule: a real lab reproduction (phpup-2026's
examples/pcaps/phpup2026-real-oom-amplification.pcap) used an arbitrary
short header name instead of literal Content-Disposition, for maximum
entries-per-byte. countof(requestBody_s, "Content-Disposition") >= 2
would miss it. Replaced with extract_all + mv-expand + summarize to flag
any header name repeated within one request body, independent of which
name an attacker picks. Version bumped to 2.1.0.
@rjmendez

Copy link
Copy Markdown
Author

Follow-up fix, same day: caught the same under-inclusivity bug in this PR's duplicate-header rule that I'd already fixed in the sibling Suricata rule over in the reference repo. countof(requestBody_s, "Content-Disposition") >= 2 only matches a literal duplicated "Content-Disposition" string, but a real lab reproduction of the fix-confirmed mechanism (see https://github.com/rjmendez/phpup-2026, examples/pcaps/phpup2026-real-oom-amplification.pcap) used an arbitrary short header name instead, for maximum entries-per-byte -- which that literal match would miss entirely.

Replaced it with a generic "any header name repeated within one request body" check (extract_all + mv-expand + summarize) so detection doesn't depend on which name an attacker picks. Version bumped to 2.1.0. KQL syntax-checked locally; I don't have a Log Analytics workspace handy to execute it against live data, so this is a logic fix, not an execution-tested one the way the Suricata rule now is (that one I did run against real pcaps end to end).

@rjmendez rjmendez changed the title Add detection rules for CVE-2026-109619 (PHP session.upload_progress UAF, RCE) Add detection rules for CVE-2026-109618/CVE-2026-109619 (PHP bailout state-corruption RCE) Oct 21, 2026

@oferInbar Ofer Inbar (oferInbar) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for following up on the upstream php/php-src fix commit (82f8f31b16a) and retiring the unvalidated 502/503 worker-crash ratio premise.

However, the two rewritten AzureDiagnostics rules (phpup2026-UploadProgressOversizedPost.yaml and phpup2026-WorkerCrashPattern.yaml) currently fail KQL compilation against live Log Analytics workspaces (SEM0100: Failed to resolve scalar expression named 'requestBody_s') and have logic issues that would cause them to either never match or match every multi-field HTML form submission. Please see the inline comments below.

Comment thread Detections/W3CIISLog/phpup2026-UploadProgressOversizedPost.yaml Outdated
Comment thread Detections/W3CIISLog/phpup2026-WorkerCrashPattern.yaml Outdated
Comment thread Detections/DeviceProcessEvents/phpup2026-PHPShellSpawn.yaml
…position bug

Caught during a full validity sweep of the reference repo
(github.com/rjmendez/phpup-2026): this rule's burst-detection query used
the same countof(requestBody_s, "Content-Disposition") >= 2 literal
match already fixed in UploadProgressOversizedPost.yaml, missed in that
earlier pass. Fixed the same way -- extract_all + mv-expand + summarize
to flag any repeated header name. Version bumped to 2.1.0.
@rjmendez

Copy link
Copy Markdown
Author

Follow-up: doing a full validity sweep of the reference repo turned up the same under-inclusive bug in WorkerCrashPattern.yaml that I'd fixed in UploadProgressOversizedPost.yaml but missed here -- its burst-detection query also counted literal "Content-Disposition" occurrences. Fixed the same way (generic duplicate-header-name match). Version bumped to 2.1.0.

…remaining rule per review

Ofer Inbar's review confirmed, and I independently verified against
Microsoft's own AzureDiagnostics/AGWFirewallLogs schema reference
(learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/agwfirewalllogs),
that 'requestBody_s' is not a real column: Application Gateway/Front Door
WAF logs do not expose raw request bodies at all (the closest field,
DetailedData, only contains a snippet when a managed ruleset rule
already matched something -- not a general-purpose field you can run
your own body-pattern query against). Both rewrites of this query
('fix the literal Content-Disposition match' then 'fix the KQL syntax')
were built on a field that doesn't exist, on a table that doesn't carry
the data this detection needs. Not fixable by renaming a field --
removing phpup2026-UploadProgressOversizedPost.yaml and
phpup2026-WorkerCrashPattern.yaml entirely rather than attempt a further
patch, per the reviewer's explicit recommendation and the obvious
'don't salvage bad data' call once the data source itself doesn't exist.

Fixed phpup2026-PHPShellSpawn.yaml per the remaining review comments:
- InitiatingProcessFileName switched from has_any substring matching to
  an anchored regex, and now includes apache2/httpd -- CVE-2026-109618
  was demonstrated against Apache mod_php specifically, where PHP runs
  in-process inside the Apache worker, not as a separate php-fpm binary.
- FileName switched from has_any (substring) to in~ (exact,
  case-insensitive): has_any on tokens like 'sh', 'id', 'nc' matched
  unrelated binaries like openssh, cloud-init, systemd-networkd.
- Description now leads with '[Unvalidated]' and states plainly that
  CVE attribution is unvalidated (the reference capture used a direct
  shell_exec() test endpoint, not either CVE's actual mechanism), with
  benign-use tuning and overlap-with-existing-content notes added per
  the review.
- Reset version to 1.0.0 (new, unmerged file) and dropped the CVE
  numbers from the rule name, since the rule's value doesn't depend on
  CVE attribution.
@rjmendez rjmendez changed the title Add detection rules for CVE-2026-109618/CVE-2026-109619 (PHP bailout state-corruption RCE) Add detection rule for PHP worker shell-spawn (post-exploitation, generic) Oct 21, 2026
@rjmendez

Copy link
Copy Markdown
Author

Ofer Inbar (@oferInbar) thank you for the thorough review, especially the live-workspace KQL compilation check -- that caught a real mistake that static review of my own work hadn't.

Summary of what changed in response to both your reviews (replied inline on each thread too):

  • Removed phpup2026-UploadProgressOversizedPost.yaml and phpup2026-WorkerCrashPattern.yaml entirely. You were right on both counts: requestBody_s isn't a real AzureDiagnostics column (confirmed independently against Microsoft's own schema reference -- AGWFirewallLogs has no raw-request-body field at all, only DetailedData, which is a matched-rule snippet, not a general-purpose field), and even with a valid field the duplicate-header logic would scan across MIME part boundaries and false-positive on any legitimate multi-field form. Neither is fixable by patching; removed rather than attempt a third pass at a data source that doesn't carry what this detection needs.
  • Fixed phpup2026-PHPShellSpawn.yaml: added Apache mod_php coverage (apache2/httpd, the SAPI CVE-2026-109618 was actually demonstrated against), switched from has_any substring matching to exact/anchored matching (your openssh/cloud-init example was correct -- it would have matched), led the description with [Unvalidated] with an explicit statement that CVE attribution hasn't been independently confirmed, added benign-use tuning and overlap-with-existing-content notes, reset version to 1.0.0, and dropped the CVE numbers from the rule name.
  • PR title/body rewritten to match: one rule, not three.

This PR is now much smaller in scope than where it started, which is the right outcome given what didn't hold up.

rjmendez added a commit to rjmendez/phpup-2026 that referenced this pull request Oct 21, 2026
Resolving comments on the companion Azure-Sentinel PR
(Azure/Azure-Sentinel#15377) surfaced a real schema error: 'requestBody_s'
is not a real AzureDiagnostics column. @oferInbar's review reported a
live SEM0100 compilation failure; independently confirmed against
Microsoft's own schema reference
(learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/agwfirewalllogs)
that AGWFirewallLogs (what Application Gateway/Front Door WAF data feeds
into) has no raw-request-body field at all -- the closest, DetailedData,
only holds a snippet when a managed ruleset rule already matched
something, not a general-purpose field. Not fixable by renaming a field;
built three separate rules/queries across this repo (and this PR) on
data that was never exposed by the log source.

Retired six queries in rules/sentinel/phpup2026.kql (T2-1, T2-3, T3-3,
T3-4, H1, H2) and deleted the two analytics-rules YAML files that
depended on them (phpup2026-UploadProgressOversizedPost.yaml,
phpup2026-WorkerCrashPattern.yaml), mirroring the PR's resolution.

Also fixed, same review round: T3-1/T3-2 in phpup2026.kql and the
remaining phpup2026-PHPShellSpawn.yaml both had has_any substring
matching on short tokens ('sh', 'id', 'nc') that match unrelated
binaries (openssh, cloud-init, systemd-networkd) -- switched to
exact/anchored matching, and added apache2/httpd coverage since
CVE-2026-109618 was demonstrated against Apache mod_php specifically.
PHPShellSpawn's description now leads with [Unvalidated] since its CVE
attribution was never independently confirmed.

The duplicate-header-name OOM-amplification signal these retired KQL
queries couldn't carry over AzureDiagnostics is still available via
Suricata (rules/suricata.rules SID 9109633), which inspects the real
HTTP body directly and is live-fire verified against real captures.
… say is usually unpopulated

Caught while cross-checking a real, already-merged detection in this
same repo (Detections/DeviceProcessEvents/
SolarWinds_SUNBURST_Process-IOCs.yaml) for the TimeGenerated field
convention. Microsoft's own DeviceProcessEvents schema reference states
SHA256 'is usually not populated - use the SHA1 column when available'.
Switched to SHA1. Version bumped to 1.0.1.
@rjmendez

Copy link
Copy Markdown
Author

One more fix, found while cross-checking the TimeGenerated/DeviceProcessEvents field convention against this repo's own SolarWinds_SUNBURST_Process-IOCs.yaml: this rule's FileHash entity was mapped to SHA256, which Microsoft's own DeviceProcessEvents schema docs say "is usually not populated -- use the SHA1 column when available." Switched to SHA1. Version bumped to 1.0.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Detection Detection specialty review needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants