Simple script to find base64_decode in your files | Malware removal

Zobair khan
8 min readOct 24, 2020

If you have a large site with a lot of files it can be very difficult, or at least very time consuming to locate any obfuscated php code on your site. This simple script will work on most, not all sites. The script is a PHP script so your server/site must support PHP for it to run. To use the script open a text editor then copy and paste the script below. There are two versions of the script in the grey box below. The first listing is the php code only without ant comments. The second copy contains comment lines that explain the what the various lines of code do. You should only copy one of the versions. Save the file the name does not matter, but the file must have a .php extension, I use find-string.php . Once you have saved the file upload the file in the root directory of your site. Next open the file in your browser http://yoursite.com/find-string.php or whatever you have named the file. If you have a large site with lots of files it can take awhile to run. If the script worked you should see as a minimum the find-string.php returned, the line

./your-file-name.php -> contains base64_decode

and hopefully any other files containing the string base64_decode. The files will be listed like this

./the directory/the file name.php,

the path/filename of the file containing the string. With some sites you might see a path/filename like this

/???/???/.temp/.tmp.php

the name of the sub-directory and file both start with a . Starting a folder or filename with a . is used to signify a “system” folder or file. Some ftp programs will not show a system folder/file with the default configuration so you may need to specify something like “show hidden files” or “display system files” to see them in your ftp program.

Once (if) you have gotten the list of files be sure to go back and delete this script/file, find-string.php from your server DO NOT LEAVE IT IN PLACE! Keep a copy on your local computer and if you ever need to use it again (hopefully not) just upload it to your site again. The script can not harm your site but if you leave it in place, particularly if you use the default name of find-string.php anyone could open it in their browser and it could give them some insight into your file structure etc.

The script:

<html><head><title>Find String</title></head><body>
<?php
// ini_set(‘max_execution_time’, ‘0’);
// ini_set(‘set_time_limit’, ‘0’);
find_files(‘.’);
function find_files($seed) {
if(! is_dir($seed)) return false;
$files = array();
$dirs = array($seed);
while(NULL !== ($dir = array_pop($dirs)))
{
if($dh = opendir($dir))
{
while( false !== ($file = readdir($dh)))
{
if($file == ‘.’ || $file == ‘..’) continue;
$path = $dir . ‘/’ . $file;
if(is_dir($path)) { $dirs[] = $path; }
else { if(preg_match(‘/^.*\.(php[\d]?|txt|js|htaccess)$/i’, $path)) { check_files($path); }}
}
closedir($dh);
}
}
}

function check_files($this_file){
$str_to_find[]=’base64_decode’;
$str_to_find[]=’edoced_46esab’; // base64_decode reversed
$str_to_find[]=’preg_replace’;
$str_to_find[]=’HTTP_REFERER’;
$str_to_find[]=’HTTP_USER_AGENT’;

if(!($content = file_get_contents($this_file)))
{ echo(“<p>Could not check $this_file You should check the contents manually!</p>\n”); }
else
{
while(list(,$value)=each($str_to_find))
{
if (stripos($content, $value) !== false)
{
echo(“<p>$this_file -> contains $value</p>\n”);
}
}
}
unset($content);
}
?>
</body></html>

Note from a WordPress user — if your text editor messes up the script adding breaks or other layout characters, just load and edit within the wordpress editor as you would edit plug in code. Then just copy back to main folder.

If you are not familiar with PHP code the listing below is the same script with comments added to explain what the lines of code do.

<html><head><title>Find String</title></head><body>
<?php
// Most hosting services will have a time limit on how long a php script can run, typically 30 seconds.
// On large sites with a lot of files this script may not be able to find and check all files within the time limit.
// If you get a time out error you can try over riding the default time limits by removing the // in the front of these two lines.

// ini_set(‘max_execution_time’, ‘0’);
// ini_set(‘set_time_limit’, ‘0’);


find_files(‘.’);

