{
  "hunt": {
    "meta": {
      "tlp": "clear",
      "hunt": {
        "handoff": "promote-to-detection",
        "trigger": "intel-report",
        "methodology": "model-assisted",
        "applicability": "campaign-specific",
        "justification": "WordPress RCE (wp2shell) provides a pre-authentication path to full host compromise. Given the high prevalence of WordPress and the availability of public PoCs, an unmitigated compromise on a production web server poses a critical risk of data theft and lateral movement."
      },
      "name": "WordPress REST API Exploitation and Plugin Staging",
      "type": "investigation",
      "labels": [
        "hunt",
        "attack.t1190",
        "attack.t1505.003",
        "attack.t1059"
      ],
      "series": {
        "slug": "wp2shell-hits-wordpress-detecting-pre-auth-rce-from-plugin-drop-to-command-execution",
        "index": 1,
        "title": "wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution",
        "total": 2
      },
      "related": [
        {
          "hunt": "wordpress-webshell-execution",
          "reason": "This hunt focuses on the staging stage; a follow-on hunt is required to detect the execution of commands via the webshell once it is staged.",
          "relation": "follows"
        }
      ],
      "targets": {
        "web": {
          "name": "Web server / proxy logs",
          "category": "siem",
          "telemetry": [
            "network"
          ]
        },
        "hunter": {
          "name": "Hunt agent",
          "agent": true
        },
        "analyst": {
          "name": "Tier-2 analyst",
          "role": "analyst"
        },
        "endpoint": {
          "name": "Endpoint telemetry (hb_ surfaces)",
          "category": "endpoint",
          "telemetry": [
            "endpoint"
          ]
        }
      },
      "analysis": "While a single rule may alert on the plugin drop, this hunt correlates the initial API exploit (network surface) with the resulting staging activity (file surface) and uses prevalence to identify the specific malicious plugin among legitimate site updates. This reduces false positives from authorized administrative plugin installs.",
      "coverage": [
        {
          "stage": "exploit-wordpress-batch-api",
          "steps": [
            "scoping-vulnerable-assets",
            "http-batch-api-exploitation"
          ],
          "status": "covered"
        },
        {
          "stage": "malicious-plugin-staging",
          "steps": [
            "rare-plugin-file-drops"
          ],
          "status": "covered"
        },
        {
          "stage": "shell-spawn-from-web-server",
          "reason": "Covered by follow-on behavioral hunts in the series.",
          "status": "out_of_scope"
        },
        {
          "stage": "post-exploitation-discovery",
          "reason": "Covered by general Linux discovery hunts.",
          "status": "out_of_scope"
        },
        {
          "stage": "automated-self-cleanup",
          "reason": "Cleanup activity is the last stage and requires separate file-deletion logic.",
          "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": "Prioritize internet-facing hosts running WordPress 6.9.x or 7.0.x. If vulnerability findings are incomplete, run the HTTP exploitation query across all systems identified as web servers.",
      "guardrails": {
        "claims": "no_unsupported",
        "evidence": "citation_required",
        "telemetry": "untrusted",
        "missing_data": "not_benign"
      },
      "hypothesis": "An attacker is exploiting the wp2shell WordPress Core RCE chain to upload and stage a malicious plugin by abusing the unauthenticated REST batch API.",
      "parameters": {
        "scope_hosts": {
          "type": "list[host]",
          "default": [],
          "description": "Optional list of hostnames to restrict the hunt; leave empty to scan the entire estate."
        },
        "lookback_days": {
          "type": "number",
          "default": "14",
          "description": "Days of history to examine."
        },
        "vulnerable_cves": {
          "from": {
            "ref": "elastic-security-labs-wp2shell",
            "kind": "article",
            "observed": "2026-07-23"
          },
          "type": "list[string]",
          "default": [
            "CVE-2026-60137",
            "CVE-2026-63030"
          ],
          "description": "CVE IDs associated with the wp2shell vulnerability."
        }
      },
      "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": "missing-http-telemetry",
          "risk": "Encrypted traffic may prevent seeing the User-Agent or full URL query parameters used in the exploit chain.",
          "stage": "exploit-wordpress-batch-api",
          "question": "Were the specific batch API parameters (SQL injection payloads) visible in the request?",
          "requires": "TLS decryption at the log source (hb_http_activity)"
        },
        {
          "id": "alternate-staging-paths",
          "risk": "If the attacker avoids the plugin-staging mechanism and writes directly to other writable directories, the rare-plugin query will not see the file drop.",
          "stage": "malicious-plugin-staging",
          "question": "Did the attacker drop a webshell using INTO OUTFILE into the cache or uploads directory?",
          "requires": "Full file monitoring outside wp-content/plugins/"
        }
      ]
    },
    "name": "WordPress REST API Exploitation and Plugin Staging",
    "description": "This hunt identifies the early stages of the wp2shell attack chain (CVE-2026-63030 and CVE-2026-60137). It first scopes the environment for vulnerable WordPress versions, then correlates evidence of the specific batch API route confusion exploit with file-system staging events where the web server process drops new PHP files into plugin directories. By focusing on the web-server-to-file-drop relationship, the hunt remains durable against variations in the final shell payload."
  },
  "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": 1,
          "title": "wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution",
          "total": 2
        },
        "coverage": [
          {
            "stage": "exploit-wordpress-batch-api",
            "steps": [
              "scoping-vulnerable-assets",
              "http-batch-api-exploitation"
            ],
            "status": "covered"
          },
          {
            "stage": "malicious-plugin-staging",
            "steps": [
              "rare-plugin-file-drops"
            ],
            "status": "covered"
          },
          {
            "stage": "shell-spawn-from-web-server",
            "reason": "Covered by follow-on behavioral hunts in the series.",
            "status": "out_of_scope"
          },
          {
            "stage": "post-exploitation-discovery",
            "reason": "Covered by general Linux discovery hunts.",
            "status": "out_of_scope"
          },
          {
            "stage": "automated-self-cleanup",
            "reason": "Cleanup activity is the last stage and requires separate file-deletion logic.",
            "status": "out_of_scope"
          }
        ],
        "rationale": "An attacker is exploiting the wp2shell WordPress Core RCE chain to upload and stage a malicious plugin by abusing the unauthenticated REST batch API.",
        "blind_spots": [
          {
            "id": "missing-http-telemetry",
            "risk": "Encrypted traffic may prevent seeing the User-Agent or full URL query parameters used in the exploit chain.",
            "stage": "exploit-wordpress-batch-api",
            "question": "Were the specific batch API parameters (SQL injection payloads) visible in the request?",
            "requires": "TLS decryption at the log source (hb_http_activity)"
          },
          {
            "id": "alternate-staging-paths",
            "risk": "If the attacker avoids the plugin-staging mechanism and writes directly to other writable directories, the rare-plugin query will not see the file drop.",
            "stage": "malicious-plugin-staging",
            "question": "Did the attacker drop a webshell using INTO OUTFILE into the cache or uploads directory?",
            "requires": "Full file monitoring outside wp-content/plugins/"
          }
        ],
        "scoping_notes": "Prioritize internet-facing hosts running WordPress 6.9.x or 7.0.x. If vulnerability findings are incomplete, run the HTTP exploitation query across all systems identified as web servers.",
        "beyond_detection": "While a single rule may alert on the plugin drop, this hunt correlates the initial API exploit (network surface) with the resulting staging activity (file surface) and uses prevalence to identify the specific malicious plugin among legitimate site updates. This reduces false positives from authorized administrative plugin installs."
      }
    },
    {
      "id": "scoping-vulnerable-assets",
      "type": "query",
      "label": "Scope for vulnerable WordPress instances",
      "config": {
        "dsl": "sqlite",
        "role": "scoping",
        "source": "endpoint",
        "content": "SELECT device_uid, cve_uid, severity, affected_package_version, first_seen FROM hb_vulnerability_finding WHERE instr(',' || '{{vulnerable_cves}}' || ',', ',' || cve_uid || ',') > 0",
        "surface": "hb_vulnerability_finding",
        "description": "Identify hosts with reported vulnerabilities corresponding to the wp2shell exploit chain to prioritize the hunt.",
        "expected_signal": "A list of device UIDs running vulnerable WordPress versions. Silence means no known-vulnerable instances are recorded in the inventory."
      },
      "parents": [
        {
          "id": "hypothesis"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "scoping",
        "label": "Scope for vulnerable WordPress instances",
        "reads": [
          "affected_package_version",
          "cve_uid",
          "device_uid",
          "first_seen",
          "severity"
        ],
        "source": "hb_vulnerability_finding",
        "target": "endpoint",
        "content": "SELECT device_uid, cve_uid, severity, affected_package_version, first_seen FROM hb_vulnerability_finding WHERE instr(',' || '{{vulnerable_cves}}' || ',', ',' || cve_uid || ',') > 0",
        "silence": "not_evidence_of_absence",
        "expected": "A list of device UIDs running vulnerable WordPress versions. Silence means no known-vulnerable instances are recorded in the inventory.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "http-batch-api-exploitation",
      "type": "query",
      "label": "Detect batch API route confusion attempts",
      "config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "source": "web",
        "content": "SELECT device_hostname, url_full, user_agent, src_endpoint_ip, time FROM hb_http_activity WHERE (LOWER(url_full) LIKE '%/batch/v1%' OR LOWER(url_full) LIKE '%rest_route=/batch/v1%') AND (LOWER(user_agent) LIKE '%wp2shell%' OR LOWER(user_agent) LIKE '%curl%' OR LOWER(user_agent) LIKE '%python%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_http_activity",
        "description": "Find HTTP requests targeting the vulnerable WordPress batch endpoint, specifically looking for common PoC User-Agents or anomalous traffic patterns.",
        "expected_signal": "Requests to the batch API from unusual User-Agents. Any hit on 'wp2shell' is a high-confidence indicator of exploitation."
      },
      "parents": [
        {
          "id": "scoping-vulnerable-assets"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "label": "Detect batch API route confusion attempts",
        "reads": [
          "device_hostname",
          "src_endpoint_ip",
          "time",
          "url_full",
          "user_agent"
        ],
        "source": "hb_http_activity",
        "target": "web",
        "content": "SELECT device_hostname, url_full, user_agent, src_endpoint_ip, time FROM hb_http_activity WHERE (LOWER(url_full) LIKE '%/batch/v1%' OR LOWER(url_full) LIKE '%rest_route=/batch/v1%') AND (LOWER(user_agent) LIKE '%wp2shell%' OR LOWER(user_agent) LIKE '%curl%' OR LOWER(user_agent) LIKE '%python%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Requests to the batch API from unusual User-Agents. Any hit on 'wp2shell' is a high-confidence indicator of exploitation.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "rare-plugin-file-drops",
      "type": "query",
      "label": "Identify rare PHP files written by web servers",
      "config": {
        "dsl": "sqlite",
        "role": "baseline",
        "source": "endpoint",
        "content": "SELECT LOWER(file_path) AS plugin_path, COUNT(DISTINCT device_hostname) AS host_count, MIN(time) AS first_seen FROM hb_file_activity WHERE (LOWER(file_path) LIKE '%/wp-content/plugins/%.php' OR LOWER(file_path) LIKE '%/wp-content/uploads/%.zip') AND (LOWER(process_name) LIKE '%apache%' OR LOWER(process_name) LIKE '%httpd%' OR LOWER(process_name) LIKE '%php-fpm%') AND activity_id = 1 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY plugin_path HAVING host_count <= 2 ORDER BY host_count ASC",
        "surface": "hb_file_activity",
        "description": "Stack-count the creation of new PHP files in WordPress plugin directories by the web server process to highlight anomalous staging activity.",
        "expected_signal": "A small number of hosts showing new PHP or ZIP files dropped into WordPress content directories by the web server runtime."
      },
      "parents": [
        {
          "id": "scoping-vulnerable-assets"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "baseline",
        "label": "Identify rare PHP files written by web servers",
        "reads": [
          "activity_id",
          "device_hostname",
          "file_path",
          "process_name",
          "time"
        ],
        "source": "hb_file_activity",
        "target": "endpoint",
        "content": "SELECT LOWER(file_path) AS plugin_path, COUNT(DISTINCT device_hostname) AS host_count, MIN(time) AS first_seen FROM hb_file_activity WHERE (LOWER(file_path) LIKE '%/wp-content/plugins/%.php' OR LOWER(file_path) LIKE '%/wp-content/uploads/%.zip') AND (LOWER(process_name) LIKE '%apache%' OR LOWER(process_name) LIKE '%httpd%' OR LOWER(process_name) LIKE '%php-fpm%') AND activity_id = 1 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY plugin_path HAVING host_count <= 2 ORDER BY host_count ASC",
        "silence": "not_evidence_of_absence",
        "baseline": {
          "window": "{{lookback_days}}d",
          "compare": "first_seen"
        },
        "expected": "A small number of hosts showing new PHP or ZIP files dropped into WordPress content directories by the web server runtime.",
        "verified": "dry-run",
        "prevalence": {
          "by": "device_hostname",
          "key": [
            "file_path"
          ],
          "rare_below": 3
        },
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "triage-exploitation-evidence",
      "type": "analytic",
      "label": "Triage WordPress exploitation and staging",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint",
          "web"
        ],
        "context": [
          "http-batch-api-exploitation",
          "rare-plugin-file-drops"
        ],
        "objective": "Determine if any host shows a sequence where a REST batch request is followed by the creation of a rare PHP file in a WordPress plugin or upload path by the web server process.",
        "description": "Evaluate whether the HTTP requests and file staging events together constitute a confirmed exploitation of CVE-2026-63030.",
        "max_iterations": 4,
        "expected_signal": "A per-host verdict linking the batch API request to the subsequent file creation.",
        "success_criteria": "A verdict of malicious, suspicious, or benign per host with citations for the specific HTTP logs and file events."
      },
      "parents": [
        {
          "id": "http-batch-api-exploitation",
          "kind": "merge"
        },
        {
          "id": "rare-plugin-file-drops",
          "kind": "merge"
        }
      ]
    },
    {
      "id": "determine-response",
      "type": "checkpoint",
      "label": "Route on verdict",
      "config": {
        "fuzzy": true,
        "judge": "hunter",
        "question": "The triage-exploitation-evidence verdict is malicious for at least one host, indicating a confirmed plugin drop via the batch API.",
        "condition": "The triage-exploitation-evidence verdict is malicious for at least one host, indicating a confirmed plugin drop via the batch API.",
        "blind_spot": "missing-http-telemetry",
        "confidence": "high",
        "description": "Direct the workflow to immediate containment if the agent confirms exploitation.",
        "checkpoint_type": "mandatory"
      },
      "parents": [
        {
          "id": "triage-exploitation-evidence"
        }
      ]
    },
    {
      "id": "isolate-compromised-host",
      "type": "action",
      "label": "Isolate compromised WordPress host",
      "config": {
        "target": "endpoint",
        "description": "Prevent further exploitation, lateral movement, or data exfiltration by isolating the affected host.",
        "instructions": "Isolate the host identified in the triage verdict. Preserve the WordPress directory and web server logs for forensic analysis before remediation.",
        "action_approval": "required"
      },
      "parents": [
        {
          "id": "determine-response",
          "branch": "on_supports"
        }
      ]
    },
    {
      "id": "manual-forensic-review",
      "type": "task",
      "label": "Manual forensic review",
      "config": {
        "assignee": "analyst",
        "description": "Verify the findings and investigate post-exploitation activity such as shell execution or lateral movement.",
        "instructions": "Examine the plugin directory identified by the hunt. Check for shell spawns from the web server process (e.g., apache2 spawning sh or dash) and verify if any commands were executed by the staged PHP script. Check for evidence of SQL injection payloads in the web server access logs."
      },
      "parents": [
        {
          "id": "determine-response",
          "branch": "default"
        },
        {
          "id": "determine-response",
          "branch": "on_unavailable"
        },
        {
          "id": "isolate-compromised-host"
        }
      ]
    },
    {
      "id": "incident-close-out",
      "type": "task",
      "label": "Incident close-out",
      "config": {
        "assignee": "analyst",
        "description": "Record the hunt results and update the vulnerability inventory.",
        "instructions": "Document the hosts examined and any identified compromises. If no activity was found on vulnerable hosts, mark them for urgent patching. Update vulnerability management records to reflect the patch status of WordPress instances."
      },
      "parents": [
        {
          "id": "determine-response",
          "branch": "on_refutes"
        },
        {
          "id": "manual-forensic-review"
        }
      ]
    }
  ]
}