{
  "hunt": {
    "meta": {
      "tlp": "clear",
      "hunt": {
        "handoff": "keep-as-periodic-hunt",
        "trigger": "intel-report",
        "methodology": "model-assisted",
        "applicability": "campaign-specific",
        "justification": "The wp2shell exploit chain allows pre-authentication RCE on millions of WordPress instances. Detecting the host-side behavior is the primary way to find compromised hosts where network scanning might be obfuscated."
      },
      "name": "Web Server Shell Execution and wp2shell Post-Exploitation",
      "type": "investigation",
      "labels": [
        "hunt",
        "attack.t1059",
        "attack.t1059.004",
        "attack.t1505.003",
        "attack.t1082",
        "attack.t1033",
        "attack.t1070.004"
      ],
      "series": {
        "slug": "wp2shell-hits-wordpress-detecting-pre-auth-rce-from-plugin-drop-to-command-execution",
        "index": 2,
        "title": "wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution",
        "total": 2
      },
      "related": [
        {
          "hunt": "malicious-plugin-staging-wordpress",
          "reason": "This hunt focuses on the execution phase; a sibling hunt should examine the Zip and PHP file staging anomalies.",
          "relation": "out-of-scope-alternative"
        },
        {
          "hunt": "wordpress-rest-api-exploitation-plugin-staging",
          "relation": "follows"
        }
      ],
      "targets": {
        "hunter": {
          "name": "Hunt agent",
          "agent": true
        },
        "analyst": {
          "name": "Tier-2 analyst",
          "role": "analyst"
        },
        "endpoint": {
          "name": "Endpoint telemetry (hb_ surfaces)",
          "category": "endpoint",
          "telemetry": [
            "endpoint"
          ]
        }
      },
      "analysis": "A simple detection rule may fire on any shell from a web server; this hunt adds the behavioral context of stack-counting rare commands and correlating with automated cleanup actions across two telemetry surfaces to confirm an actual intrusion.",
      "coverage": [
        {
          "stage": "shell-spawn-from-web-server",
          "steps": [
            "detect-web-shell-spawn",
            "evaluate-lead"
          ],
          "status": "covered"
        },
        {
          "stage": "post-exploitation-discovery",
          "steps": [
            "rare-shell-commands"
          ],
          "status": "covered"
        },
        {
          "stage": "automated-self-cleanup",
          "steps": [
            "cleanup-file-events"
          ],
          "status": "covered"
        },
        {
          "stage": "exploit-wordpress-batch-api",
          "reason": "Belongs to another part of the 'wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "malicious-plugin-staging",
          "reason": "Belongs to another part of the 'wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution' series.",
          "status": "out_of_scope"
        }
      ],
      "scenario": {
        "stages": [
          {
            "name": "Exploitation of WordPress REST batch API",
            "slug": "exploit-wordpress-batch-api",
            "tactic": "initial-access",
            "techniques": [
              "T1190"
            ],
            "observables": [
              "POST /?rest_route=/batch/v1",
              "POST /wp-json/batch/v1",
              "User-Agent: wp2shell",
              "CVE-2026-63030",
              "CVE-2026-60137"
            ]
          },
          {
            "name": "Malicious plugin staging on disk",
            "slug": "malicious-plugin-staging",
            "tactic": "persistence",
            "techniques": [
              "T1505.003"
            ],
            "observables": [
              "wp-content/plugins/wp2shell_*",
              "wp-content/uploads/wp2shell_*.zip",
              "temp-write-test-*",
              "wp-content/upgrade/wp2shell_*/",
              "wp-content/plugins/wp2shell_*.php"
            ]
          },
          {
            "name": "Shell execution by web server process",
            "slug": "shell-spawn-from-web-server",
            "tactic": "execution",
            "techniques": [
              "T1059"
            ],
            "observables": [
              "apache2 spawning dash",
              "httpd spawning sh",
              "php-fpm spawning bash",
              "sh -c -- id; whoami; hostname"
            ]
          },
          {
            "name": "System and privilege reconnaissance",
            "slug": "post-exploitation-discovery",
            "tactic": "discovery",
            "techniques": [
              "T1082",
              "T1033"
            ],
            "observables": [
              "uname",
              "cat /etc/passwd",
              "find / -perm -u=s -type f"
            ]
          },
          {
            "name": "Indicator removal and cleanup",
            "slug": "automated-self-cleanup",
            "tactic": "defense-evasion",
            "techniques": [
              "T1070.004"
            ],
            "observables": [
              "rm -rf wp-content/plugins/wp2shell_*",
              "deletion of staged zip files under wp-content/uploads/"
            ]
          }
        ],
        "summary": "Attackers leverage a pre-authentication RCE vulnerability in the WordPress REST batch API (CVE-2026-63030) to stage malicious plugins or web shells on vulnerable servers. Once established, the web server process is used to execute system shells for reconnaissance and automated artifact cleanup."
      },
      "severity": "high",
      "rationale": "Focus on the Linux fleet hosting public-facing WordPress instances. Identify web server processes first, then look for shell transitions.",
      "guardrails": {
        "claims": "no_unsupported",
        "evidence": "citation_required",
        "telemetry": "untrusted",
        "missing_data": "not_benign"
      },
      "hypothesis": "An attacker has exploited a WordPress vulnerability to spawn a shell from a web server process and is currently performing system discovery or cleaning up traces of the wp2shell plugin.",
      "parameters": {
        "lookback_days": {
          "from": {
            "ref": "hunt-standard",
            "kind": "manual",
            "observed": "2026-07-23"
          },
          "type": "number",
          "default": "14",
          "description": "Days of history to examine."
        },
        "shell_children": {
          "from": {
            "ref": "elastic-security-labs",
            "kind": "article",
            "observed": "2026-07-23"
          },
          "type": "list[string]",
          "default": [
            "sh",
            "bash",
            "dash",
            "zsh",
            "ksh",
            "fish"
          ],
          "description": "Common shell process names spawned during exploitation."
        },
        "web_server_parents": {
          "from": {
            "ref": "elastic-security-labs",
            "kind": "article",
            "observed": "2026-07-23"
          },
          "type": "list[string]",
          "default": [
            "apache2",
            "httpd",
            "php-fpm",
            "php-cgi",
            "nginx",
            "php-fcgi",
            "lsphp",
            "sw-engine-fpm"
          ],
          "description": "Common web server and PHP runtime process names to monitor as parents."
        }
      },
      "provenance": {
        "authors": [
          {
            "org": "huntbase.io",
            "name": "Huntbase hunt generation"
          }
        ],
        "generated": {
          "by": "huntbase-hunt-generation",
          "from": "https://www.elastic.co/security-labs/blog/wp2shell-wordpress-rce-detection-elastic-defend",
          "gates": [
            "dry-run",
            "lint",
            "critic"
          ],
          "model": "hb_google/gemini-3-flash-preview"
        }
      },
      "references": [
        {
          "url": "https://www.elastic.co/security-labs/blog/wp2shell-wordpress-rce-detection-elastic-defend",
          "name": "elastic-security-labs \u2014 wp2shell hits WordPress"
        }
      ],
      "blind_spots": [
        {
          "id": "insufficient-process-telemetry",
          "risk": "If parent command line data is missing, distinguishing legitimate server restarts from RCE spawns becomes difficult.",
          "stage": "shell-spawn-from-web-server",
          "question": "whether the web server spawned the shell with an exploit payload",
          "requires": "hb_process_activity with parent command line information"
        },
        {
          "id": "insufficient-file-telemetry",
          "risk": "If file deletion logging is disabled for the web root, the post-exploitation cleanup phase remains invisible.",
          "stage": "automated-self-cleanup",
          "question": "whether the attacker cleaned up the plugin files",
          "requires": "hb_file_activity recording activity_id 4 (deletion)"
        }
      ]
    },
    "name": "Web Server Shell Execution and wp2shell Post-Exploitation",
    "description": "This hunt focuses on the host-side behavior of the wp2shell RCE chain (CVE-2026-63030). It targets the specific transition where a web server or PHP runtime spawns a command shell, followed by reconnaissance and automated cleanup. By using a gated flow, the hunt first identifies suspicious parent-child process pairs before fanning out to search for rare discovery commands and specific file deletion patterns that indicate a successful compromise."
  },
  "nodes": [
    {
      "id": "hypothesis",
      "type": "hypothesis",
      "label": "Hypothesis",
      "config": {
        "tags": [],
        "series": {
          "slug": "wp2shell-hits-wordpress-detecting-pre-auth-rce-from-plugin-drop-to-command-execution",
          "index": 2,
          "title": "wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution",
          "total": 2
        },
        "coverage": [
          {
            "stage": "shell-spawn-from-web-server",
            "steps": [
              "detect-web-shell-spawn",
              "evaluate-lead"
            ],
            "status": "covered"
          },
          {
            "stage": "post-exploitation-discovery",
            "steps": [
              "rare-shell-commands"
            ],
            "status": "covered"
          },
          {
            "stage": "automated-self-cleanup",
            "steps": [
              "cleanup-file-events"
            ],
            "status": "covered"
          },
          {
            "stage": "exploit-wordpress-batch-api",
            "reason": "Belongs to another part of the 'wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "malicious-plugin-staging",
            "reason": "Belongs to another part of the 'wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution' series.",
            "status": "out_of_scope"
          }
        ],
        "rationale": "An attacker has exploited a WordPress vulnerability to spawn a shell from a web server process and is currently performing system discovery or cleaning up traces of the wp2shell plugin.",
        "blind_spots": [
          {
            "id": "insufficient-process-telemetry",
            "risk": "If parent command line data is missing, distinguishing legitimate server restarts from RCE spawns becomes difficult.",
            "stage": "shell-spawn-from-web-server",
            "question": "whether the web server spawned the shell with an exploit payload",
            "requires": "hb_process_activity with parent command line information"
          },
          {
            "id": "insufficient-file-telemetry",
            "risk": "If file deletion logging is disabled for the web root, the post-exploitation cleanup phase remains invisible.",
            "stage": "automated-self-cleanup",
            "question": "whether the attacker cleaned up the plugin files",
            "requires": "hb_file_activity recording activity_id 4 (deletion)"
          }
        ],
        "scoping_notes": "Focus on the Linux fleet hosting public-facing WordPress instances. Identify web server processes first, then look for shell transitions.",
        "beyond_detection": "A simple detection rule may fire on any shell from a web server; this hunt adds the behavioral context of stack-counting rare commands and correlating with automated cleanup actions across two telemetry surfaces to confirm an actual intrusion."
      }
    },
    {
      "id": "detect-web-shell-spawn",
      "type": "query",
      "label": "Web server shell spawns",
      "config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "source": "endpoint",
        "content": "SELECT device_hostname, process_name, process_cmd_line, parent_process_name, parent_process_cmd_line, user_name, time FROM hb_process_activity WHERE (instr(',' || '{{web_server_parents}}' || ',', ',' || LOWER(parent_process_name) || ',') > 0 OR LOWER(parent_process_name) LIKE 'php-fpm%') AND instr(',' || '{{shell_children}}' || ',', ',' || LOWER(process_name) || ',') > 0 AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_process_activity",
        "description": "Identify instances where a web server or PHP runtime process is the direct parent of a command shell, indicating potential RCE.",
        "expected_signal": "Rows showing a web server parent (e.g., apache2) spawning a shell (e.g., dash) as a low-privileged user (e.g., www-data). Silence suggests no such direct process spawns occurred."
      },
      "parents": [
        {
          "id": "hypothesis"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "label": "Web server shell spawns",
        "reads": [
          "device_hostname",
          "parent_process_cmd_line",
          "parent_process_name",
          "process_cmd_line",
          "process_name",
          "time",
          "user_name"
        ],
        "source": "hb_process_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, process_name, process_cmd_line, parent_process_name, parent_process_cmd_line, user_name, time FROM hb_process_activity WHERE (instr(',' || '{{web_server_parents}}' || ',', ',' || LOWER(parent_process_name) || ',') > 0 OR LOWER(parent_process_name) LIKE 'php-fpm%') AND instr(',' || '{{shell_children}}' || ',', ',' || LOWER(process_name) || ',') > 0 AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Rows showing a web server parent (e.g., apache2) spawning a shell (e.g., dash) as a low-privileged user (e.g., www-data). Silence suggests no such direct process spawns occurred.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "evaluate-lead",
      "type": "analytic",
      "label": "Evaluate shell spawn leads",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint"
        ],
        "context": [
          "detect-web-shell-spawn"
        ],
        "objective": "Determine if any of the shell spawns identified in detect-web-shell-spawn are suspicious for RCE post-exploitation.",
        "description": "Filter out legitimate maintenance activity or known scripts to identify truly suspicious RCE shell spawns.",
        "max_iterations": 3,
        "expected_signal": "A per-host verdict on whether the shell spawn matches the wp2shell pattern (e.g., running from web directories, low-priv user).",
        "success_criteria": "A clear assessment citing suspicious process lineages and command lines."
      },
      "parents": [
        {
          "id": "detect-web-shell-spawn"
        }
      ]
    },
    {
      "id": "gate-on-lead",
      "type": "checkpoint",
      "label": "Gate on lead suspicion",
      "config": {
        "fuzzy": true,
        "judge": "hunter",
        "question": "the evaluate-lead verdict is suspicious or malicious for at least one host",
        "condition": "the evaluate-lead verdict is suspicious or malicious for at least one host",
        "blind_spot": "insufficient-process-telemetry",
        "confidence": "high",
        "description": "Only proceed to expensive behavioral queries if the initial shell spawn is deemed suspicious.",
        "checkpoint_type": "mandatory"
      },
      "parents": [
        {
          "id": "evaluate-lead"
        }
      ]
    },
    {
      "id": "rare-shell-commands",
      "type": "query",
      "label": "Rare reconnaissance commands",
      "config": {
        "dsl": "sqlite",
        "role": "baseline",
        "source": "endpoint",
        "content": "SELECT LOWER(process_cmd_line) AS cmd, COUNT(DISTINCT device_hostname) AS host_count, MIN(time) AS first_seen FROM hb_process_activity WHERE (instr(',' || '{{web_server_parents}}' || ',', ',' || LOWER(parent_process_name) || ',') > 0 OR instr(',' || '{{shell_children}}' || ',', ',' || LOWER(parent_process_name) || ',') > 0) AND (LOWER(process_cmd_line) LIKE '%id%' OR LOWER(process_cmd_line) LIKE '%whoami%' OR LOWER(process_cmd_line) LIKE '%hostname%' OR LOWER(process_cmd_line) LIKE '%uname%' OR LOWER(process_cmd_line) LIKE '%/etc/passwd%' OR LOWER(process_cmd_line) LIKE '%-perm%') AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY LOWER(process_cmd_line) HAVING host_count < 3 ORDER BY host_count ASC",
        "surface": "hb_process_activity",
        "description": "Find rare system and privilege discovery commands executed by the identified shells.",
        "expected_signal": "Rarely seen commands like 'find / -perm -u=s' or 'cat /etc/passwd' occurring on a small number of hosts. Silence means no such commands were recorded for the suspicious processes."
      },
      "parents": [
        {
          "id": "gate-on-lead",
          "branch": "on_supports"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "baseline",
        "label": "Rare reconnaissance commands",
        "reads": [
          "device_hostname",
          "parent_process_name",
          "process_cmd_line",
          "time"
        ],
        "source": "hb_process_activity",
        "target": "endpoint",
        "content": "SELECT LOWER(process_cmd_line) AS cmd, COUNT(DISTINCT device_hostname) AS host_count, MIN(time) AS first_seen FROM hb_process_activity WHERE (instr(',' || '{{web_server_parents}}' || ',', ',' || LOWER(parent_process_name) || ',') > 0 OR instr(',' || '{{shell_children}}' || ',', ',' || LOWER(parent_process_name) || ',') > 0) AND (LOWER(process_cmd_line) LIKE '%id%' OR LOWER(process_cmd_line) LIKE '%whoami%' OR LOWER(process_cmd_line) LIKE '%hostname%' OR LOWER(process_cmd_line) LIKE '%uname%' OR LOWER(process_cmd_line) LIKE '%/etc/passwd%' OR LOWER(process_cmd_line) LIKE '%-perm%') AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY LOWER(process_cmd_line) HAVING host_count < 3 ORDER BY host_count ASC",
        "silence": "not_evidence_of_absence",
        "baseline": {
          "window": "{{lookback_days}}d",
          "compare": "first_seen"
        },
        "expected": "Rarely seen commands like 'find / -perm -u=s' or 'cat /etc/passwd' occurring on a small number of hosts. Silence means no such commands were recorded for the suspicious processes.",
        "verified": "dry-run",
        "prevalence": {
          "by": "device_hostname",
          "key": [
            "cmd"
          ],
          "rare_below": 3
        },
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "cleanup-file-events",
      "type": "query",
      "label": "Cleanup file deletions",
      "config": {
        "dsl": "sqlite",
        "role": "enrichment",
        "source": "endpoint",
        "content": "SELECT device_hostname, file_path, activity_name, time FROM hb_file_activity WHERE activity_id = 4 AND (LOWER(file_path) LIKE '%/wp-content/plugins/wp2shell_%' OR LOWER(file_path) LIKE '%/wp-content/uploads/wp2shell_%.zip') AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_file_activity",
        "description": "Detect the removal of wp2shell plugin artifacts or staged zip files.",
        "expected_signal": "Deletions of files under the WordPress plugin or upload directories matching the wp2shell pattern. Silence suggests the attacker's automated cleanup did not trigger or was not captured."
      },
      "parents": [
        {
          "id": "gate-on-lead",
          "branch": "on_supports"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "enrichment",
        "label": "Cleanup file deletions",
        "reads": [
          "activity_id",
          "activity_name",
          "device_hostname",
          "file_path",
          "time"
        ],
        "source": "hb_file_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, file_path, activity_name, time FROM hb_file_activity WHERE activity_id = 4 AND (LOWER(file_path) LIKE '%/wp-content/plugins/wp2shell_%' OR LOWER(file_path) LIKE '%/wp-content/uploads/wp2shell_%.zip') AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Deletions of files under the WordPress plugin or upload directories matching the wp2shell pattern. Silence suggests the attacker's automated cleanup did not trigger or was not captured.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "final-triage",
      "type": "analytic",
      "label": "Final triage of compromise",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint"
        ],
        "context": [
          "evaluate-lead",
          "rare-shell-commands",
          "cleanup-file-events"
        ],
        "objective": "Weigh the initial lead with the corroborating evidence of rare discovery and file deletions to confirm active wp2shell exploitation.",
        "description": "Correlate shell spawns, discovery commands, and cleanup file events into a final verdict.",
        "max_iterations": 5,
        "expected_signal": "A unified malicious | suspicious | benign verdict per host citing the full attack sequence.",
        "success_criteria": "A detailed timeline and verdict for each host in scope."
      },
      "parents": [
        {
          "id": "rare-shell-commands",
          "kind": "merge"
        },
        {
          "id": "cleanup-file-events",
          "kind": "merge"
        }
      ]
    },
    {
      "id": "route-final",
      "type": "checkpoint",
      "label": "Route on final verdict",
      "config": {
        "fuzzy": true,
        "judge": "hunter",
        "question": "the final-triage verdict is malicious for at least one host",
        "condition": "the final-triage verdict is malicious for at least one host",
        "blind_spot": "insufficient-file-telemetry",
        "confidence": "high",
        "description": "Initiate response for confirmed compromised hosts.",
        "checkpoint_type": "mandatory"
      },
      "parents": [
        {
          "id": "final-triage"
        }
      ]
    },
    {
      "id": "isolate-host",
      "type": "action",
      "label": "Isolate host",
      "config": {
        "target": "endpoint",
        "description": "Prevent lateral movement and data exfiltration from a compromised WordPress instance.",
        "instructions": "Isolate the host immediately. Do not restart the web server until memory forensics or binary preservation has been completed.",
        "action_approval": "required"
      },
      "parents": [
        {
          "id": "route-final",
          "branch": "on_supports"
        }
      ]
    },
    {
      "id": "analyst-review",
      "type": "task",
      "label": "Analyst review",
      "config": {
        "assignee": "analyst",
        "description": "Review the hunt findings, confirm the intrusion, and document attacker actions.",
        "instructions": "Review the cited rows from final-triage. Identify the specific WordPress plugin used for staging and check for any additional webshells dropped under wp-content/cache/ or wp-content/uploads/."
      },
      "parents": [
        {
          "id": "gate-on-lead",
          "branch": "default"
        },
        {
          "id": "gate-on-lead",
          "branch": "on_unavailable"
        },
        {
          "id": "route-final",
          "branch": "default"
        },
        {
          "id": "route-final",
          "branch": "on_unavailable"
        },
        {
          "id": "route-final",
          "branch": "on_refutes"
        },
        {
          "id": "isolate-host"
        }
      ]
    },
    {
      "id": "close-out",
      "type": "task",
      "label": "Close out",
      "config": {
        "assignee": "analyst",
        "description": "Summarize the hunt and record the negative result.",
        "instructions": "Document the hosts and time windows examined. Log that no suspicious web server shells or wp2shell artifacts were found. Verify that patches for CVE-2026-63030 are being applied."
      },
      "parents": [
        {
          "id": "gate-on-lead",
          "branch": "on_refutes"
        }
      ]
    }
  ]
}