Clean Up A Hacked WordPress Site

Recently, a colleague contacted me saying his WordPress instance had been hacked and asked for suggestions on how to clean it up. This got me thinking about how many articles and blogs I read regarding being proactive about security, but how few I’ve read about cleaning up your site if it’s been infected.

If someone hacks your site, they can do many tricky things to infect it and ensure they can hack again. That’s why it is important to be thorough and rid your server of infected code.

File System

The first place to start is the file system. Malicious files can be uploaded to your server, and often files are put there by an automated process and uploaded all at the same time. Find an infected file (or malicious file if you have one) and check the last modified date. Next, create a file named malware.php and copy/paste this code into it:

<?php

$filename = $_GET["s"];
$content_pattern = $_GET["c"];
echo "Searching for $content_pattern in ".$filename."</br>";

//define the path as relative
$path = ".";
$webpath ="http://".$_SERVER['HTTP_HOST']."/";

//using the opendir function
$dir_handle = @opendir($path) or die("Unable to open $path");

echo "Directory Listing of $path<br/>";

list_dir($dir_handle,$path,$filename,$content_pattern);

function list_dir($dir_handle,$path,$filename_pattern,$content_pattern)
{
    // print_r ($dir_handle);
    echo "<ol>";
    //running the while loop
    while (false !== ($file = readdir($dir_handle))) {
        $dir =$path.'/'.$file;
        if(is_dir($dir) && $file != '.' && $file !='..' ) {
            $handle = @opendir($dir) or die("undable to open file $dir/$file");
            list_dir($handle, $dir, $filename_pattern, $content_pattern);
        } elseif($file != '.' && $file !='..') {
			//echo "<li><a href='$webpath.$dir'>$webpath.$dir - ".date("Y/m/d H:i",filemtime($webpath.$dir))."</a></li>";
			if(date("YmdHi", filemtime($webpath.$dir))==$content_pattern || intval(date("Ymd", filemtime($webpath.$dir)))==intval($content_pattern)-1 || intval(date("Ymd", filemtime($webpath.$dir)))==intval($content_pattern)+1){
				echo "<li><a href='$webpath.$dir'>$webpath.$dir</a> ".date("Y/m/d H:i", filemtime($webpath.$dir))."</li>";
				
				$handle = @fopen($dir, "r"); 
				if ($handle) { 
				   while (!feof($handle)) {
						$content = fgets($handle); 
						$test = stristr($content, $content_pattern);
						echo $test;
						//unlink($webpath.$dir);
				   } 
				   fclose($handle); 
				} 
			}
        }
    }
    
    echo "</ol>";

    closedir($dir_handle); 
}
?>

Then, upload the file to your root directory. It is used to find files that were modified within a certain time range. You can visit the page with the “c” querystring parameter that has the value of the date/time you are requesting. Request it in the format year/month/day (leading zeros) or year/month/day/hours/minutes for very specific times

So, if you were searching for January 04, 2012 at 9:10pm your request would look like:

malware.php?c=201201042110

Note that the leading zeros for month, date, hours and minutes should be present. This will traverse the file system for any files modified with this date. It should find the infected file you have already looked at plus any more that may come up. If no files appear, make sure your servers timezone matches your local settings – sometimes they can conflict and the date you see in your FTP may not be the accurate time as far as the server is concerned. Try testing on other, legitimate files to see if they come up.

If you do see a number of infected files, you can go through and delete them in FTP or SSH. Sometimes, an infection will place numerous files across every directory on your server. If this occurs you should check the malware.php file with plus or minus minutes as this process may have spanned a few minutes and not all files will necessarily have the same last-modified minutes. If you find it too time consuming to manually remove these files, ensure that there are no legitimate files that come up, and modify the malware.php file and uncomment line 39 of the file:

unlink($webpath.$dir);

Once you add this code, visit the same page ONCE then immediately recomment the line and the file. This will delete any file with that modified date.

It is important to delete this file when you’re finished as it could give anyone who visits the page access to file system info.

This method of cleaning up your site is not specific to WordPress and can work on any file system based CMS.

Database Clean Up

When a site is hacked, code can get inserted into your database. The wp_options table is a common place. Data in this table, and in others, can be encrypted, encoded, or serialized – sometimes two or three of these, so it is difficult to diagnose an infection.

When your site is hacked, I recommend using the export feature of WordPress (Tools -> Export) to export your content to a flat file, then reinstalling WordPress, and importing your content from the flat file. You will also have to re-enable plugins, backup your wp-uploads directory, and change any custom settings you have such as permalinks, homepage etc. This can be a cumbersome task and there may be some other things you’ll have to take into consideration as each WordPress instance, theme, and plugin is unique. Use care when doing this.

Once your site has become “uninfected” it’s best to become proactive to prevent this from happening again. You should let your hosting company know your site was hacked in case it was hacked from a vulnerability in their servers. You should also check server logs and figure out if you were infected by an XSS, SQL injection, or CSRF so that you’re not keeping the same, vulnerable files out there to be hacked again.

In future posts, I’ll discuss ways to diagnose a hack to help find vulnerabilities as well as a post on WordPress-specific security techniques you can use to prevent another attack.

One thought on “Clean Up A Hacked WordPress Site”

Leave a Reply

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