MIKESTOWE.COM

Just another php, religion, and politics weblog

PHP Malicious Code Scanner

OS Commerce, WordPress, Joomla, Drupal, and custom built sites have all been hacked by the “wonderful” <?php @eval(base64_decode($_GET[q])); ?> hack.  By slyly uploading a single php file to your server, these hackers gain the ability to push any code, view any source, and retrieve any data.  And unfortunately, as hard as we try to prevent such hacks, as long as you use open source code, or for that manner any code, it’s more of a question of when, rather than if.

Thankfully, we as programmers have the ability to fight back, matching the hackers ingenius with innovative techniques of our own.  One such way to do this is to use a PHP file in conjunction with a Cron Job to locate this malicious backdoor code.  Enter PHP Malicious Code Scanner.

The PHP Malicious Code Scanner was designed specifically for the eval(base64_decode(‘…’)) hack, and quickly scans all files and subdirectories in its parent folder.  If it doesn’t locate any malicious code, no worries.  But if it does, it quickly sends an email detailing the specific file locations where the malicious, or just downright dangerous code is located.

Special thanks to Er. Rochak Chauhan (http://www.rochakchauhan.com/), as this was based on his idea.

Installing PHP Malicious Code Scanner

PHP Malicious Code Scanner can be installed on any server running PHP 5.

To install PHP Malicious Code Scanner:

  1. Download the source and place it in the folder you would like to scan (remember it will scan all subdirectories and files)
  2. Make sure you change [email protected] to your email
  3. Recommended: Setup a Cron Job to run the script automatically – Help

Bugs

  • No known bugs at this time

Download:

http://github.com/mikestowe/Malicious-Code-Scanner

Facebook Twitter Linkedin Digg Reddit Stumbleupon Tumblr Posterous Email Snailmail
Share

37 Responses to “PHP Malicious Code Scanner”

  • Randy says:

    Can I run it on the live site or do I need to download the site first and then run the script on the local copy?

    Do I HAVE to run it as a Cron job? Can we just run it?

    What is the purpose of running it as a Cron job? Is it to run it daily or something?

    • mike says:

      Hey Randy,
      The file can be uploaded to the live site and then either accessed directly or via a cron job (just for convenience). The reason for the cron job is that you can set it up to scan say weekly and then really forget about it. If something is detected it sends you an email, bringing it immediately to your attention.

      This is especially helpful if you have multiple sites and may not be able to test them all, or may not want to have to manually test them all on a regular basis.

      Keep in mind that I always recommend a backup before uploading new scripts as this one will read your files… but should not impact them in any way.

      Thanks!

  • Thanks Mike !

    I am glad that you like my code and it was of some use to someone :)

    Appreciate it !!

    Let me know if you face any issue or have some suggestion.

    Regards,
    Rochak Chauhan

    Founder and Director,
    Jumbo Labs Solutions (P) Limited

  • Riyaz says:

    Hi,

    Thanks for wonderful script. I got error when i browsed it through browser

    Warning: in_array() [function.in-array]: Wrong datatype for second argument in /phpscan.php on line 37

  • Joseph says:

    Hi Mike,
    I love the idea of the script. However, when I run it, I get a php warning.
    Warning: in_array() [function.in-array]: Wrong datatype for second argument in /home/eaglemar/public_html/cleanup4chris.php on line 37

    Any ideas?

  • Roderick says:

    When I run it directly I get an error that says segmentation fault, what does that mean?

    • mike says:

      What OS are you using? In Ubuntu there is a bug that can cause this error. I would try making sure you have the latest version of PHP installed with all the patches.

  • Montster says:

    Kind of a newbie here. How do I get it to scan, once I’ve put it in the folder?

    • mike says:

      You can either go to the file directly (ie: site.com/folder/file.php) or you can setup a cronjob to do it automatically

  • Asad says:

    Well its dumb to assign untrusted users with input filters that allow them to input php code that can be run on the server. That is why people that use drupal should make sure they don’t use php filter unless they absolutely need it. Other than that if your solution requires sharing of source code there are plenty of options such as Google Code, GIT, SVN, etc. to make sure what the users are uploading cannot be executed on ur production server.

    • mike says:

      Many applications contain vulnerabilities that allow for users to upload files via back-doors in the code. This is most commonly done by spam-bots on applications such as WordPress and OSCommerce. The purpose of this application is not to prevent these leaks, but rather to help identify when a leak has been exploited. This script is designed to send a red flag notifying the developer that a malicious file has indeed been uploaded through a scripting backdoor and that it should be promptly dealt with, and the script should be reviewed to close any security gaps.

  • Nico says:

    hello, with the file from GitHub I have this errors:

    Warning: scandir(__DIR__) [function.scandir]: failed to open dir: No such file or directory in /home/…/public_html/malscan.php on line 35

    Warning: scandir() [function.scandir]: (errno 2): No such file or directory in /home/…/public_html/malscan.php on line 35

    Fatal error: Uncaught exception ‘Exception’ with message ‘Unable to scan directory __DIR__. Please make sure proper permissions have been set.’ in /home/…/public_html/malscan.php:38 Stack trace: #0 /home/…/public_html/malscan.php(28): phpMalCodeScan->scan(‘__DIR__’) #1 /home/…./public_html/malscan.php(76): phpMalCodeScan->__construct() #2 {main} thrown in /home/…./public_html/malscan.php on line 38

    • mike says:

      Hey Nico,
      I’ve updated the script on GitHub to fix that issue and also fix some issues in PHP 5.4

      Thanks,
      Mike

  • Reid says:

    Hi Mike,
    I uploaded the php file to my server, but when i entered the url to run it, all i got was a blank screen. Nothing appeared. Not even when I tried to view page source.
    Thanks,
    Reid

    • mike says:

      Because the script is intended to be run as a cron I didn’t have it echo out any output. You can add

      echo ‘done’;

      to the end of the script to ensure that it is running and has completed. Otherwise, be sure to check your PHP Error Logs to make sure there’s not an exception being thrown (as if you have errors turned off this can create the blank white page as well). Otherwise, if something is found it will be emailed to you, not outputted on the screen.

  • Simon says:

    I run the script and after some waiting it comes back with Request Timeout. Is this working or just needs more time? I also extended the time-out to maximum with same result.

  • Arslan Qamar says:

    I have also uploaded this file but only white page display. please guide me

    • mike says:

      The script doesn’t have any output, so it’s possible everythings great, or it’s possible that there’s an exception being thrown if you have errors turned off. To get output, after

      new phpMalCodeScan;

      add

      echo ‘Scan Complete’;

      You can also check your PHP Error Log to see if there are any exceptions being thrown. Otherwise, basically the script will run, and if nothing is found it doesn’t do anything, but if it does find something it will send you a list via email.

  • julian kemp says:

    how long does the script take to run on a typical sized joomla site? when i access the script directly all i get is a blank white page

  • shouton says:

    What is the mechanism?

    I don’t understand why your code have to be install in a live site.
    and run as a corn job.

    How can I trust you?

    • mike says:

      Hello,
      I understand your concern. The reason it has to be installed on the live site and run as a cron is because hackers will be attacking your live site (assuming your dev/ test site is behind a firewall or on a private intranet).

      So on the live site because that’s where they will most likely attack, and set as a cron so that the script is executed on a regular basis instead of requiring you to remember to manually utilize it to check for any breaches/ hacks (you can do it this way, just a cron will do this automatically and be a lot more convenient).

      What the script does itself is very simple, it first accesses the file directory to get a list of folders and files. It views directories and files recursively to ensure that it is checking all of your files. It does this using a “read only” process, so it will NOT edit your files in any way. Once the file is opened it runs a simple regular expression check to see if it contains either an “eval()” or a “eval(base64…())” function. If it does it adds it to a list of files that MAY have been modified, and sends you an email with that list.

      As far as how do you know you can trust me, well you really don’t. The source code is available on GitHub (see the link above) and you can see EXACTLY what the script does for yourself. If you’re not sure, get someone you TRUST who knows PHP and have them review the file prior to installation. Of course, there’s no promises or guarantees, but the purpose of the script is to help IDENTIFY sites that have been hacked so that malicious code can be removed BEFORE the site becomes an agent of the hacker.

      Best of luck!

      - Mike

  • HM Soeharto says:

    Hi Mike,

    Can I use your code on localhost (XAMPP) and how to use it?

    • mike says:

      Yes you can :) Just add it to your base directory, update the email address, and then browse to the script on your localhost to run it. You could also setup a cron job or a scheduled Windows batch file to have the process automated… however if you’re doing it on your localhost chances are you will just want to run the script prior to deploying (unless your localhost is publicly available)

  • John Haywood says:

    I’m using a modified version of this Class to supplement some other file scanning I’m doing (nice work by the way!).
    For anyone that is interested, I’m using it on a bespoke CMS that contains around 4000+ files and the time it takes to scan them is less than 2 seconds.
    I did find I could speed things up a little by removing some none directories up front because scandir() will count ‘.’ and ‘..’ as directories so in the scan function I added an extra line in the foreach loop

    foreach($files as $file) {
    if ($file != ‘.’ && $file != ‘..’) {
  • Eduardo says:

    Hi… somehow I cannot get php to mail me anything. How can I modify the script so instead of mailing anyone it put results on screen?

    Thanks!

    • mike says:

      Hey Eduardo,
      The easiest way would to replace line 66:

      mail(SEND_EMAIL_ALERTS_TO,'Malicious Code Found!',$message,'FROM:');

      with:

      echo $message;

      That will output it on the screen instead of mailing it :)

  • Tim Liton says:

    Sir am getting those errors:

    Warning: file_get_contents(/home/hostingclerks2/public_html/allinclusive.io/.ftpquota): failed to open stream: Permission denied in /home/hostingclerks2/public_html/clean-malware.php on line 43

    Warning: file_get_contents(/home/hostingclerks2/public_html/budget-domains.net/.ftpquota): failed to open stream: Permission denied in /home/hostingclerks2/public_html/clean-malware.php on line 43

    Warning: file_get_contents(/home/hostingclerks2/public_html/h2o3.org/.ftpquota): failed to open stream: Permission denied in /home/hostingclerks2/public_html/clean-malware.php on line 43

    Warning: file_get_contents(/home/hostingclerks2/public_html/selectall.net/.ftpquota): failed to open stream: Permission denied in /home/hostingclerks2/public_html/clean-malware.php on line 43

    Warning: file_get_contents(/home/hostingclerks2/public_html/smarty/.ftpquota): failed to open stream: Permission denied in /home/hostingclerks2/public_html/clean-malware.php on line 43

    Fatal error: Maximum execution time of 30 seconds exceeded in /home/hostingclerks2/public_html/clean-malware.php on line 42

    • mike says:

      Hey Tim,
      You’re getting two different errors, the first is a timeout error (at the very bottom) which can be corrected by updating the time limit directive in the php.ini or utilizing the set_time_limit() function – http://php.net/manual/en/function.set-time-limit.php

      The second error is caused because you do not have permission to open .ftpquota – you may want to add some code to skip this file – if you email me (see Contact page) I can help you add that code if you’d like.

      Those two fixes should take care of the errors you’re seeing now.

      Best of luck!
      - Mike

  • Hey Mike,

    Thanks for the file, hopefully it will work out for us where some nasties are lurking!

    I am a complete newbie on this but have tried to run the cron job in the following manner, it just throws me back a copy of the whole file;

    /usr/bin/php -q /home/our-username/public_html/phpMalCodeScanner.php

    Am I doing something wrong? This was what I was told to place by my hosts.

    Hope you can help cause I think we might be infected after a DDoS attack a couple of weeks back.

    Cheers, Chris

    • mike says:

      That should work… I’m not sure why it would be outputting the code of the file- if you go to the url in your browser does it work?

      Another option might be utilizing a CURL request to open the file on the server instead of trying to run it in the shell.

      But unless someone else see’s something that I’m missing, it should be working!

    • Hey Mike,

      Thanks for getting back to me.

      I apologise for the way I have to place this but here is the text I get back on the email.

      Malicious-Code-Scanner/phpMalCodeScanner.php at master · mikestowe/Malicious-Code-Scanner · GitHub

      Skip to content

      Sign up
      Sign in

      This repository

      Explore

      Features

      Enterprise

      Blog

      Star


      15

      Fork


      17

      mikestowe/Malicious-Code-Scanner



      Code


      Issues


      Pull Requests


      Pulse


      Graphs

      HTTPS clone URL

      Subversion checkout URL

      You can clone with
      HTTPS
      or Subversion.

      Clone in Desktop

      Download ZIP

      Permalink

      branch:
      master

      Switch branches/tags

      Branches

      Tags


      master

      Nothing to show

      Nothing to show



      Malicious-Code-Scanner / phpMalCodeScanner.php

      LukasFT
      Apr 24, 2014

      Unlimited memory


      2
      contributors


      Users who have contributed to this file

      mikestowe

      LukasFT

      82 lines (56 sloc)

      2.026 kb

      Raw
      Blame
      History


      <?php

      /*

      Plugin Name: php Malicious Code Scanner

      Plugin URI: http://www.mikestowe.com/phpmalcode

      Description: The php Malicious Code Scanner checks all files for one of the most common malicious code attacks, the eval( base64_decode() ) attack…

      Version: 1.3 alpha

      Author: Michael Stowe

      Author URI: http://www.mikestowe.com

      Credits: Based on the idea of Er. Rochak Chauhan (http://www.rochakchauhan.com/), rewritten for use with a cron job

      License: GPL-2

      */

      // Set to your email:

      define('SEND_EMAIL_ALERTS_TO','[email protected]');

      ############################################ START CLASS

      class phpMalCodeScan {

      public $infected_files = array();

      private $scanned_files = array();

      function __construct() {

      $this->scan(dirname(__FILE__));

      $this->sendalert();

      }

      function scan($dir) {

      $this->scanned_files[] = $dir;

      $files = scandir($dir);

      if(!is_array($files)) {

      throw new Exception('Unable to scan directory ' . $dir . '. Please make sure proper permissions have been set.');

      }

      foreach($files as $file) {

      if(is_file($dir.'/'.$file) && !in_array($dir.'/'.$file,$this->scanned_files)) {

      $this->check(file_get_contents($dir.'/'.$file),$dir.'/'.$file);

      } elseif(is_dir($dir.'/'.$file) && substr($file,0,1) != '.') {

      $this->scan($dir.'/'.$file);

      }

      }

      }

      function check($contents,$file) {

      $this->scanned_files[] = $file;

      if(preg_match('/eval\(base64/i',$contents) || preg_match('/eval\($_/i',$contents)) {

      $this->infected_files[] = $file;

      }

      }

      function sendalert() {

      if(count($this->infected_files) != 0) {

      $message = "== MALICIOUS CODE FOUND == \n\n";

      $message .= "The following files appear to be infected: \n";

      foreach($this->infected_files as $inf) {

      $message .= " – $inf \n";

      }

      mail(SEND_EMAIL_ALERTS_TO,'Malicious Code Found!',$message,'FROM:');

      }

      }

      }

      ############################################ INITIATE CLASS

      ini_set('memory_limit', '-1'); ## Avoid memory errors (i.e in foreachloop)

      new phpMalCodeScan;

      ?>

      Jump to Line

      Go


      Status
      API
      Training
      Shop
      Blog
      About

      © 2014 GitHub, Inc.
      Terms
      Privacy
      Security
      Contact




      Something went wrong with that request. Please try again.

      Is it supposed to come out like this?

      Thanks, Chris

    • mike says:

      Hey Chris,
      It looks like you downloaded the GitHub page and not the actual script itself which is why you are getting the file contents back in the format that you are. What you’ll want to do is copy the file from here:

      https://raw.githubusercontent.com/mikestowe/Malicious-Code-Scanner/master/phpMalCodeScanner.php

      Once you bring that code over you will need to add your email on line 14.

      Hope that helps!
      - Mike

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>