---
analysis: A single rule on shell execution from a web server is useful but lacks the
  historical context of the zero-day window and the correlation with HTTP status codes
  and follow-on botnet C2 that this phased hunt provides.
blind_spots:
- id: brotli-stream-blindspot
  question: Was a specifically crafted Brotli-compressed stream used to trigger memory
    corruption?
  requires: Full HTTP request body inspection
  risk: Exploit payloads inside valid compressed streams are invisible to hb_http_activity.
  stage: initial-access-vuln-exploitation
- id: no-identity-ip-correlation
  question: Is the external IP used for a VPN sign-in definitely the same as the attacker's
    beachhead IP?
  requires: Device-to-Identity IP correlation logs
  risk: An attacker using different IPs for RCE and persistence may evade correlation
    if src_endpoint_ip doesn't match.
  stage: external-remote-persistence
coverage:
- stage: initial-access-vuln-exploitation
  status: covered
  steps:
  - scope-vulnerable-runtimes
  - http-exploitation-attempts
- stage: unauthenticated-remote-code-execution
  status: covered
  steps:
  - rce-shell-execution
- stage: botnet-command-and-control
  status: covered
  steps:
  - mirai-botnet-c2
- stage: external-remote-persistence
  status: covered
  steps:
  - remote-access-persistence
- stage: data-encryption-impact
  status: covered
  steps:
  - investigate-impact
guardrails:
  claims: no_unsupported
  evidence: citation_required
  missing_data: not_benign
  telemetry: untrusted
hunt:
  applicability: campaign-specific
  handoff: keep-as-periodic-hunt
  justification: Threat actors exploited critical web runtime vulnerabilities four
    days before patches existed. Identifying these breaches requires investigating
    activity during the October zero-day window across several telemetry surfaces.
  methodology: model-assisted
  trigger: intel-report
hypothesis: An attacker has exploited a zero-day vulnerability in an internet-facing
  web runtime during the four-day pre-patch window (Oct 17-21, 2026) to gain remote
  code execution, established botnet C2, and leveraged stolen credentials to persist
  via remote access services.
labels:
- hunt
- attack.t1190
- attack.t1133
- attack.t1486
- command and control
- execution
- impact
- initial access
- persistence
name: Pre-Patch Web Runtime Exploitation
parameters:
  end_date:
    default: '2026-10-21 23:59:59'
    description: The date the official patch was released.
    from:
      kind: article
      observed: '2026-10-21'
      ref: sekoia-php2shell
    type: string
  runtime_packages:
    default:
    - php
    - node
    - nodejs
    - bun
    description: Package names representing the targeted web runtimes.
    type: list[string]
  scope_hosts:
    default: []
    description: Hostnames to focus the investigation; leave empty to hunt across
      the entire estate.
    type: list[host]
  start_date:
    default: '2026-10-17 00:00:00'
    description: The date active zero-day exploitation was first observed.
    from:
      kind: article
      observed: '2026-10-17'
      ref: sekoia-php2shell
    type: string
  suspicious_ips:
    default: []
    description: IP addresses identified as suspicious in the first phase; leave empty
      to search all authentication attempts during the window.
    from:
      kind: article
      observed: '2026-10-27'
      ref: https://www.sekoia.com/blog/php2shell-was-exploited-before-the-patch-expect-more-of-it
    type: list[ip]
provenance:
  authors:
  - name: Huntbase hunt generation
    org: huntbase.io
  generated:
    by: huntbase-hunt-generation
    from: https://www.sekoia.com/blog/php2shell-was-exploited-before-the-patch-expect-more-of-it
    gates:
    - dry-run
    - lint
    model: hb_google/gemini-3-flash-preview
rationale: Focus on internet-facing servers running PHP or Node.js. Narrow the search
  to the specific window from Oct 17 to Oct 21, 2026.
references:
- name: PHP2Shell Was Exploited Before the Patch
  url: https://www.sekoia.com/blog/php2shell-was-exploited-before-the-patch-expect-more-of-it
related:
- hunt: mirai-botnet-persistence-patterns
  reason: This hunt focuses on the initial zero-day web vector; general Mirai persistence
    is handled separately.
  relation: out-of-scope-alternative