function find_files($seed)
{
if(! is_dir($seed)) return false;
$files = array();
$dirs = array($seed);
while(NULL !== ($dir = array_pop($dirs)))
{
if($dh = opendir($dir))
{
while( false !== ($file = readdir($dh)))
{
if($file == ‘.’ || $file == ‘..’) continue;
$path = $dir . ‘/’ . $file;
if(is_dir($path)) { $dirs[] = $path; }

// the line below tells the script to only check the content of files with a .php extension.
// the if{} statement says if you “match” php[\d]? at the end of the file name then check the contents
// of the file. The [\d]? part means also match if there is a digit \d such as .php4 in the file extension

// else { if(preg_match(‘/\/*\.php[\d]?$/i’, $path)) { check_files($path); }}

// 07/26/2011 Based on some recent Pharma hacks I have changed the default to check php, js and txt files
else { if(preg_match(‘/^.*\.(php[\d]?|js|txt)$/i’, $path)) { check_files($path); }}

// if you would like to check other (all) file types you can comment out/un-comment and or modify
// the following lines as needed. You can only have one of the else{} statements un-commented.
// The first example contains a lengthy OR (the | means OR) statement, the part inside the (),
// (php[\d]?|htm|html|shtml|js|asp|aspx) You can add/remove filetypes by modifying this part
// (php[\d]?|htm|html|shtml) will only check .php, .htm, .html, .shtml files.

// else { if(preg_match(‘/^.*\.(php[\d]?|htm|html|shtml|js|asp|aspx)$/i’, $path)) { check_files($path); }}
// In the next else{} statement there is no if{}, no checking of the file extension every file will be checked
// else { check_files($path); } // will check all file types for the code
}
closedir($dh);
}}} function check_files($this_file)
{
// the variable $str_to_find is an array that contains the strings to search for inside the single quotes.
// if you want to search for other strings replace base64_decode with the string you want to search for.

$str_to_find[]=’base64_decode’;
$str_to_find[]=’edoced_46esab’; // base64_decode reversed
$str_to_find[]=’preg_replace’;
$str_to_find[]=’HTTP_REFERER’; // checks for referrer based conditions
$str_to_find[]=’HTTP_USER_AGENT’; // checks for user agent based conditions
$str_to_find[]=’assert(‘; $str_to_find[]=’create_function(‘; $str_to_find[]=’$_REQUEST[‘; if(!($content = file_get_contents($this_file)))
{ echo(“<p>Could not check $this_file You should check the contents manually!</p>\n”); }
else
{
while(list(,$value)=each($str_to_find))
{
if (stripos($content, $value) !== false)
{
echo(“<p>$this_file -> contains $value</p>\n”);
}
}
}
unset($content);
}?>
</body></html>

Some things that can (will?) go wrong. Most hosting services will have a maximum time limit that a php script can run so on an extremely large site the script may time out. If the script times out you can try un-commenting the first two lines, that should override any time limits.

Change

// ini_set(‘max_execution_time’, ‘0’);
// ini_set(‘set_time_limit’, ‘0’);

to

ini_set(‘max_execution_time’, ‘0’);
ini_set(‘set_time_limit’, ‘0’);

The script opens and reads the directories on your site starting in the directory where you place it. So if you place it in your root directory it will read your root directory and all directories below your root. If you place it in a sub-directory, say you have a structure like /htdocs/wp-admin/themes/cool/ and you place it in /wp-admin it will check files in /wp-admim/ and any sub-directories of /wp-admin/. Since it will be checking a smaller number of sub-directories/files it is less likely to time out.

The script may not be able to open and check some files, usually due to permissions. If this occurs the files that could not be opened should be listed and you should check those files manually.

The script is set up to only check .php, .txt, .js, and .htaccess files, the line

else { if(preg_match(‘/^.*\.(php[\d]?|txt|js|htaccess)$/i’, $path))

partially because this is the most common location for any malicious script but mostly because if you check all files on the site it tends to time out. You can alter the script to check only .htm files or only .html files etc. or you can set it to check all files.

* In several recent pharmacy hacks the hackers have created a file and named it with a .js extension, common.js, func.js, query.js or a .txt extension — but when you examine the contents it contains obfuscated php code, not javascript.

The script is set up to only look for the string base64_decode, preg_replace and for the conditionals HTTP_REFERER and HTTP_USER_AGENT, the array $str_to_find[], again mostly for speed of execution. If you would like to check other file types and/or other strings the script can be easily modified. I have put some examples in the file and used php comment tags, the // at the beginning of the line. You can just comment and un-comment the lines or modify the lines if the examples don’t meet your needs. For example using the lines

else { check_files($path); }

and

$str_to_find=’RewriteRule’;

would find any .htaccess files that contain any re-write-rules.

If the script finds anything you will then need to check each of the files manually. Open the file in your editor and scan through the contents for anything malicious. While base64 encoded code is a favorite of hackers there are also legitimate uses of base64 encoded scripts, the code may not be malicious so check it before you edit anything. You can use the on-line tool at Redleg’s PHP base64 decode to try and decode any strings you find.

If you are not absolutely 100% sure the file is malicious you can rename the file instead of deleting it. Say you have a file named /wp-stat.php that you believe to be malicious but are not sure, rename the file to something like /susp-wp-stat.php. Renaming the file will render it ineffective as part of the hack if it is in fact malicious and it is pretty easy to go back and change the name back to the original if it is a file needed for your site to function properly. If you locate a base64 encoded line in one of your legitimate site files and again are not 100% sure it is malicious then comment the line out. Placing two forward slashes // in front of a line of php code will “comment it out” the line of code will not execute when the script runs. Change

eval(base64_decode(‘abcd………..

to

// eval(base64_decode(‘abcd………..

Again you can always go back and remove the // if you find the line of code is not malicious and needed for your site to function properly.

I have tried to keep this script as lean and easy to use as I could, however lean and easy also means very limited utility. If this script just isn’t getting it done for you (or even if it is) suggest that you check out the script at 25 Years of Programming — PHP script to find malicious code on a hacked server — The script is much more robust and powerful and will find malicious “things” that this script does not even look for. It is easy to install and is a tool that every site owner should have around!

--

--