Skip to main content
Blog

BETA DETECTION: Windows IIS Worker or PHP CGI Process Spawning Suspicious Command Process Analytic

  • October 23, 2026
  • 0 replies
  • 2 views
  • Translate All

Aaron Beardslee
Forum|alt.badge.img
name: Windows IIS Worker or PHP CGI Process Spawning Suspicious Command Process Analytic
signatureid: EDR-SYM974-RUN
category: 'Execution'
threatname: 'Command & Scripting Interpreter: Windows Command Shell'
functionality: 'Endpoint Management Systems'

description: |
Detects a Windows web worker process - the IIS worker w3wp.exe, a PHP CGI/FastCGI worker
php-cgi.exe or php.exe, or a Windows build of another web daemon - spawning a command shell
with execution-oriented arguments, a general-purpose interpreter with inline-code,
remote-resource or temporary-path arguments, or a network transfer or tunneling utility as a
direct child. These process-tree shapes are durable post-exploitation evidence for
server-side remote code execution and are not tied to a particular exploit payload.

This is the Windows counterpart to EDR-NIX5-RUN and mirrors its three-tier child structure so
the same false-positive discipline applies on both platforms. It includes coverage for the
unauthenticated PHP core RCE vulnerabilities CVE-2026-109618 and CVE-2026-109619 (php2shell).
The PHP project confirmed exploitation can execute code as the web worker account across PHP
web SAPIs, and CISA specifically recommends monitoring PHP workers launching shells or
downloading tools.

Under IIS the PHP FastCGI handler runs PHP inside php-cgi.exe, a separate process created by
w3wp.exe. Code executed through a PHP request therefore has ParentImage php-cgi.exe, NOT
w3wp.exe, which is why an IIS-worker-only parent anchor does not see this behavior. Both
parents are included here.

Sysmon Event ID 1 or equivalent process-creation telemetry is required. Shells and
interpreters are not matched on process name alone: their command lines must show command
execution, encoding, download, or temporary staging. Transfer and tunneling tools are
intentionally high signal as direct children of a web-facing worker.
reference:
- https://www.php.net/archive/2026.php#2026-10-21-5
- https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w
- https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp
- https://www.cisa.gov/news-events/alerts/2026/10/21/critical-vulnerabilities-php-require-immediate-patching
- https://attack.mitre.org/techniques/T1059/003/
- https://attack.mitre.org/techniques/T1105/
- https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon
- https://github.com/bobby-tablez/FT-Sysmon-Config
labels:
- attack.execution
- attack.t1059
- attack.t1059.001
- attack.t1059.003
- attack.command_and_control
- attack.t1105
- attack.t1190
- CVE_2026_109618
- CVE_2026_109619
- PHP
- IIS
- FastCGI
- Post_Exploitation
logsource:
category: process_creation
product: windows
detection:
selection_webworker_parent:
ParentImage|endswith:
- '\php-cgi.exe'
- '\php.exe'
- '\w3wp.exe'
- '\httpd.exe'
- '\nginx.exe'
- '\tomcat.exe'
- '\tomcat9.exe'
- '\tomcat10.exe'
selection_shell:
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\pwsh.exe'
- '\powershell_ise.exe'
selection_shell_suspicious_arguments:
ChildProcessCommandLine|contains:
- ' /c '
- ' /k '
- ' -enc'
- ' -EncodedCommand'
- ' -nop'
- ' -NoProfile'
- ' -w hidden'
- ' -WindowStyle hidden'
- ' -Command '
- 'DownloadString'
- 'DownloadFile'
- 'Invoke-WebRequest'
- 'Invoke-Expression'
- 'FromBase64String'
- 'Start-BitsTransfer'
- '\Temp\'
- '\AppData\'
selection_interpreter:
Image|endswith:
- '\python.exe'
- '\python3.exe'
- '\perl.exe'
- '\ruby.exe'
- '\wscript.exe'
- '\cscript.exe'
- '\mshta.exe'
selection_interpreter_suspicious_arguments:
ChildProcessCommandLine|contains:
- ' -c '
- ' -e '
- 'base64'
- 'exec('
- 'eval('
- 'http://'
- 'https://'
- 'urllib'
- 'socket'
- '\Temp\'
- '\AppData\'
selection_transfer_or_tunnel_tool:
Image|endswith:
- '\curl.exe'
- '\wget.exe'
- '\certutil.exe'
- '\bitsadmin.exe'
- '\ftp.exe'
- '\nc.exe'
- '\ncat.exe'
- '\netcat.exe'
- '\socat.exe'
condition: selection_webworker_parent and ((selection_shell and selection_shell_suspicious_arguments) or (selection_interpreter and selection_interpreter_suspicious_arguments) or selection_transfer_or_tunnel_tool)
criticality: High
saveasthreat: true

violation_summary:
grouping_attribute: 'AccountName'
level2_attribute: 'DeviceHostName'
level2_metadata_attributes:
metadata_attributes:

TECHNICAL DETAILS


    COVERAGE INTENT
    ---------------
    This is a behavior-level post-exploitation analytic and the Windows counterpart to
    EDR-NIX5-RUN, following the corpus NIX/SYM counterpart convention (EDR-NIX27/EDR-SYM961,
    EDR-NIX28/EDR-SYM962). It does not attempt to identify the multipart heap-shaping requests
    used by CVE-2026-109618 or the producer/consumer request sequence used by CVE-2026-109619;
    those request mechanics need multipart-part and worker-affinity fields that web access logs
    do not expose. It detects the durable endpoint consequence instead.

    WHY php-cgi.exe IS THE PARENT, AND WHY THAT IS THE GAP
    -----------------------------------------------------
    Under IIS, PHP is normally hosted through the FastCGI handler, which maps *.php to
    php-cgi.exe. w3wp.exe creates php-cgi.exe, and PHP user code then runs INSIDE php-cgi.exe.
    A process spawned by PHP code is therefore a child of php-cgi.exe, and its ParentImage is
    php-cgi.exe - not w3wp.exe. This was measured directly on range AURORA01 (see VALIDATION
    STATUS): the IIS handler mapping was confirmed in-guest as PHP_via_FastCGI *.php ->
    C:\PHP\php-cgi.exe, and all five captured child processes carried
    ParentImage C:\PHP\php-cgi.exe.

    A consequence worth stating plainly for the reviewer: an IIS-worker-only parent anchor
    (ParentImage|endswith '\w3wp.exe') does not see php2shell post-exploitation at all, because
    the PHP child is one process deeper than w3wp.exe.

    WINDOWS vs LINUX PARENT RESOLUTION - THE ASYMMETRY MATTERS
    ---------------------------------------------------------
    EDR-NIX5-RUN carries a fourth, parent-image-independent branch keyed on the web service
    account (selection_web_service_account on AccountName www-data and friends). That branch
    exists only because Sysmon for Linux frequently ships ParentImage as the literal '-' for a
    forked PHP-FPM or nginx worker, and it was measured to widen false-positive exposure to any
    'sudo -u www-data sh -c ...' maintenance command.

    This Delta deliberately does NOT include an equivalent account branch, and the reason is a
    measurement rather than a preference. Under IIS FastCGI, php-cgi.exe is created by
    CreateProcess - it is exec'd, not forked - so it is a fully-tracked process and Windows
    Sysmon resolves ParentImage for its children correctly and consistently. All five captured
    events carried a correct, fully-qualified ParentImage. The parent anchor alone is therefore
    sufficient on Windows, and adding an 'IIS APPPOOL\...' account branch would import
    EDR-NIX5-RUN's false-positive exposure while buying nothing. Sites should not add one.

    FALSE-POSITIVE CONTROL
    ----------------------
    IIS-hosted applications do legitimately shell out for media conversion, backup, deployment,
    and integration work, and EDR-SYM858-RUN's own technical_details concedes the same for IIS
    generally. A shell or interpreter image name is therefore insufficient by itself. Shell
    children must also carry execution, encoding, download, or temporary-staging arguments;
    interpreter children must carry inline-code, remote-resource, decoding, or temporary-path
    arguments. Direct curl, wget, certutil, bitsadmin, ftp, netcat, or socat children remain
    intentionally ungated because payload retrieval or tunneling initiated by a web worker is
    uncommon and is the behavior CISA recommends monitoring.

    Note that ' /c ' and ' -Command ' are broad on their own - a legitimate application shelling
    out will usually use them. They are included because they are the minimum evidence that a
    shell was asked to EXECUTE something rather than merely being launched, which is the same
    bar EDR-NIX5-RUN sets with ' -c '. Environments with known server-side automation should
    baseline and filter the specific application, script, account, and maintenance-window
    combinations rather than excluding the web-worker parent globally, which would disable the
    detection entirely.

    RELATIONSHIP TO EDR-SYM858-RUN - READ THIS BEFORE DEPLOYING BOTH
    ---------------------------------------------------------------
    EDR-SYM858-RUN ('Suspicious WSUS Spawning Command Shell for Reconnaissance Analytic', L0) is
    the only other Delta in the corpus anchored on an IIS worker parent. Its condition is
    (ParentImage|endswith '\w3wp.exe' or '\wsusservice.exe') and (Image|endswith cmd.exe,
    powershell.exe, pwsh.exe, powershell_ise.exe, whoami.exe, net.exe, net1.exe), with no
    command-line gating at all.

    The two are complementary, and that was verified by measurement rather than assumed:

      - EDR-SYM858-RUN does NOT fire on the captured php2shell evidence. Its parent anchor
        requires w3wp.exe or wsusservice.exe; the measured ParentImage on all five captured
        children is C:\PHP\php-cgi.exe. This is the core gap this Delta closes.
      - EDR-SYM858-RUN also has no curl.exe, certutil.exe, bitsadmin.exe, python.exe or other
        interpreter/transfer children, so it would not have matched the captured curl.exe child
        even with a matching parent.
      - There IS one overlapping firing path: w3wp.exe spawning cmd.exe or powershell.exe.
        On that path both Deltas can fire. This Delta is the stricter of the two there, because
        it additionally requires execution-oriented command-line arguments, so any event that
        satisfies this Delta on that path also satisfies EDR-SYM858-RUN. The Content team may
        reasonably prefer to treat EDR-SYM858-RUN as the narrow WSUS/CVE-2025-59287 alert it is
        named for and this Delta as the general web-worker rule. No change is made to
        EDR-SYM858-RUN in this pull request.

    Other Deltas reviewed and ruled out as overlaps: EDR-SYM961-RUN requires java/javaw parents
    with mandatory Windchill command-line markers; EDR-SYM838-ERI is a tomcat-parent rare-child
    event-rarity analytic on Windows; EDR-SYM881-RUN is SolarWinds Web Help Desk wrapper.exe;
    EDR-SYM844-RUN, EDR-SYM973-RUN and EDR-SYM962-RUN are Windows file-creation rules with no
    process lineage; EDR-NIX5-RUN is logsource.product linux and cannot fire on Windows. A
    delta_search for 'php-cgi' returns zero results across the corpus.

    VALIDATION STATUS
    -----------------
    L1, with emulation performed and cited in master_meta.ATD. The parser-mapping question that
    held this at L0 through version 20261022.2 is resolved; see PARSER MAPPING below. No
    selector changed on promotion.

    Emulated on range AURORA01 on 2026-10-22, host WP01 (Windows Server 2022, IIS 10,
    PHP 8.3.35 cgi-fcgi, Sysmon64 v15.15, config ft-sysmonconfig-export.xml). A token-gated,
    non-parameterized PHP endpoint performed fixed inert actions only; no request input ever
    reached a command line, and every command was a hardcoded argv array or fixed string.
    Requests were driven from range-internal web01 through an nginx/ModSecurity WAF on port 80.
    Children were spawned with proc_open and bypass_shell so that each is a DIRECT child of
    php-cgi.exe via CreateProcess, with no intermediate cmd.exe.

    PROVEN against the captured collector archive (sysmon_remote.txt). evidence_grep truncates
    each line before the parent fields, so every claim below was proven by writing the deciding
    field name and value into the search pattern itself:

      - ParentImage C:\PHP\php-cgi.exe appears EXACTLY 5 times, and those 5 are precisely the
        5 intended child spawns.
      - Image C:\Windows\System32\cmd.exe with ParentImage C:\PHP\php-cgi.exe: 3 records
        (22:16:26, 22:17:59, 22:19:07 UTC; PIDs 5096, 4428, 3736).
      - Image C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe with ParentImage
        C:\PHP\php-cgi.exe: 1 record (22:16:30 UTC, PID 5816).
      - Image C:\Windows\System32\curl.exe with ParentImage C:\PHP\php-cgi.exe: 1 record
        (22:16:35 UTC, PID 6016). This satisfies selection_transfer_or_tunnel_tool.
      - The child command line is populated and selectable alongside the parent anchor: the
        marker string from the cmd.exe payload co-occurs with ParentImage C:\PHP\php-cgi.exe in
        3 records. The captured command lines are 'cmd.exe /c echo <marker>' and
        'powershell.exe -NoProfile -NonInteractive -Command Write-Output <marker>', which
        satisfy ' /c ' and ' -NoProfile'/' -Command ' respectively.
      - The account is populated: User IIS APPPOOL\DefaultAppPool co-occurs with
        ParentImage C:\PHP\php-cgi.exe in all 5 records.
      - Host is DeviceHostName-equivalent AURORA01-WP01 on every record.
      - Event is Sysmon EID 1 Process Create via Microsoft-Windows-Sysmon/Operational, shipped
        to the collector as expected.

    NEGATIVE CONTROLS - both kinds behaved:

      - Absence. A normal request to a stock WordPress page, a request with an INVALID token but
        a valid action keyword, and a request with a valid token and no action keyword all
        produced ZERO child processes. The ParentImage count of exactly 5 is itself the proof:
        had any control spawned anything, the count would exceed 5.
      - Specificity. The same three child images were then spawned locally on WP01 from a
        non-web parent (powershell.exe, PID 2308) with marker strings suffixed -LOCALCTL. Those
        records carry ParentImage C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe, so
        they do NOT satisfy selection_webworker_parent. Identical children, different parent,
        no match - which is the precise property a parent-anchored selector depends on.

    REQUEST-PATH CORROBORATION
    --------------------------
    The IIS W3C log for the same window is committed alongside the Sysmon trace

    It records the endpoint, the exact cs-uri-query, sc-status 200 for valid tokens and 403 for
    the invalid-token control, confirming the full client -> WAF -> IIS -> php-cgi.exe path. It
    is corroboration of the request path only, not validation evidence for this Delta's
    process-creation logic.


    ---------------------------------------
    selection_shell_suspicious_arguments and selection_interpreter_suspicious_arguments select on
    the published attribute ChildProcessCommandLine, and violation_summary.grouping_attribute is
    AccountName. ChildProcessCommandLine and ParentProcessCommandLine are the Endpoint Management
    Systems names for the child and parent command line. The Microsoft Windows functionality
    names the equivalent field CommandLine. That difference is a per-functionality naming
    convention and not a gap. This Delta is functionality 'Endpoint Management Systems', so
    ChildProcessCommandLine is the correct attribute for it to select on.


Policy building walkthrough can be found in this previous post:

 

https://connect.securonix.com/threat%2Dresearch%2Dintelligence%2D62/beta%2Ddetection%2Dtelnyx%2Dteampcp%2Dcredential%2Dexfiltration%2D241