Skip to main content
Blog

BETA DETECTION: Web Server or PHP Worker Spawning Suspicious Command Process Analytic

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

Aaron Beardslee
Forum|alt.badge.img
name: Web Server or PHP Worker Spawning Suspicious Command Process Analytic
signatureid: EDR-NIX5-RUN
category: 'Execution'
threatname: 'Command & Scripting Interpreter: Unix Shell'
functionality: 'Endpoint Management Systems'
lifecycle: experimental
version: 20261022.5
description: |
Detects a web server daemon or PHP-FPM worker spawning a shell with execution-oriented
arguments, a network transfer or tunneling utility, or a general-purpose interpreter with
suspicious inline-code, remote-resource, or temporary-path arguments. 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 Delta 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, with the highest demonstrated
risk under Apache mod_php. CISA specifically recommends monitoring PHP workers launching
shells or downloading tools. It also retains the web-server reverse-shell behavior originally
covered for XWiki CVE-2025-24893.

Sysmon for Linux Event ID 1 or equivalent process-creation telemetry is required. PHP-FPM is
matched with a substring because common Linux packages use version-suffixed binaries such as
/usr/sbin/php-fpm8.3. Shells are not matched on process name alone: their command lines must
show command execution, interactive use, network redirection, transfer, decoding, or temporary
staging. Transfer/tunneling tools are high-signal direct children of web-facing workers.