scenario:
  stages:
  - name: Exploitation of Web Runtimes
    observables:
    - CVE-2026-111497
    - Brotli-compressed streams
    - Scanning for PHP 8.1 or older
    - Requests targeting Node.js, Bun, or PHP instances
    - Attempts captured on 2026-10-17
    slug: initial-access-vuln-exploitation
    tactic: initial-access
    techniques:
    - T1190
  - name: RCE via Web Server
    observables:
    - PHP or Node.js processes spawning shells
    - /bin/sh
    - /bin/bash
    - curl or wget used for downloader scripts
    - One-line root fix scripts from GitHub
    slug: unauthenticated-remote-code-execution
    tactic: execution
    techniques:
    - T1190
  - name: Botnet Communication
    observables:
    - Mirai botnet C2 traffic
    - Outbound network connections from web server to known botnet IPs
    slug: botnet-command-and-control
    tactic: command-and-control
    techniques:
    - T1190
  - name: Persistence via Remote Services
    observables:
    - Anomalous sign-ins to VPN gateways
    - Citrix appliance access patterns following web server compromise
    slug: external-remote-persistence
    tactic: persistence
    techniques:
    - T1133
  - name: Data Encryption for Impact
    observables:
    - Ransomware encryption on local drives
    - Mass file modification on web servers
    slug: data-encryption-impact
    tactic: impact
    techniques:
    - T1486
  summary: Threat actors exploited critical PHP and Brotli vulnerabilities (CVE-2026-111497)
    during a 'negative window' before official patches were released. The campaign
    involved mass scanning of internet-facing web runtimes to achieve unauthenticated
    remote code execution, primarily for botnet recruitment and potential ransomware
    impact.
severity: critical
targets:
  analyst:
    name: Tier-2 analyst
    role: analyst
  endpoint:
    category: endpoint
    name: Endpoint telemetry (hb_ surfaces)
    telemetry:
    - endpoint
  hunter:
    agent: true
    name: Hunt agent
  identity:
    category: identity
    name: Identity / sign-in telemetry
    telemetry:
    - identity
  network:
    category: network
    name: Network telemetry
    telemetry:
    - network
  web:
    category: siem
    name: Web server / proxy logs
    telemetry:
    - network
tlp: clear
type: investigation
---


# Pre-Patch Web Runtime Exploitation

This hunt examines the negative window between the start of active exploitation for vulnerabilities like PHP2Shell and Node2Shell (CVE-2026-111497) and the release of patches on October 21, 2026. Threat actors were observed scanning and exploiting these systems days before a fix existed, meaning patching alone is insufficient for response. The hunt uses a phased approach: first, it identifies exposed runtimes and correlates 500-series web errors with suspicious shell interpreters spawned by web processes. Second, it searches for follow-on botnet communication and anomalous logins to VPN or Citrix gateways from IPs involved in the initial RCE.

## scope-vulnerable-runtimes
<!-- Scope vulnerable runtimes -->
Identify hosts running targeted web runtimes that were vulnerable during the October 2026 window.

```sqlite target=endpoint role=scoping params=(runtime_packages=runtime_packages, scope_hosts=scope_hosts)
~~~yaml
expected: A list of hosts and paths where PHP, Node.js or Bun are installed. Silence
  means these runtimes are not under management.
reads:
- device_hostname
- package_name
- package_version
- install_path
silence: not_evidence_of_absence
source: hb_software_inventory
verified: dry-run
verified_at: '2026-10-29'
~~~
SELECT device_hostname, package_name, package_version, install_path FROM hb_software_inventory WHERE (instr(',' || '{{runtime_packages}}' || ',', ',' || LOWER(package_name) || ',') > 0) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0)
```

## early-stage-fan-out
<!-- Correlate exploitation and execution -->
parallel:
- → http-exploitation-attempts
- → rce-shell-execution
join: → triage-exploitation

## http-exploitation-attempts
<!-- HTTP exploitation attempts -->
Identify HTTP requests targeting web servers that resulted in server errors or heavy POST activity during the zero-day window.

```sqlite target=web role=enrichment params=(scope_hosts=scope_hosts, start_date=start_date, end_date=end_date)
~~~yaml
expected: Unusual URIs with 500-series errors or high volumes of POST requests. Silence
  proves absence only if web server logging is enabled.
reads:
- device_hostname
- src_endpoint_ip
- http_method
- url_path
- status_code
- time
silence: not_evidence_of_absence
source: hb_http_activity
verified: dry-run
verified_at: '2026-10-29'
~~~
SELECT device_hostname, src_endpoint_ip, http_method, url_path, status_code, COUNT(*) AS request_count FROM hb_http_activity WHERE (status_code >= 500 OR http_method = 'POST') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND (time >= '{{start_date}}' AND time <= '{{end_date}}') GROUP BY device_hostname, src_endpoint_ip, http_method, url_path, status_code ORDER BY request_count DESC
```

## rce-shell-execution
<!-- RCE shell execution -->
Detect instances where a web runtime process spawns a shell or downloader, indicating successful unauthenticated execution.

