Skip to content

Latest commit

 

History

History
148 lines (127 loc) · 10.1 KB

File metadata and controls

148 lines (127 loc) · 10.1 KB

WordPress Malware Families & 2026 Threat Landscape

Distilled from the top WordPress security sources (Wordfence, Sucuri, Patchstack, MalCare, BlogVault, Jetpack, real 2026 incident write-ups). This is the domain knowledge that makes the skill an expert: what the families are, how each hides, and the exact signal that catches it. Pair with scripts/signatures.json.

The 2026 landscape (hard numbers — use for prioritization & positioning)

  • 91% of new WordPress vulnerabilities are in plugins; ~3% themes; core negligible. (Source: Patchstack State of WordPress Security 2026.)
  • 11,334 new vulns in 2025 (+42% YoY); 17% high-severity mass-exploitation risk (+113% YoY).
  • Median time to mass exploitation: 5 hours; ~50% of high-impact vulns exploited within 24h; 46% are unpatched at disclosure. → The window is tiny; version cross-check matters.
  • Premium/freemium components: 29% of reports, 76% exploitable, 3× more known-exploited vulns than free. → Nulled/premium plugins are a top vector; signature-based scans generally can't see inside them.
  • Top exploited types: Broken Access Control, unauth Stored XSS, Authorization Bypass, Arbitrary File Upload, Privilege Escalation, PHP Object Injection → RCE.
  • Traditional WAFs blocked only ~12% of WordPress-specific attacks. → A WAF is not a scanner.
  • ~49% of compromised sites contain at least one backdoor; cleaned files often reinfect within hours (memory-resident/persistent creators). → Always re-scan 24–48h post-clean.

The families

1. SEO-spam cloaking (Japanese keyword / pharma / gambling)

  • Mechanism: PHP router or fake plugin serves spam only to crawlers (UA contains Googlebot/Bingbot) or mobile; clean content to everyone else and to scanners.
  • Hides in: web-root shadow folders, a fake plugin named after the victim domain (wp-content/plugins/example-com/example-com.php), .htaccess, wp_options, injected posts.
  • Signals: cloaking_router, seo_spam_keywords, payload_hosts, sitemap_injection; Layer 1 bot-vs-browser diff is the definitive catch. Rogue sitemap*.xml with spam URLs; robots.txt pointing at foreign sitemaps; Japanese charset in posts (post_content REGEXP '[ぁ-んァ-ヶ]').
  • Real 2026: the "domain-mimic" SEO-spam plugin fetching instructions from metainfo.jpg, C2 base64-encoded (mag1cw0rld[.]com).