The parent condition can also be satisfied by the web service account the worker runs as.
That branch exists because Sysmon for Linux does not RELIABLY resolve ParentImage for a
forked web worker: whether it resolves depends on whether that worker PID has already
produced an instrumented event of its own. See the measured behavior in
master_meta.technical_details before deploying.
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://www.vulncheck.com/blog/xwiki-under-increased-attack
- https://www.vulncheck.com/blog/xwiki-cve-2025-24893-eitw
- https://github.com/bobby-tablez/FT-Sysmon-Config
labels:
- attack.execution
- attack.t1059
- attack.t1059.004
- attack.command_and_control
- attack.t1105
- attack.t1190
- CVE_2026_109618
- CVE_2026_109619
- CVE_2025_24893
- PHP
- PHP_FPM
- Post_Exploitation
logsource:
category: process_creation
product: linux
detection:
selection_webserver_parent_image:
ParentImage|endswith:
- '/java'
- '/java.bin'
- '/httpd'
- '/apache2'
- '/nginx'
- '/tomcat'
- 'catalina.sh'
selection_phpfpm_parent_image:
ParentImage|contains: '/php-fpm'
selection_webserver_parent_cmdline:
ParentProcessCommandLine|contains:
- 'httpd'
- 'apache2'
- 'nginx'
- 'tomcat'
- 'catalina'
- 'php-fpm'
selection_web_service_account:
AccountName:
- 'www-data'
- 'apache'
- 'apache2'
- 'httpd'
- 'nginx'
- 'http'
selection_shell:
Image|endswith:
- '/bash'
- '/sh'
- '/zsh'
- '/dash'
- '/ksh'
selection_shell_suspicious_arguments:
ChildProcessCommandLine|contains:
- ' -c '
- ' -i'
- '/dev/tcp/'
- '/dev/udp/'
- '>&'
- 'curl '
- 'wget '
- 'base64'
- '/tmp/'
- '/var/tmp/'
- '/dev/shm/'
selection_interpreter:
Image|endswith:
- '/python'
- '/python3'
- '/perl'
- '/ruby'
- '/php'
selection_interpreter_suspicious_arguments:
ChildProcessCommandLine|contains:
- ' -c '
- ' -e '
- 'base64'
- 'exec('
- 'http://'
- 'https://'
- '/tmp/'
- '/var/tmp/'
- '/dev/shm/'
selection_transfer_or_tunnel_tool:
Image|endswith:
- '/curl'
- '/wget'
- '/nc'
- '/ncat'
- '/netcat'
- '/socat'
condition: (selection_webserver_parent_image or selection_phpfpm_parent_image or selection_webserver_parent_cmdline or selection_web_service_account) 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. 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 require multipart-part and worker-
    affinity fields that ordinary web access logs do not expose reliably. Instead, this rule
    detects the durable endpoint consequence: a web-facing worker launching tooling associated
    with command execution, payload retrieval, tunneling, or staged interpreter execution.

    PHP PARENT PROCESS HANDLING
    ---------------------------
    Apache mod_php executes PHP inside the Apache worker, so the resulting process parent
    resolves to httpd or apache2. That was an expectation up to version 20261022.3 and is a
    measurement from 20261022.4: see APACHE MOD_PHP PREFORK - MEASURED 2026-10-23 below. On
    Ubuntu the binary is /usr/sbin/apache2 and the shipped ParentImage is exactly that, so the
    match is carried by the '/apache2' value of selection_webserver_parent_image; the '/httpd'
    value covers the RHEL-family path and remains unexercised. PHP-FPM uses a separate worker
    binary. Distribution packages commonly suffix that binary with the PHP version, for example
    php-fpm8.3, so the PHP-FPM selector uses ParentImage|contains: '/php-fpm' rather than a
    fixed |endswith value. ParentProcessCommandLine is retained as a fallback where the parser
    populates the parent command line but not ParentImage.

    SYSMON FOR LINUX PARENT RESOLUTION - MEASURED BEHAVIOR
    ------------------------------------------------------
    Emulated on range AURORA01 on 2026-10-22 and captured through the collector; the trace is
    cited in master_meta.ATD. A php-fpm8.3 pool worker on Ubuntu 24.04 executed one fixed inert
    child in response to an HTTP request routed through an nginx/ModSecurity WAF. Sysmon for
    Linux Event ID 1 shipped the following to the collector:

      Image                 /usr/bin/dash
      CommandLine           sh -c -- true
      User                  www-data
      ParentProcessId       15828              (the php-fpm pool worker)
      CurrentDirectory      /var/www/petalstem
      ParentImage           -
      ParentCommandLine     -

    ParentImage and ParentCommandLine are the literal string '-', not the worker path. Sysmon
    for Linux resolves parent image and parent command line from an internal per-PID process
    cache. PHP-FPM pool workers and nginx worker processes are created by fork(2) from their
    master process and never call execve(2), so a worker that has not produced an instrumented
    event of its own is absent from that cache and its children are shipped with no parent
    identity at all.

    Measured on the same host: only three Event ID 1 records exist with
    Image /usr/sbin/php-fpm8.3, and all three are the MASTER process (ParentProcessId 1, started
    by systemd). Pool workers 15827 and 15828, and 55327 and 55328 after a deliberate service
    restart, have no process-creation record whatsoever. Across the capture window, 4135 of the
    4226 process-creation records carrying a ParentImage element shipped it as '-', or 97.8
    percent.

    CORRECTION AT VERSION 20261022.3 - RESOLUTION IS CONDITIONAL, NOT IMPOSSIBLE
    ---------------------------------------------------------------------------
    Versions up to and including 20261022.2 concluded from the measurements above that
    selection_webserver_parent_image, selection_phpfpm_parent_image and
    selection_webserver_parent_cmdline are all "unsatisfiable for a PHP-FPM, nginx-worker or
    Apache-prefork parent on this telemetry". That conclusion was too strong and is retracted
    here. The 97.8 percent measurement itself is reproduced and stands; the absolute inference
    drawn from it does not.

    A controlled experiment on range AURORA01 on 2026-10-22, cited under SUPPORTING TRACES,
    isolated the variable. A temporary one-worker static pool (pm = static, pm.max_children = 1)
    was configured so that worker identity is a measured fact rather than an inference, and
    php8.3-fpm was restarted to obtain exactly one fresh worker, PID 9351, with no prior
    instrumented activity of any kind. Three requests were then driven through the WAF, eight
    seconds apart, every one of them served by PID 9351:

      1. an inert /bin/echo child   -> ParentProcessId 9351, ParentImage '-'
      2. a warm action performed by the worker itself: one EID 3 NetworkConnect to a host-local
         address, plus an EID 11 FileCreate and EID 23 FileDelete pair on a /tmp marker, all
         under PID 9351. These are the ONLY instrumented events for that PID between steps 1
         and 3.
      3. a second inert /bin/echo child -> ParentProcessId 9351,
                                           ParentImage /usr/sbin/php-fpm8.3

    Same worker PID, same host, same pool, same Sysmon for Linux v1.5.2. The only intervening
    change was that the worker PID had by then produced instrumented events of its own.
    Sysmon for Linux therefore enriches ParentImage from a per-PID cache populated by that PID's
    own earlier instrumented activity of ANY event type. fork-without-execve explains why a
    pool worker is usually absent from that cache, but it is not a permanent disqualification.

    This confirms the mechanism asserted by EDR-NIX29-RUN and EDR-NIX31-RUN. EDR-NIX31-RUN
    recorded that mechanism as an operational inference that was "strong, but not proven from
    Sysmon for Linux's source"; it is now proven by direct measurement, and no correction is
    owed to either of those Deltas. A cross-check against the CITY01 archive closes the
    remaining ambiguity there as well: a grep that pins the element name immediately before the
    value (the literal text ParentImage followed by /usr/sbin/php-fpm8.3) returns one match on
    line 1 of EDR-NIX29-RUN_evidence.txt, Hostname WEB01, 2026-10-01T15:40:59. A prior audit
    could only establish that the php-fpm path sat inside some XML Data element; the element is
    now read directly as ParentImage.

    Consequence for this Delta, stated precisely: the three original parent branches ARE
    satisfiable and are not dead code, but they are UNRELIABLE for a forked web worker. They
    fire only when the worker PID happens to have produced an earlier instrumented event. In
    ordinary operation a pool worker that merely serves HTTP produces no Sysmon event of its
    own, which is exactly why 97.8 percent of records shipped '-'. Both measurements are true
    at once: the branches work when the cache is warm for that PID and are silent when it is
    not. Which case a given event is in is not stated in the record, but it is predictable from
    the SAPI's accept transport - see the Apache measurement below, where the worker accepts TCP
    itself and is therefore always warm. '/java' and '/tomcat' are unaffected either way,
    because a JVM is exec'd rather than forked, which is why the java parent anchor in
    EDR-NIX27-RUN never depended on this behavior.

    selection_web_service_account is therefore added as a fourth, parent-image-independent way
    to satisfy the parent condition, keyed on the service account the web worker runs as. It is
    purely additive - where a parser does populate ParentImage, the original three branches
    continue to work exactly as before. This correction strengthens rather than weakens its
    justification: a parent-image-independent branch is what keeps the Delta working across both
    cache states.

    CurrentDirectory is also present in the raw record and would discriminate a web-application
    parent context well, but the Endpoint Management Systems functionality publishes no
    CurrentDirectory attribute, so it cannot be used in a selector for this datasource.

    APACHE MOD_PHP PREFORK - MEASURED 2026-10-23
    --------------------------------------------
    Run php2shell-apacheprefork-capture-20261023 on range AURORA01 closed the one branch left
    unexercised at version 20261022.3. Host aurora01-web02 was given Apache 2.4.58 with
    mpm_prefork_module and libapache2-mod-php8.3 8.3.6-0ubuntu0.24.04.13 on port 8081, SAPI
    apache2handler, alongside the unchanged nginx/PHP-FPM stack. A dedicated vhost
    /var/www/aurora-prefork was configured for exactly one persistent worker (StartServers,
    MinSpareServers, MaxSpareServers and MaxRequestWorkers all 1, MaxConnectionsPerChild 0), so
    worker identity is a measured fact. A token-gated non-parameterized endpoint spawned one
    fixed direct child with the PHP proc_open array form, which execs without /bin/sh.

    Two children were spawned by the same worker PID 3610, seventeen seconds apart, with a
    deliberate warming action by that worker in between. Both shipped identically:

      Image                 /usr/bin/dash
      CommandLine           /bin/sh -c -- true P2SAPACHE20261023
      User                  www-data
      ParentProcessId       3610               (the Apache prefork worker)
      CurrentDirectory      /var/www/aurora-prefork
      ParentImage           /usr/sbin/apache2
      ParentCommandLine     /usr/sbin/apache2 -k start
      ParentUser            www-data

    So selection_webserver_parent_image is satisfied by shipped data through its '/apache2'
    value, and selection_webserver_parent_cmdline and selection_web_service_account are
    satisfied on the same records. No selector change is owed: the Apache expectation recorded
    since 20261022.1 is confirmed as written.

    THE PREDICTED COLD CASE DOES NOT EXIST UNDER MOD_PHP, AND THAT IS THE REAL FINDING
    ----------------------------------------------------------------------------------
    The run was designed to catch an unwarmed Apache worker, expecting ParentImage '-' on the
    first child and /usr/sbin/apache2 on a second child after a warming action, mirroring the
    PHP-FPM experiment above. That prediction is FALSE, for a structural reason worth recording.

    An Apache mpm_prefork worker accepts the inbound TCP connection ITSELF, and Sysmon for Linux
    logs that accept as an Event ID 3 with the worker as subject process and Initiated=false.
    The worker therefore produces an instrumented event of its own on every single request it
    serves, including its first, so its per-PID cache entry exists before PHP ever executes.
    Measured: 11 inbound-accept records in the window carry Image /usr/sbin/apache2 and
    Initiated=false, and the replacement worker 3610 produced its first one 1.0 second after it
    was forked, on its first ever request. Exactly 1 record carries Initiated=true, which is the
    deliberate warm action.

    A PHP-FPM pool worker accepts on a UNIX socket because nginx terminates the TCP connection,
    which produces no NetworkConnect event at all. The operative difference between the two
    SAPIs is therefore the transport the worker accepts on, not fork-versus-exec alone. The
    practical consequence for a rule author is the opposite of the PHP-FPM case: under Apache
    mod_php on a TCP listener, the parent branches are the reliable path and the account branch
    is redundant insurance rather than the load-bearing one.

    One residual unknown is recorded honestly. Worker 3610 had already accepted five connections
    before the first child was spawned, so this run cannot separate "warmed by its own accept in
    the same request" from "warmed by an earlier accept". The accept for the child-spawning
    request preceded that child by 7 milliseconds, so same-request warming is fast enough in
    principle. Settling it requires a worker whose first ever accepted request is the
    child-spawning one, which needs a second controlled worker termination and was outside the
    one-termination limit set for this run.

    NEGATIVE AND SPECIFICITY CONTROLS, 2026-10-23
    ---------------------------------------------
    Exactly three records in the window carry the fixed child command line, and they are the two
    Apache children plus one control. The absence proof is that count: a stock static-page
    request, an invalid-token request that still carried the valid action keyword (HTTP 403), and
    a valid-token request with no action keyword (HTTP 200, no action) each spawned nothing.

    The specificity control is the same child run as www-data from sudo with no inbound HTTP
    request. It ships ParentImage /usr/bin/sudo and ParentCommandLine 'sudo', so the
    parent-image branch does not match it, while selection_web_service_account does. This is the
    exposure recorded under FALSE-POSITIVE CONTROL reproduced on Apache, and it is also the
    reason the account branch needs baselining wherever ParentImage is reliable.

    ABNORMAL WORKER TERMINATION IS NOT A DELTA SIGNAL - RESEARCH, NOT COVERAGE
    -------------------------------------------------------------------------
    The same run produced one real but controlled abnormal termination: SIGABRT to the sole
    Apache worker 1901 from privileged guest control. The master survived with an unchanged start
    time, Apache forked a replacement about 7.2 seconds later, and the first client request was
    satisfied 12.1 seconds after the signal. This is recorded here only to state that it yields
    NO detection content for this or any Delta on this telemetry path, and no selector was added
    for it:

      - Sysmon Event ID 5 ProcessTerminate is disabled by the host config, which has
        <ProcessTerminate onmatch="include"> with zero rules; include with no rules logs nothing.
      - Apache's own AH00051 'child pid 1901 exit signal Abort (6)' notice goes only to the
        GLOBAL error log, not the vhost ErrorLog, and the host's nxlog reads neither.
      - nxlog holds read file descriptors on /var/log/syslog and /var/log/auth.log only, and
        drops every non-Sysmon syslog line at the input, so kernel and systemd messages do not
        ship either.
      - The only shipped witness anywhere in the collector is the sudo authorization record for
        the signal itself, in the linuxauth source. That records the cause, not the effect.

    Two incidental findings from the same run are worth carrying forward. apache2.service runs
    with PrivateTmp=yes, so a /tmp write by a mod_php worker ships an EID 11 FileCreate whose
    TargetFilename carries the systemd-private host path
    /tmp/systemd-private-<id>-apache2.service-<id>/tmp/... while the matching EID 23 FileDelete
    shows the in-namespace path; a /tmp selector aimed at mod_php must expect both shapes. And on
    this collector path the flat file is NOT raw Sysmon XML: nxlog runs
    parse_windows_eventlog_xml then to_json, so the archive holds JSON with the XML in a Message
    field and entities decoded. A grep that pins an element name can therefore match a probe
    process whose own command line contained the search text, which inflates naive counts; every
    count above was taken with a pattern no probe carried and cross-checked against the guest.

    FALSE-POSITIVE CONTROL
    ----------------------
    Web applications sometimes invoke shells or language runtimes for legitimate maintenance,
    media conversion, backup, deployment, or integration tasks. A shell or interpreter name is
    therefore insufficient by itself. Shell children must also contain execution, interactive,
    network-redirection, transfer, decoding, or temporary-staging arguments. Interpreter children
    require inline-code, remote-resource, decoding, or temporary-path arguments. Direct curl,
    wget, netcat, or socat children remain intentionally high signal because payload retrieval or
    tunneling from a web worker is uncommon and is the behavior CISA recommends monitoring.
    Environments with known server-side automation should tune exact application, script, account,
    and maintenance-window combinations rather than excluding the parent web worker globally.

    selection_web_service_account widens that exposure and was measured doing so. A deliberate
    negative control ran '/bin/sh -c true' as www-data from a non-web parent - sudo, with no
    inbound HTTP request. It carries AccountName www-data, Image /usr/bin/dash and ' -c ', so it
    satisfies the new branch and the shell branch together. Any administrative
    'sudo -u www-data sh -c ...' and any cron job running as the web service account behaves the
    same way. Sites enabling this branch should baseline and filter known maintenance command
    lines before deployment. The three original parent branches do not carry this exposure, so an
    environment whose parser populates ParentImage correctly may prefer to omit the account branch
    - subject to the reliability caveat in the CORRECTION section above, which the 2026-10-23
    Apache measurement narrows to the UNIX-socket SAPIs.

    RELATIONSHIP TO OTHER DELTAS
    ----------------------------
    EDR-NIX7-RUN is narrower and remains useful for the specific base64-decode-to-shell pipeline.
    EDR-NIX20-RUN is restricted to cPanel cpsrvd/cpdavd parents. EDR-NIX29-RUN requires the
    SLAPSHOT-specific Python wrapper and .uxdport/.uxdlock artifacts. EDR-NIX31-RUN requires a
    chmod operation granting setuid to /bin/sh. EDR-NIX27-RUN covers a Windchill Method Server
    JVM parent and is unaffected by the fork-versus-exec behavior described above. This update
    generalizes EDR-NIX5-RUN rather than adding a parallel Delta for the same
    web-worker-to-command-execution telemetry layer.

    EDR-SYM974-RUN is the Windows counterpart to this Delta, added 2026-10-22. It mirrors this
    three-tier child structure for process_creation/windows, anchored on php-cgi.exe and w3wp.exe
    among other Windows web workers. It deliberately carries NO account branch, because under IIS
    FastCGI php-cgi.exe is created by CreateProcess rather than forked and Windows Sysmon
    resolves ParentImage for its children correctly and consistently - the asymmetry with this
    Delta is a measured difference between the two platforms, not a stylistic one.

    VALIDATION STATUS
    -----------------
    L1. Emulation was performed and is cited in master_meta.ATD, and the one open mapping question
    that previously held this Delta at L0 has been confirmed by STR parser review on 2026-10-22.

    PROVEN against the captured collector archive:
      - A PHP-FPM worker spawning a shell child is captured by Sysmon for Linux and reaches the
        collector, stamped with the correct hostname aurora01-web02.
      - Image and ChildProcessCommandLine carry the deciding values '/usr/bin/dash' and
        'sh -c -- true', so selection_shell and selection_shell_suspicious_arguments (on ' -c ')
        are both satisfied by shipped data.
      - The negative controls behaved. A normal PHP request that spawns no child, a request with
        an invalid token, and the same multipart body sent to a static route produced no shell
        child anywhere in the window: exactly one 'sh -c -- true' record exists among 4296
        shipped records, at the timestamp of the single positive request.
      - ParentImage and ParentCommandLine were '-' on that event. Per the CORRECTION section
        above, that reflects the unwarmed-cache state for that worker PID; it is the common case
        for a UNIX-socket SAPI but not an absolute property of the telemetry.
      - Apache mod_php, added 2026-10-23: ParentImage /usr/sbin/apache2 and ParentCommandLine
        '/usr/sbin/apache2 -k start' on both captured children, proven against the archive by
        element-pinned greps. selection_webserver_parent_image is live on this SAPI.

    ACCOUNT MAPPING - CONFIRMED
    ---------------------------
    selection_web_service_account selects on AccountName. The archive proves the raw Sysmon for
    Linux element User equals 'www-data'. The mapped attribute is not visible in that archive,
    which holds collector-side raw Sysmon output rather than parsed data, so the mapping is
    established by review rather than read off the capture. STR parser review on 2026-10-22
    confirmed that the Sysmon for Linux User element is parsed into the published attribute
    AccountName, so the shipped User 'www-data' reaches the rule as AccountName 'www-data' and
    selection_web_service_account is satisfied by the captured positive event. SourceUserName
    is not the mapping and no selector change is owed. This is a confirmed parser mapping
    rather than the corpus convention it was described as at version 20261022.1, and it is
    what allows promotion to L1.

    NOW EXERCISED AT VERSION 20261022.3
    -----------------------------------
    The interpreter branch and the transfer/tunnel branch were recorded as unexercised at
    20261022.2. Both were exercised on range AURORA01 on 2026-10-22 against the stock dynamic
    pool on aurora01-web02, through the same WAF, from the same kind of token-gated
    non-parameterized endpoint, and the trace is cited under SUPPORTING TRACES:

      - selection_interpreter: ChildProcessCommandLine 'python3 -c pass', User www-data. The
        interpreter branch requires ' -c ', which this command line carries.
      - selection_transfer_or_tunnel_tool: ChildProcessCommandLine 'wget --version', the
        ungated transfer-tool branch. wget was used rather than curl because curl is not
        installed on that host.
      - Both children are DIRECT children of the pool worker. The endpoint used the PHP 7.4+
        proc_open array form, which execs without /bin/sh, so unlike the 'sh -c -- true' record
        above there is no intervening dash process.
      - Negative controls behaved again: a stock page request, an invalid-token request carrying
        a valid action keyword, and a valid-token request with no action keyword each produced
        no child process.
      - ParentImage was '-' on both, consistent with the CORRECTION section: these were
        ordinary pool workers serving HTTP, so their PIDs were not in Sysmon's cache. Both
        events are matched through selection_web_service_account, which is the branch that
        exists for exactly this case.

    NOW EXERCISED AT VERSION 20261022.4
    -----------------------------------
    Apache mod_php under mpm_prefork, the last unexercised parent branch and the SAPI with the
    highest demonstrated exploitability for CVE-2026-109618. Measured on 2026-10-23 and detailed
    under APACHE MOD_PHP PREFORK above; the traces are cited under SUPPORTING TRACES.
    selection_webserver_parent_image fires on shipped data through its '/apache2' value.

    STILL NOT EXERCISED, which does not block L1:
      - The '/httpd' value of selection_webserver_parent_image. Ubuntu names the binary
        apache2, so an RHEL-family host with /usr/sbin/httpd has not been captured. The value
        is retained on the same reasoning as before, and the Ubuntu measurement makes the
        mechanism rather than the path the uncertain part.
      - '/java', '/java.bin', '/nginx', '/tomcat' and 'catalina.sh' as parent images.

    The confirmed mapping does not reduce the false-positive exposure recorded under
    FALSE-POSITIVE CONTROL. It does the opposite: the account branch is now known to be live, so
    the measured 'sudo -u www-data sh -c true' negative control is a real firing path and must be
    baselined and filtered before deployment.

    SUPPORTING TRACES
    -----------------
    The interpreter-branch, transfer-tool-branch and controlled parent-resolution evidence
    described above:

      https://bitbucket.org/securonixsnypr/str-atd/src/main/Execution/php2shell_phpfpm_interpreter_transfer_and_parent_resolution_sysmonlinux_20261022.log

    The Apache mod_php prefork evidence added at 20261022.4. The first is the child lineage,
    including the non-web-parent specificity control; the second is the Apache worker's own
    instrumented events, which is what establishes why the parent cache is warm on this SAPI:

      https://bitbucket.org/securonixsnypr/str-atd/src/main/Execution/php2shell_apache_modphp_prefork_child_lineage_sysmonlinux_20261023.log
      https://bitbucket.org/securonixsnypr/str-atd/src/main/Execution/php2shell_apache_prefork_worker_self_warming_sysmonlinux_20261023.log

    The abnormal-termination result from the same run is deliberately NOT cited as validation
    evidence for this Delta, because it produced no detection content. It is recorded separately
    so the negative result is not re-investigated:

      https://bitbucket.org/securonixsnypr/str-atd/src/main/Execution/php2shell_apache_prefork_worker_sigabrt_privileged_control_linuxauth_20261023.log

    The same emulation run also captured a bounded multipart precursor request, the request-shape
    half of CVE-2026-109618, against a Windows IIS / PHP 8.3.35 CGI-FastCGI backend through the
    same WAF. Those traces are not validation evidence for this Delta's process-creation logic
    but they document what the request layer does and does not show:

      https://bitbucket.org/securonixsnypr/str-atd/src/main/Initial_Access/php2shell_multipart_precursor_waf_modsec_20261022.log
      https://bitbucket.org/securonixsnypr/str-atd/src/main/Initial_Access/php2shell_multipart_precursor_iis_w3c_20261022.log

    Two findings there bear on why this Delta is endpoint-based rather than request-based. First,
    the backend IIS W3C log records cs-bytes but no Content-Type, so a 51-part multipart request
    carrying repeated part headers and empty-filename controls is indistinguishable from a benign
    single-file upload of identical size - both logged cs-bytes 4927. Second, CRS v4 at default
    paranoia raised no multipart rule on the anomalous request; the only rule that fired was
    920350, Host header is a numeric IP address, which is an artifact of addressing the lab by IP.
    The discriminating structure survived only inside the full ModSecurity JSON audit record.


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