name: 'WordPress wp2shell Post-Exploitation Persistence and Enumeration Activity Analytic'
signatureid: WAF-APP02-RUN
category: 'Persistence'
threatname: 'Server Software Component: Web Shell'
functionality: 'Web Proxy'
description: |
Detects the post-exploitation web activity Wiz Research observed following successful exploitation of
the wp2shell WordPress Core RCE chain (CVE-2026-63030 + CVE-2026-60137), disclosed 2026-07-17 and
confirmed exploited in the wild from 2026-07-18. This rule covers what multiple
actors did next on compromised, cloud-self-hosted WordPress instances:
1. Malicious plugin upload for persistence — attackers accessed
/wp-admin/plugin-install.php?tab=upload and POSTed to /wp-admin/update.php?action=upload-plugin to
install backdoors. Observed payloads included a minimal one-liner PHP webshell
(eval($_POST['<param>'] ?? 'http_response_code(404);'), returning 404 as an evasion technique), a
~150KB full-featured webshell masquerading as "CMSmap" — note the genuine Dionach CMSmap project
is a standalone Python CMS scanner, NOT a WordPress plugin, so a plugin directory bearing that
name is itself the finding (GUI, password auth, file management, database access, port scanning,
batch code injection, and MySQL UDF privilege-escalation modules; obfuscated via hex-encoded
string concatenation and
eval(gzuncompress(base64_decode(...)))), and a plugin registering a custom REST route
(/morning/v1/<redacted>) with permission_callback => '__return_true' that passthru()s a
base64-decoded command from the 'c' parameter and returns the output as JSON.
2. User enumeration — requests to /wp-json/wp/v2/users?context=edit to harvest administrator
usernames and email addresses.
3. Local file inclusion — admin-ajax.php?template=../../../wp-config, targeting database credentials
and authentication keys for exfiltration.
4. Authenticated admin panel access — /wp-admin/ returning HTTP 200, indicating a successful session.
Wiz also observed high-volume opportunistic mass scanning without follow-on activity, and had not
identified lateral movement or data exfiltration at time of publication. Note that plugin upload,
user listing, and /wp-admin/ access are all legitimate administrative actions in isolation.
reference:
- https://www.wiz.io/blog/wp2shell-cve-2026-63030-cve-2026-60137
- https://hadrian.io/blog/wp2shell-a-pre-authentication-rce-in-wordpress-cores-rest-batch-api
- https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core/
- https://www.tenable.com/blog/wp2shell-cve-2026-63030-cve-2026-60137-frequently-asked-questions-about-remote-code-execution
- https://thehackernews.com/2026/07/wordpress-wp2shell-exploitation-grows.html
- https://github.com/dionach/CMSmap
labels:
- attack.persistence
- attack.t1505.003
- attack.t1505
- attack.discovery
- attack.t1087
- attack.credential_access
- attack.t1552.001
- attack.initial_access
- attack.t1190
- cve.2026.63030
- cve.2026.60137
- wp2shell
- WordPress
- Web Shell
- CMSmap
logsource:
product: Web Application Firewall
category: web server
detection:
selection_plugin_upload:
RequestUrl|contains:
- '/wp-admin/update.php?action=upload-plugin'
- '/wp-admin/plugin-install.php?tab=upload'
selection_user_enumeration:
RequestUrl|contains:
- '/wp-json/wp/v2/users?context=edit'
- 'rest_route=/wp/v2/users'
- 'rest_route=%2Fwp%2Fv2%2Fusers'
selection_lfi_wpconfig:
RequestUrl|contains|all:
- 'admin-ajax.php'
- 'template='
- 'wp-config'
selection_webshell_rest_route:
RequestUrl|contains:
- '/wp-json/morning/v1/'
- 'rest_route=/morning/v1'
- 'rest_route=%2Fmorning%2Fv1'
condition: selection_plugin_upload or selection_user_enumeration or selection_lfi_wpconfig or selection_webshell_rest_route
violator: RTActivityAccount
verbose_info: 'WordPress post-exploitation activity consistent with wp2shell follow-on tradecraft was observed from ${sourceaddress!"UNKNOWN"} to ${domainname!"UNKNOWN"} (${requesturl!"UNKNOWN"}, status ${statuscode!"UNKNOWN"}).'
violation_summary:
grouping_attribute: 'devicehostname'
level2_attribute: 'domainname'
level2_metadata_attributes:
- requesturl
- statuscode
- sourceaddress
- requestclientapplicationTECHNICAL DETAILS
Post-exploitation behaviors and webshell descriptions are taken from Wiz Research's 2026-07-20
in-the-wild exploitation writeup (Shahar Dorfman, Gili Tikochinski).
SELECTION-LEVEL FP GUIDANCE
---------------------------
selection_plugin_upload:
MODERATE-TO-HIGH FP RISK. Legitimate administrators install plugins this way. The signal is source
and timing, not the path itself. Recommended triage: correlate against SourceAddress (expected admin
ranges / VPN egress) hit on the same host within the preceding hours. In environments where plugin installation is change-controlled or disabled
(DISALLOW_FILE_MODS), FP risk drops to near zero and this becomes the single highest-value selector
in this rule — persistence via malicious plugin was the primary observed objective.
selection_user_enumeration:
MODERATE FP RISK. ?context=edit requires an authenticated session with list_users capability, so
hits from unauthenticated or unexpected sources are strongly suspicious. The broader
rest_route=/wp/v2/users patterns will also match benign unauthenticated user-listing requests, which
are extremely common background internet noise against WordPress. Consider tightening to the
context=edit form only if noise is excessive.
selection_lfi_wpconfig:
LOW FP RISK. Requires 'admin-ajax.php' AND both 'template=' and 'wp-config' in the same URL. There
is no legitimate reason for a template parameter to reference wp-config. Any hit warrants immediate
credential-rotation assessment: wp-config.php holds DB credentials and the WordPress auth salts/keys.
Note this pattern is a generic vulnerable-plugin LFI primitive that predates wp2shell and may
indicate an unrelated plugin vulnerability — either way it is worth investigating.
selection_webshell_rest_route:
NEAR-ZERO FP, but PERISHABLE. 'morning/v1' is the REST namespace used by one specific malicious
plugin Wiz observed; the route name after the namespace was redacted in their publication, so this
selector matches on namespace only. A different operator, or the same operator in a later wave, will
use a different namespace. Retain for the specific cluster, but do not treat its absence as evidence
of no webshell.
/wp-admin/ ACCESS — DELIBERATELY NOT IMPLEMENTED
------------------------------------------------
Wiz listed "attackers accessed /wp-admin/ and received HTTP 200" as an observed post-exploitation
behavior. A selector for that would match essentially every legitimate administrator session in the
environment and was omitted as unmanageably noisy for an alerting rule. Recommend covering it instead
as a hunting query: /wp-admin/ 200-responses from source addresses with no prior successful
/wp-login.php POST, or from geographies/ASNs inconsistent with the admin population.
KNOWN IOCs (Wiz Research, 2026-07-20) — SHA-1 hashes of deployed PHP webshells:
2a1410d8e2a8337ac2171cedea8c0fdc47c647a0
58eca847e9eae9e6b08cc211f1559817b71bc4cc
ebea44890f434d5d67ede22009a3f4bb5cac33f8
d9a220c8039f1c4d72cae7ccb8b3a33dec8815be
e9756e2338f84746007235e4cab7a70d5b3ca47f
Policy building walkthrough can be found in this previous post:
