Finding and removing malware in WordPress and other PHP sites

Been dealing with a lot of malware lately that has been ending up on sites I manage.  Usually the malware is installed through some sort of know exploit.  Most sites I have seen this on were outdated versions of WordPress, but I have also seen it appear on OpenCart installations as well.

In my particular situation, code was being inserted into different WordPress files.  This code essentially intercepted the the permalink system and delivered pages that may not exist on the actual site instead of delivering a 404 error.  One important thing to note is this code also delivered different content to search engines. If it detected googlebot or bingbot it may deliver a completely different homepage than you might see normally.  This is usually only noticed after it is too late and your site appears to be selling Viagra or Loan services based on the search results descriptions.   The particular code that was injected is similar to the below code.

It could be injected in many different files.  The goal was to get it in a WordPress core file before too much happened.  This could be the wp-config.php, wp-login.php, wp-settings.php or multiple other files.  It seemed to intelligently randomly pick files.  It started with the wp-config.php files.  After I locked those down it appeared in other files.  So the first thing I did was get rid of this code wherever I could find it.  But before I get into looking for the code lets take a look at what it is doing.

  1. Line 1 is simple enough.  It sets the variable $file_Oyi_name to a string that points to what appears to be an image.  The appears to be an image part is what becomes common.
  2. Line 2 is just defining the same string to a constant.  This may be so it can be globally accessed.
  3. Line 3 is making sure that the file exists, if the file exists it creates the string ‘_(.*)_e’ Note how it divides it up so you can search for _(.*)_e
  4. Line 4 is just defining a constant string that points to the directory of the file in line 1
  5. Line 5 is now reading in the data from the file that appears to be an image.
  6. Line 6 is essentially applying an “un-zip” to the data from the image file.  It is now pretty obvious that this files does not have an actual image in it, but is some sort of compressed data.
  7. Line 7… the $code_ONr variable not contains the decompressed data from the file that appeared to be an image.  This data is most likely PHP code.  But the code isn’t quite ready for execution yet.  Some replacing needs to happen which can be translated to preg_replace(‘_(.*)_e’, “eval(‘code_from_$code_ONr’);”, NULL);

I’m somewhat at a loss in step 7.  But it seems that the code is somehow executed at this point.

So… how do we go about getting rid of this code.  It is as simple as search for a particular string of this now known malware.  I decided to look for the “file_Oyi” string since it seemed unique and I saw it in all my infected files.  The command below will find all the files within the directory it is ran, including sub directories.

Once you do this you can inspect each file and remove the malicious code.

At this point I thought I was done.  But I was wrong.  The code started re-appearing even after closing up all known security issues.  So there was either an unknown security issue or there was still some malicious code hiding out somewhere in the site.

After some investigation of the access logs I noticed some hits to a hidden PHP file.  A file that was named something like .settings.php or maybe .user.php  This was strange as I was unaware of any PHP files being hidden on purpose.  So I took a look at one of these files and discovered it was either a lot of encoded code or contained functions that were not part of anything else on the site. An example of this file is below.

At this point I searched for and removed any files that were in the form of .*.php  I used the following command for that.  Warning this could delete important files, I suggest you first do a dry run by removing the -exec and everything after it.  You can also change “rm -f” to “rm -i” to give you the option to verify removal of each file found.

So now all is goo right? Nope.  Apparently there are some files just like the above that were not proceeded with a “.” However these files all had similar text in them.  Below is a list of strings I searched for in all the PHP files to find any remaining scripts like the above.

Some strings to search for include

And another file you will probably find will look something like this…

The above file actually will look like this file below once it is decoded and executed.  This turns out to the the WSO Web Shell script.