This article is part of the WordPress Forensics series — practical guides for WordPress security, recovery, and migration.
Introduction
Security scanners catch the obvious malware. But sophisticated attackers know what scanners look for, and they design their code to evade detection. This guide teaches you manual forensics techniques — how to find what the automated tools miss.
Why Scanners Fail
- Signature-based detection — Only finds known malware patterns
- Obfuscation — Attackers encode malicious code to avoid signatures
- Legitimate-looking code — Malware hidden in normal functions
- Database infections — Many scanners only check files
- Time-delayed execution — Code that only runs under certain conditions
Setting Up Your Forensics Environment
Tools You Need
- SSH access to the server
- Text editor with regex support (VS Code, Sublime)
- phpMyAdmin or command-line MySQL access
- Clean WordPress installation for comparison
- File integrity monitoring data (if available)
Create a Forensics Snapshot
- Download complete site files to local machine
- Export full database
- Record current file timestamps
- Note server access logs location
File-Based Malware Hunting
Suspicious File Patterns
Search for these in your wp-content directory:
- PHP files in uploads directory
- Files with random names (abc123.php, x.php)
- Files with recent modification dates you did not make
- Hidden files (.file.php)
- Files with multiple extensions (image.jpg.php)
Malicious Code Signatures
Search file contents for:
eval(combined withbase64_decodepreg_replacewith/emodifierassert(with string parametercreate_function(call_user_func(with dynamic function name$_GET,$_POST,$_REQUESTpassed to eval/systemshell_exec,passthru,system,execfile_put_contentswith user input- Heavily encoded strings (gzinflate, str_rot13, base64)
Finding Hidden Backdoors
Common backdoor locations:
- wp-includes/class-wp-*.php (fake core files)
- wp-content/themes/theme-name/functions.php
- wp-content/plugins/plugin-name/plugin-name.php
- wp-config.php (injected at top or bottom)
- .htaccess (rewrite rules to malicious scripts)
- index.php files in various directories
Database Malware Hunting
Check wp_options
SELECT option_name, option_value FROM wp_options
WHERE option_value LIKE '%eval%'
OR option_value LIKE '%base64%'
OR option_value LIKE '%script%';
Check Post Content
SELECT ID, post_title FROM wp_posts
WHERE post_content LIKE '%<script%'
OR post_content LIKE '%javascript:%'
OR post_content LIKE '%onclick=%';
Check User Meta
SELECT * FROM wp_usermeta
WHERE meta_value LIKE '%eval%'
OR meta_value LIKE '%base64%';
Rogue Admin Accounts
SELECT u.ID, u.user_login, u.user_email, u.user_registered
FROM wp_users u
JOIN wp_usermeta m ON u.ID = m.user_id
WHERE m.meta_key = 'wp_capabilities'
AND m.meta_value LIKE '%administrator%';
Log Analysis
Access Log Patterns
Look for:
- POST requests to unusual PHP files
- Requests with base64 encoded parameters
- Multiple failed login attempts
- Requests to wp-includes or wp-admin from unusual IPs
- User-agent strings with SQL injection attempts
Error Log Analysis
PHP errors often reveal malware:
- Syntax errors in files you did not modify
- Failed require/include of non-existent files
- Permission denied errors from unusual locations
Core File Integrity
Compare Against Clean Installation
- Download fresh WordPress of same version
- Compare wp-includes and wp-admin directories
- Any modified or additional files are suspicious
WordPress Checksums
wp core verify-checksums
This WP-CLI command compares your core files against official checksums.
Timeline Analysis
- Identify when infection likely occurred (file timestamps, logs)
- Correlate with any changes made (plugin installs, theme changes)
- Check if backups from before that date exist
- Review what access was granted during that period
Documentation
For every finding, document:
- File path or database location
- Malicious code snippet
- When it was likely added
- What it does (if you can determine)
- How it was likely injected
Conclusion
Manual forensics is time-consuming but necessary. Scanners are a starting point, not the final word. Learn to think like an attacker — where would you hide malicious code if you wanted it to survive a scanner? That is where you will find what the tools missed.