25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more...
Website security: How to find PHP backdoor shell scripts on a server
When hackers get access to your website, they sometimes install a backdoor shell script designed to allow them to regain entry even after you've cleaned up the site, repaired the original security hole that allowed the hack to be successful, otherwise improved site security, and even installed measures to try to lock the hackers out.
A backdoor script can be called from a browser like any other web page. It gives its user a web page interface where they can download and upload, view or modify files, create directories, and otherwise manage the site using PHP's ability to read and write files and pass operating system commands through to the operating system.
Backdoors can be difficult to find because they are usually hidden in files that are already part of the site or uploaded as new files with innocent looking names, often in a directory with many files in it.
1) Detect backdoor scripts by searching website access logs
One way to find these scripts is by searching website access logs for suspicious entries generated when the hacker uses the scripts to modify site files.
Here is a good example, from an Apache HTTP log, of a backdoor script in actual use by a hacker, to edit the /public_html/.htaccess file:
xxx.xxx.xxx.xxx - - [dd/mm/yyyy:hh:mm:ss -0700]
Nobody should be able to edit your .htaccess file from a web page! A log line like this is a huge warning flag, and points directly to the file where the backdoor script is hidden.
The above example suggests a few obvious things to search for in your log file:
If you use legitimate web-interface editors like CKEditor or TinyMCE, they might conceivably produce log lines like this when you edit files yourself, but the pages being called as seen in your log file should be recognizable as scripts belonging to those editors, not weird names like footer.inc.php.
The website security article linked at the top of this page has a section (12b) that describes how to obtain your website access logs.
2) Detect backdoor scripts by searching site files with grep or findstr
Backdoor scripts often use PHP commands that most legitimate scripts don't, so you can search the files in your site for those commands. There are search utility programs you can use for finding text in files. The two described below are ones that you run from a command line (prompt), not graphical GUI programs.
Suspicious PHP code to search for
Here is a list of some PHP functions used by malicious scripts and less commonly used by legitimate ones, but false positives are certainly a possibility, especially for the last three in the list. Don't delete a script or a file just because you find one or more of these functions in it. Use your judgment while inspecting the surrounding code. On the other hand, if a header at the top of the script says it's a "web shell" written by a hacking team (some of them do say that), you can be reasonably certain you don't want that script in your site.
Text search in Linux with grep
On a Linux server, the grep program is already installed as part of the operating system. The only problem is figuring out how to launch it.
If you have command line access to your server (SSH), there's no problem. You can run it from the command line and have the results displayed to you. However, for security reasons, most shared webhosts do not give their customers shell access.
In that case, the solution may be to use crontab to schedule and run your command. Crontab is allowed by most webhosts and is provided in cPanel as Cron Jobs and in Plesk as Scheduled Tasks. Everything that would normally be displayed to you in your terminal window (the output from your command and any error messages) is sent to you by email instead. The procedure for setting up the cron job is the same as described here except that in Step 4 you enter your grep command instead of the one described in that article.
Old versions of grep have limited capabilities. Newer ones allow the more useful PCRE Perl regular expressions and other options. Before doing searches, we need to discover what capabilities you have available, and some other information about your server.
Run these test commands either from a shell command line or by the Cron Job method, whichever you discovered you could use. You'll probably find that you can only enter one command in each cron job you create, so this procedure feels clunky until you get used to it:
You're now familiar with the method of entering these commands, and you have information that will help you make judgment decisions in the next steps, such as whether you can use the more complex regular expressions or must use the simple ones.
We're going to restrict the searches to the public_html folder and everything inside it. When you got your directory listing in Step 2 above, you probably saw that there are many files and folders outside public_html. It's not impossible that malicious code might have been placed there, but we're going to ignore them for these automated global searches.
One reason is to avoid grep searching all your stored emails, website access logs, and other potentially massive files that could take a lot of time and generate many false positives.
The other reason is that there are some types of files that can cause grep to stop searching but not quit running, leaving it in basically a hung state. When you're running it from cron, you aren't able to type Control-C to make it stop. For now, we'll try to make this situation as unlikely as possible by restricting the search to the files that are actually part of your website.
We'll also use the grep -Dskip (or --devices=skip) option, which tells grep not to process "device" files, one of the types of files that can cause grep to hang.
On a dedicated server, it is best to avoid searching the following directories with grep: /dev/, /lib/, /media/, /proc/, /sys/. On a shared server, you don't normally have access to those.
One notable exception to ignoring files outside public HTML is that if you see an .htaccess file in the same folder where public_html is (that is, outside public_html), you should examine it manually for malicious code. It's a text file.
Sample text searches for suspicious PHP code
This simple syntax should work with older grep versions. Do the search once for each of the suggested PHP keywords listed above. To understand the options used in the lines below, refer to the Help text you obtained in a preliminary step above. The space-asterisk combination in the regular expression allows for zero or more spaces between the end of the command and the opening parenthesis, two different styles of PHP coding:
grep -RnDskip "passthru *(" public_html/
Your result email will contain a list of the files where matching lines were found, the line numbers where the matches occurred, and the text of the lines that matched.
If your grep Help text showed that the -P flag (Perl regular expressions) is available, you can combine all the searches into one command like this, although it could generate a multi-megabyte result email if it turns out that any of the functions are used extensively by many of your legitimate scripts (false positives):
grep -RPnDskip "(passthru|shell_exec|system|phpinfo|base64_decode|chmod|mkdir|fopen|fclose|readfile) *\(" public_html/
Grep is a powerful and flexible search program that is well worth taking some time to become acquainted with. You can also use it for searching your access logs as discussed in section 1 of this article. If you'll be doing that search on your local PC and it uses Windows, see Note 1, below.
Text search in Windows with findstr
A built-in Windows text search utility similar to grep is called findstr. It should exist on any Windows computer, whether it's your local PC or your remote Windows server. You can get help for it (such as on your Windows PC after opening a Command Prompt) with the command: help findstr, or findstr /?.
I am not familiar enough with Windows shared hosting plans to know if they usually provide SSH (I doubt it) or some other way to run system commands like findstr. Plesk Scheduled Tasks is probably the best first place to look for that capability.
*.* means All files, DOS-style wildcards.
Use this form of the command to search for one keyword at a time:
findstr /r /s /n /c:"passthru *(" *.*
Use this form of the command to search for all keywords at once, with a risk of false positives or a large amount of output. It appears that when using this form you can't allow for any spaces between the command and the parenthesis. I added a parenthesis to system because it's such a common word:
findstr /r /s /n "passthru shell_exec system( phpinfo base64_decode chmod mkdir fopen fclose readfile" *.*
3) Detect backdoor scripts by searching site files with a PHP script
As an alternative to the above searches, this PHP script searches your website files for the suspicious function calls listed above, searches for other suspicious text snippets, can report files modified between two date/times, and can be modified to perform other actions, as well.
Questions, comments, reports of experiences, and suggestions of additional text strings or filenames to search for are welcome in the discussion forum.
Copyright ©2012 Steven Whitney. Last modified Sun 07/29/2012 10:56:59 -0700.