```sqlite target=endpoint role=detection-candidate params=(scope_hosts=scope_hosts, start_date=start_date, end_date=end_date)
~~~yaml
expected: A web runtime parent spawning a shell or network utility. This is highly
  suspicious during a zero-day window.
reads:
- device_hostname
- process_name
- process_cmd_line
- parent_process_name
- user_name
- time
silence: evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-10-29'
~~~
SELECT device_hostname, process_name, process_cmd_line, parent_process_name, user_name, time FROM hb_process_activity WHERE (LOWER(parent_process_name) LIKE '%/php%' OR LOWER(parent_process_name) LIKE '%/node%' OR LOWER(parent_process_name) LIKE '%/bun%' OR LOWER(parent_process_name) LIKE '%/httpd%' OR LOWER(parent_process_name) LIKE '%/nginx%') AND (LOWER(process_name) LIKE '%/sh' OR LOWER(process_name) LIKE '%/bash' OR LOWER(process_name) LIKE '%/curl' OR LOWER(process_name) LIKE '%/wget') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND (time >= '{{start_date}}' AND time <= '{{end_date}}')
```

## triage-exploitation
<!-- Triage early exploitation -->
```agent target=hunter
cite: required
context:
- scope-vulnerable-runtimes
- http-exploitation-attempts
- rce-shell-execution
max_iterations: 4
objective: Determine if any host with a web runtime shows signs of unauthenticated
  remote code execution citing HTTP errors and shell spawning.
success_criteria: Verdicts citing the specific web runtime and the subsequent shell
  commands.
tools:
- endpoint
- identity
- network
- web
```

## follow-on-fan-out
<!-- Hunt follow-on activity -->
parallel:
- → mirai-botnet-c2
- → remote-access-persistence
join: → triage-intrusion

## mirai-botnet-c2
<!-- Mirai botnet C2 -->
Detect outbound connections to rare external IPs, indicative of a botnet agent established via the RCE.

```sqlite target=network role=baseline params=(scope_hosts=scope_hosts, start_date=start_date, end_date=end_date)
~~~yaml
baseline:
  compare: first_seen
  window: 5d
expected: Outbound connections to unique IPs. Mirai often targets non-standard ports
  (23, 2323) but may use 80/443.
prevalence:
  by: device_hostname
  key:
  - dst_endpoint_ip
  rare_below: 3
reads:
- device_hostname
- dst_endpoint_ip
- dst_endpoint_port
- direction
- time
silence: not_evidence_of_absence
source: hb_network_connection
verified: dry-run
verified_at: '2026-10-29'
~~~
SELECT dst_endpoint_ip, dst_endpoint_port, COUNT(DISTINCT device_hostname) AS host_count, MIN(time) AS first_seen FROM hb_network_connection WHERE direction = 'outbound' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND (time >= '{{start_date}}' AND time <= '{{end_date}}') GROUP BY dst_endpoint_ip, dst_endpoint_port HAVING host_count <= 2 ORDER BY host_count ASC
```

## remote-access-persistence
<!-- Remote access persistence -->
Identify successful sign-ins to VPN or Citrix gateways from IP addresses involved in the RCE or botnet activity.

```sqlite target=identity role=triage params=(suspicious_ips=suspicious_ips, start_date=start_date, end_date=end_date)
~~~yaml
expected: Successful logons to gateways from external IPs identified as suspicious.
  This indicates credential reuse or theft.
reads:
- actor_user_name
- src_endpoint_ip
- provider
- dst_endpoint_name
- time
silence: not_evidence_of_absence
source: hb_auth_signin
verified: dry-run
verified_at: '2026-10-29'
~~~
SELECT actor_user_name, src_endpoint_ip, provider, dst_endpoint_name, time FROM hb_auth_signin WHERE (instr(',' || '{{suspicious_ips}}' || ',', ',' || src_endpoint_ip || ',') > 0 OR '{{suspicious_ips}}' = '') AND status_id = 1 AND (time >= '{{start_date}}' AND time <= '{{end_date}}')
```

## triage-intrusion
<!-- Triage intrusion chain -->
```agent target=hunter
cite: required
context:
- triage-exploitation
- mirai-botnet-c2
- remote-access-persistence
max_iterations: 6
objective: Confirm whether the RCE beachhead was used to establish botnet C2 or pivot
  to external remote services.
success_criteria: A final verdict identifying compromised hosts, IPs, and accounts
  with high confidence.
tools:
- endpoint
- identity
- network
- web
```

## route-on-verdict
<!-- Route on verdict -->
if~: "the triage-intrusion verdict is malicious for at least one host" (confidence: high, judge=hunter)
then: → isolate-and-revoke
indeterminate: → investigate-impact
unavailable: → investigate-impact (blind_spot: brotli-stream-blindspot)
else: → close-out

## isolate-and-revoke
<!-- Isolate and revoke -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the compromised web server from the network and revoke any active VPN or Citrix sessions associated with the user accounts involved in the suspicious sign-ins.
```
→ investigate-impact

## investigate-impact
<!-- Investigate impact -->
```manual target=analyst
Review hb_file_activity on the compromised host for mass modification or renaming (ransomware indicators) and check shell_history for commands executed by the attacker.
```
→ close-out

## close-out
<!-- Close out -->
```manual target=analyst
Confirm that all web runtimes identified in the scoping step have been patched to versions released on or after October 21, 2026. Document any gaps in log visibility found during the triage.
```
→ end
