This guide is an attempt to identify and remove the most common artifacts and persistence mechanisms seen in the wild in compromised wordpress/php servers.
Looking for suspicious files
A good starting point would be to scan the server’s file system for files that could be used as backdoors/webshells:
Find recently modified files
Checking the recently modified files is a good way to start tracking the activities from attackers. For example, to find all the files modified in the last 5 days in the root filesystem:
1
find / -mtime -5
To refine the search, we can look for php files or scripts added by the attacker in the web directory:
1
find /var/www -type f -name "*.php" -mtime -7 -print
Hidden files in web directories
The malicious files could also be hidden files:
1
find /var/www -type f -name ".*.php" -print
Files in globally written directories
Malicious files are usually stored in directories that are globally writable, list their contents (including hidden files) to check for suspicious artifacts:
1
ls -la /tmp /var/tmp /dev/shm
Searching for malicious code or suspicious functions with grep
grep is the most valuable tool to find code functions frequently used in malware, these functions can allow arbitrary code execution. We can do a recursive grep search with the following command:
1
grep -RniE "(eval|base64_decode|shell_exec|exec|system)\s*\(" /var/www
Many webshells are heavily obfuscated (they pass a long string to some eval/decode function). You can search for eval( coupled with base64_decode as a common indicator:
1
grep -Rni "eval(base64_decode" /var/www
PHP code in non-php files
PHP code in non-PHP files is another clear sign of evil activity, attackers can hide PHP code in files with unexpected extensions (like images). For instance, they might upload a file named picture.jpg that actually contains PHP code and is interpreted as such by the web application. To find this, look in the uploads directory for the <?php tag:
1
find wp-content/uploads -type f -iname '*.jpg' -exec grep -Il "<?php" {} \;
Hidden iframes or scripts
If the attack involved defacement or code injection, search for <iframe> tags or <script> tags in the php files:
1
grep -Rni "<iframe" /var/www
Web Server Logs (access & error logs)
Logs are tipically found in /var/log/apache2/ or /var/log/httpd/ for apache, and in /var/log/nginx for nginx. These logs record all requests processed by the web server (apache, nginx) and any errors encountered.
Access logs
Look for the following behaviours in the logs:
- Direct webshell access: search requests to known or suspected webshell file names or requests with command injection patterns in the parameters, e.g.:
1
GET /uploads/shell.php?cmd=id HTTP/1.1
grep command to search for those patterns:
1
grep -iE '\.php.*(cmd=|command=|exec=|query)' /var/log/nginx/access.log
- Exploit attempts: signatures of common exploits, e.g., SQL injection attempts like
' OR '1'='1, directory traversal attempts like../../.., LFI/RFI attempts that include external URLs or sensitive file paths like/etc/passwd.
Example grep command for traversal patterns:
1
grep -iE '(\.\.\/|\.\.%2F)' /var/log/nginx/access.log
- Vulnerability Scanning: Large numbers of requests generating 404s, often from a single IP address, indicate scanning activity. Example of awk to count 404s per IP
1
grep " 404 " access.log | awk '{print $1}' | sort | uniq -c | sort -nr
Error logs
Look for the following:
- PHP errors, warnings and fatal errors related to suspicious file paths or functions
- Errors that could indicate failed exploit attempts (e.g., permission denied errors when trying to access restricted files)
- Database connection errors or other application-level errors that correlate with suspicious log entries
System-level configuration checks
Server configuration files are commonly modified by attackers to establish persistence or facilitate their attackes. The following configuration files should be inspected
Auditing cron jobs
Check /etc/crontab and any files in /etc/cron.d/ for scripts and binaries that look suspicious. You can check all users crontabs by running the following command as root (or using sudo):
1
for user in $(cut -f1 -d: /etc/passwd); do echo "Cron for $user:"; crontab -u $user -l; done
Inspecting system services (systemd, init.d)
Look for systemd services that execute suspicious binaries or scripts
1
cat /etc/systemd/system/*service | grep Exec
For older systems, inspect scripts in /etc/init.d and symbolic links in /etc/rc*.d/.
Reviewing php.ini .user.ini, .htaccess, and web server configurations
Use disable_functions = exec, system, shell_exec in the php.ini file, so that the exec(), system(), and shell_exec() functions will be disabled, and attempts to call them within PHP scripts will result in a fatal error. 1
.htaccess is another heavily abused file by attackers. Changes to this file can redirect site visitors to a malicious site. Look for suspicious RewriteRule directives. For example:
1
2
3
4
5
6
7
8
9
RewriteEngine On
RewriteCond %{HTTP_REFERER} .*google.* [OR]
RewriteCond %{HTTP_REFERER} .*ask.* [OR]
RewriteCond %{HTTP_REFERER} .*yahoo.* [OR]
RewriteCond %{HTTP_REFERER} .*baidu.* [OR]
..
RewriteCond %{HTTP_REFERER} .*linkedin.* [OR]
RewriteCond %{HTTP_REFERER} .*flickr.*
RewriteRule ^(.*)$ hxxp://verybadwebsite[.]lol/in.cgi?3 [R=301,L]
That script will check the referrer from users visiting the website from one of those search engines, and proceed to redirect them to a page with malware. You can remove a .htaccess file like that and wordpress will recreate a basic one.
Delivery vectors (how webshells get in)
- Vulnerable file upload forms: web applications that allow users to upload files (e,g,, images, documents) but fail to properly validate the file type.
- Software vulnerabilities: unpatched vulnerabilities in the web application itself (wordpress, plugins, themes) or the underlying server software (apache, nginx) are common entry points. Exploiting those vulnerabilities might allow remote code execution or provide a allow the upload of an arbitrary file (e.g., a webshell).
- Local File Inclusion (LFI) / Remote File Inclusion (RFI): if a web application dynamically includes files based on user input without proper sanitization, attacker can exploit this. LFI allows including files already present on the server, while RFI allows including files from a remote URL. Both can be used to execute malicious code.
- SQL Injection (SQLi): under some conditions, SQL injection vulnerabilities allow not only access to database information but also writing files to the server’s file system, allowing the attacker to create and execute webshells.
In the next part, I’m going to cover how to get rid of the malicious files (without breaking wordpress) and how to harden the system to prevent issues in the future.
Sources
https://dfir.ch/posts/php_dangerous_functions_and_webshell/ ↩