2. Backdoors & web-shells

  • Mechanism: persistent remote access. From full file-managers (GYOKKA, b374k, WSO, c99, alfa, IndoXploit) to 500-byte auto-login files (wp_set_auth_cookie on the first admin).
  • Hides in: wp-content/uploads, inactive plugins, theme folders, wp-admin/maint/, disguised as .ico.php/.png.php/hidden .*.php, or core-filename typosquats (wp-comments-posts.php vs core's singular wp-comments-post.php; the wp-vcd family).
  • Signals: shells, auto_login_backdoor, cookie_auth_markers, double_extension_files, core_filename_typosquat. Single indicator is enough — don't require two.

3. Persistent admin creators / reinfection

  • Mechanism: code on every load recreates a rogue admin or re-drops the payload → malware "returns" after you delete the user. Memory-resident variants (e.g. Lock360) reinfect cleaned files.
  • Hides in: theme functions.php, mu-plugins, wp_options autoloaded values, a cron hook.
  • Signals: persistent_admin_creator, malicious_cron; check mu-plugins and autoloaded options. Re-scan after 24–48h to confirm it didn't respawn.

4. wp-config.php injection

  • Mechanism: appends executable code after require_once ABSPATH . 'wp-settings.php'; — survives wp core download --force because wp-config is preserved.
  • Signals: wp_config_injection. Read wp-config tail specifically; nothing executable belongs after the wp-settings require.

5. Malicious redirects

  • Mechanism: conditional redirect (by referrer, first-visit, mobile, geo, crawler) to spam/ casino/phishing. Owner logged-in often exempted, so the owner "sees nothing."
  • Hides in: .htaccess (301/302), wp_options siteurl/home, theme header.php/ functions.php, obfuscated JS in header/footer, injected post <script>.
  • Signals: htaccess_injection, db_injection (siteurl/home hijack, foreign <script>/iframe), obfuscation. Trace the redirect chain as a crawler AND a mobile UA.

6. Supply-chain plugin backdoors (the 2026 escalation)

  • Mechanism: attacker buys/compromises a popular plugin, ships a backdoor via a trusted update. Example (Essential Plugin / Flippa, ~400k installs): unauth REST route /wp-json/wpos/v1/analytics with permission_callback => '__return_true'PHP Object Injection via @unserialize() → gadget chain writes ~6KB into wp-config.php and drops wp-comments-posts.phpGooglebot cloaking for gambling/crypto/pharma. 8-month dormancy, then a ~7h activation window.
  • Signals: rogue_rest_route, object_injection, wp_config_injection, core_filename_typosquat. Cross-check installed plugin versions against the Wordfence feed; watch access logs for POSTs to odd /wp-json/* routes.

7. Credit-card skimmers (Magecart)

  • Mechanism: JS on WooCommerce checkout captures card/CVV fields and exfiltrates to a foreign host. Often injected via DB (wp_options, post content) or a compromised payment plugin.
  • Signals: card_skimmer. Flag only when captured data goes to a host that is not the site's own payment processor.

8. Cryptominers

  • Mechanism: server-side PHP miner or browser JS (Coinhive-style) hijacks CPU.
  • Signals: cryptominer; corroborate with sustained 90–100% CPU without a traffic spike.

Advanced evasion (community-sourced from real 2026 cleanups)

These are techniques practitioners on r/ProWordPress / r/Wordpress reported as hard to detect — several got past the scanners and host teams involved before being found manually. Make sure the skill catches each.

  • Stream-wrapper + image payload. Payload is a compressed PHP file hidden in screenshot.webp, executed via compress.bzip2://screenshot.webp through load_template(). On disk it's an "image," so file scanners see nothing; the loader is cloaked as a fake wpengine_update() function. In the reported case it went unresolved until a developer decompressed the webp and found it. Signals: php_stream_wrapper, fake_core_function_loader. Decode any "image" that a PHP file references or includes.
  • DB-rebuilt loader. The malicious function builds its target path from wp_options (get_option('wpengine_' . get_stylesheet() . '_data')['screenshot','webp','bzip2','compress']) and reconstructs itself after you delete files — persistence lives in the DB, execution in an image. Clean the option AND the file AND flush cache, or it respawns.
  • Query-string (?g=) cloaking. 900k spam URLs generated purely from ?g= params, served only to Googlebot; nothing in posts, sitemap, or source; a garbage ?g=x URL renders spam to a crawler. Paired with a .htaccess DirectoryIndex wp-ingat.php index.php hijack that runs a malicious script before WordPress. Signals: Layer 1 query-string probe as Googlebot + htaccess_injection (DirectoryIndex).
  • Server-level / above-WordPress persistence. Reinfects wp-config.php every few hours; a clean WordPress audit shows nothing. Real case: a webmail log file turned into a root backdoor; another via ~/.bashrc, system cron, or mail services. If it keeps coming back after a clean WP pass, the persistence is outside WordPress — check .bashrc, system crontab, mail logs, and service-startup scripts (see edge-cases.md).
  • Practitioner-validated workflow (matches this skill's Layers 11–12 + hardening): Patchstack the vulns → get the payload's file-creation timestamp → cross-reference access logs (mind the FS-vs-log timezone difference) → force-logout everyone + rotate all passwords, SSH keys, FTP → fix permissions → clean uploads → update everything → install an activity-log plugin for early warning.

Cross-cutting detection truths (why surface scanners fail)

  • Scan MODIFIED core/plugin files, not just added ones. Attackers inject into legitimate files; deletion-only remediation misses it. Use checksum verify (Layer 3/4), not "new file" heuristics alone.
  • Remote/surface scanners can't see: file-timestamp manipulation, server-side-only payloads, database infections, cloaked content. That's four whole families invisible to a browser-style scan.
  • Signature-only scanners miss: premium/nulled plugins (no signatures), novel/obfuscated code, and DB malware — and produce false positives on custom code. The verify gate (read-in-context) is what gives low false positives without a signature monopoly.
  • Timing beats signatures: with a 5-hour median to mass exploitation, the Wordfence vuln cross-check (is an installed version in a known-exploited range?) often finds the door faster than any file scan finds the payload.

Hardening (researched consensus — apply after cleanup)

wp-config.php: DISALLOW_FILE_EDIT, DISALLOW_FILE_MODS (during lockdown), FORCE_SSL_ADMIN, disable XML-RPC if unused, move/chmod 400 wp-config, rotate salts. Perms: dirs 755, files 644, wp-config 400/440, no 777. DB user limited to SELECT/INSERT/UPDATE/DELETE. Enforce 2FA (stolen creds are a top vector). Rename the admin user. Block direct PHP execution in wp-content/uploads (nginx location ~* /uploads/.*\.php$ { deny all; } or .htaccess). Update or remove every component flagged by the Wordfence cross-check within the 24h window. Monitor logs + re-scan 24–48h for reinfection.

Sources

Patchstack State of WordPress Security 2026 · Sucuri hacked-site cleanup guides · Wordfence Intelligence + learning center · MalCare / BlogVault malware & scanner guides · Jetpack redirect-spam guide · Malcure Japanese-keyword-hack guide · 2026 Essential Plugin supply-chain write-up · securityonline domain-mimic SEO-spam analysis.