detect php backdoor

September 27, 2011

how to detect php backdoor ?

(Note content is from

Website security: How to find backdoor PHP shell scripts on a server

This is supplemental information for a series of articles that begins at:

Although the article below looks like my others that are intended to be understandable to a novice who is sufficiently motivated to make the attempt, this one might not realistically be in that same category. The information presented below is probably most useful to a person who already knows how to use these search programs, has experience with regular expressions, and has at least some experience running system commands on a webserver, but has not previously put all those things to use for this particular purpose. For others, this might be overly advanced.

When hackers get access to your website server, 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 occur, 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 the suspicious lines that can be generated when someone 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: – – [dd/mm/yyyy:hh:mm:ss -0700]
“GET /path/ HTTP/1.1”
200 4795 “http://website/path/” “Mozilla/5.0…”

  • is the innocently-named file containing the backdoor script.
  • Notice the “act”(action)=edit and file=.htaccess.
  • The referer (previous page visited) was also the backdoor page, which has a built-in file manager.

Nobody should be able to edit your .htaccess 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 suggests a few obvious things to search for in your log file:

Search Text Comment
htaccess Unless you write articles about .htaccess and the word is in your search-engine-friendly filename URLs, there is no reason for the word htaccess to appear in your HTTP access logs.
From the example above, and a reasonable variation.
filemanager Another word that probably won’t normally appear 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

The article linked at the top of this page has a section (currently 12b) describing how to obtain your website access logs from cPanel. Plesk is similar, and if you don’t have either of those, or something comparable, you can usually get the logs by FTP, usually from a folder outside public_html, with “logs” or “access logs” in its name.

2) Detect backdoor scripts by searching site files with grep or findstr

Backdoor scripts often need to 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

This is an attempt at a list of PHP functions that are needed by malicious scripts but 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 it uses one or more of these functions. Use your judgment while inspecting the surrounding code. On the other hand, if a header at the top of the file 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.

  • passthru
  • shell_exec
  • system
  • phpinfo
  • base64_decode
  • edoced_46esab  (base64_decode used backwards to avoid detection by string searches like this)
  • chmod
  • mkdir
  • “ (backticks with an operating system command between them)
  • fopen
  • fclose
  • readfile

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, not many shared webhosts allow their customers shell access anymore.

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 for 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 in an email. 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 is somewhat time consuming until you get used to it:

  1. Determine the default directory that crontab starts in: pwd
    The result should be something like /home/userID
  2. Get a listing of the files and folders in that directory: ls -aFlq
    Examine the listing to make sure public_html is there. It should look something like this:
    drwxr-x— 39 xxxxxxxx xxxxxxxx 4096 Jan 12 18:30 public_html/
  3. Determine your server’s version of grep: grep –version
  4. Determine which options your version of grep supports: grep –help
    If the output has a line like this, you have a newer version that supports Perl regular expressions:
    -P, –perl-regexp PATTERN is a Perl regular expression

You’re now familiar with the method of entering these commands, and 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 that it will 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 file types 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.

At least one type of file that can cause grep to hang is a “device”, which in Linux is a file. You’re not likely to encounter this situation on a shared server, but on a dedicated server it is best to avoid searching the following directories with grep: /dev/, /lib/, /media/, /proc/, /sys/. If grep tries to search a character device, it will sit waiting forever for input from the device. As far as I know, it won’t hang the server, but I also don’t know how to force it to terminate from cron.

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 -Rn “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 -RPn “(passthru|shell_exec|system|phpinfo|base64_decode|chmod|mkdir|fopen|fclose|readfile) *\(” public_html/

Grep is a flexible and powerful search program. You can also use it for the access log searches discussed in section 1 of this article.

Text search in Windows with findstr

A built-in Windows utility similar to grep is called findstr. You can get some help for it (even on your own Windows PC after opening a Command Prompt) with help findstr, or findstr /?. Findstr should be sufficient for these searches, but there is a Win32 version of grep available1. However, I don’t know if Windows shared hosting plans normally provide a mechanism for obtaining command prompt where you can run system commands. Plesk Scheduled Tasks might be one possibility.

Sample search

*.* means All files, DOS style wildcards

To search for one keyword at a time:

findstr /r /s /n /c:”passthru *(” *.*

To search for all keywords at once, with risk of false positives or a large amount of output. Notice that with this format 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

This PHP script can search your website files for the suspicious function calls listed above, as well as for other suspicious text and filenames.


  1. I got an excellent Windows version of grep at However, it’s unlikely your webhost would permit you to install it on a shared Windows server. On a dedicated server, I imagine the installation would be as straightforward as on a PC. It’s not a single .exe file, though; it has 4 associated .dll files.
  2. Here is what you don’t want to see when you visit one of your website pages. This is a screenshot of a backdoor web shell’s menu page. The page is all gray except for this menu. Menu items in Russian are: Full Information, File Manager, phpinfo(), Run a PHP command, Execute Linux Command. Screenshots of the more common and complex shells c99 and r57 can be easily found with a search engine image search. The PHP code in this web shell fails to validate incoming GET and POST data before using it, so it has security vulnerabilities. Oh my!

Names of some common backdoor web shells: c99 or any variation such as c99madshell, r57.php or any variation, gifimg.php.