├── scanner-logs ├── .gitkeep └── scannerfiles.txt ├── README.md ├── index.php ├── LICENSE └── src └── phpWebScan.php /scanner-logs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scanner-logs/scannerfiles.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Php Website Scanner 2 | A php script that will check all files for malware injection, new files, removed files and modified files since the last scan 3 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | readFile(); 27 | $scan->scan($_SERVER['DOCUMENT_ROOT']); 28 | $scan->sendAlert(); 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Kenny Turner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/phpWebScan.php: -------------------------------------------------------------------------------- 1 | scanned_files[] = $dir; 23 | 24 | $files = scandir($dir); 25 | 26 | // loop through the DIR and check for files or Directories 27 | foreach($files as $file) { 28 | if(is_file($dir.'/'.$file) && !in_array($dir.'/'.$file,$this->scanned_files)) { 29 | // grab the cile contents and check for malware injection 30 | $this->check(file_get_contents($dir.'/'.$file),$dir.'/'.$file); 31 | } elseif(is_dir($dir.'/'.$file) && substr($file,0,1) != '.') { 32 | // do not scan scanner log files as they change every scan 33 | if($file != 'scanner-logs') 34 | $this->scan($dir.'/'.$file); 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * Function to check the file contents for injections 41 | * @string $contents Content of the file 42 | * @string $file Filename being checked 43 | */ 44 | public function check($contents,$file) { 45 | $this->scanned_files[] = $file; 46 | $this->fileindex[] = $file; 47 | 48 | // check for injection 49 | if(preg_match('/eval\((base64|eval|\$_|\$\$|\$[A-Za-z_0-9\{]*(\(|\{|\[))/i',$contents)) { 50 | $this->infected_files[] = $file; 51 | echo 'Infected File : '.$file.'
'; 52 | } 53 | 54 | /* if you are looking for other injected code add here */ 55 | if(preg_match('/x65\/li\x6eweb/' , $contents)){ 56 | $this->infected_files[] = $file; 57 | echo 'Infected File : '.$file.'
'; 58 | } 59 | 60 | // check for modification 61 | if(filemtime($file) > $this->lastscan){ 62 | $this->modified[] = $file.' modified '.date ("F d Y H:i:s.", filemtime($file)); 63 | } 64 | } 65 | 66 | /** 67 | * Function to create a message containing results of scan 68 | */ 69 | public function sendalert() { 70 | // files count 71 | $message = "== FILES SCANNED ==

"; 72 | $message .= count($this->fileindex)." files scanned
"; 73 | $message .= count($this->oldfileindex)." last scanned

"; 74 | 75 | // infected file list 76 | if(count($this->infected_files) != 0) { 77 | $message .= "== MALICIOUS CODE FOUND ==

"; 78 | $message .= "The following files appear to be infected:
"; 79 | foreach($this->infected_files as $inf) { 80 | $message .= " - $inf
"; 81 | } 82 | } else { 83 | $message .= "
== LOOKS ALL CLEAN TO ME ==

"; 84 | } 85 | 86 | // files added 87 | $difference = array_diff($this->fileindex, $this->oldfileindex); 88 | if(count($difference) > 0){ 89 | // set flag for file write 90 | $updateList = true; 91 | 92 | $message .= "
== FILES ADDED ==

"; 93 | foreach ($difference as $added) { 94 | $message .= $added."
"; 95 | } 96 | } else { 97 | $message .= "
== NO FILES HAVE BEEN ADDED ==

"; 98 | } 99 | 100 | // files Removed 101 | $removed = array_diff($this->oldfileindex, $this->fileindex); 102 | if(count($removed) > 0){ 103 | // set flag for file write 104 | $updateList = true; 105 | 106 | // add results to message 107 | $message .= "
== FILES REMOVED ==

"; 108 | foreach ($removed as $deleted) { 109 | $message .= $deleted."
"; 110 | } 111 | } else { 112 | $message .= "
== NO FILES HAVE BEEN REMOVED ==

"; 113 | } 114 | 115 | // files modified 116 | if(count($this->modified) > 0) { 117 | // set flag for file write 118 | $updateList = true; 119 | 120 | $message .= "
== FILES MODIFIED ==

"; 121 | foreach ($this->modified as $modded) { 122 | $message .= $modded."
"; 123 | } 124 | } else { 125 | $message .= "
== NO FILES HAVE BEEN MODIFIED ==

"; 126 | } 127 | 128 | // do we need to create an updated file list 129 | if($updateList){ 130 | // create an update file list 131 | self::writeFile(); 132 | } 133 | 134 | $header = "

PHP Web Scanner Results



"; 135 | $footer .= "


Website was scanned by PHP Web Scanner by South Coast Web Design Ltd"; 136 | 137 | $headers = "MIME-Version: 1.0" . "\r\n"; 138 | $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n"; 139 | // More headers 140 | $headers .= 'From: PHP Website Scanner <'.FROM_EMAIL.'>' . "\r\n"; 141 | 142 | mail(EMAIL_ALERT, 'Website Scan results', $header.$message.$footer, $headers); 143 | 144 | echo '
'.$message.'
'; 145 | 146 | // log record 147 | self::logResults($message); 148 | } 149 | 150 | /** 151 | * Function will create a file containing a serialiazed array of files scanned 152 | */ 153 | public function writeFile() { 154 | // debug. Uncomment to get a fresh file list 155 | // $this->freshclean(); 156 | 157 | $data = serialize($this->fileindex); 158 | $fopen = fopen('scanner-logs/scannerfiles.txt', 'w+'); 159 | fwrite($fopen, $data); 160 | fclose($fopen); 161 | } 162 | 163 | /** 164 | * Function to read the previously canned filenames and unserialize them to an array 165 | * It will also return the last time a file list was created 166 | */ 167 | public function readFile() { 168 | $this->oldfileindex = unserialize(file_get_contents('scanner-logs/scannerfiles.txt')); 169 | $this->lastscan = filemtime('scanner-logs/scannerfiles.txt'); 170 | } 171 | 172 | /** 173 | * Function to help with debugging. Will clear the fileindex array. 174 | */ 175 | public function freshclean() { 176 | unset($this->fileindex); 177 | $this->fileindex[] = ''; 178 | } 179 | 180 | /** 181 | * Function to log results for future reading 182 | * @string $message Records a log of the results 183 | */ 184 | public function logResults($message) { 185 | $fopen = fopen('scanner-logs/scan-results-'.date('H:i').'.log', 'w+'); 186 | fwrite($fopen, $message); 187 | fclose($fopen); 188 | } 189 | } 190 | 191 | 192 | 193 | --------------------------------------------------------------------------------