Last active
July 27, 2022 12:16
-
-
Save grisha87/4106151 to your computer and use it in GitHub Desktop.
PHP.Kryptik.AB removal script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* PHP.Kryptik.AB Cleanup script | |
* | |
* Usage: place the script in same directory that contains files / directories | |
* to be scanned. Then run `php [script_name].php` and wait a bit | |
* | |
* @link http://blog.twelvecode.com | |
* @author Grzegorz Godlewski <grisha87@gmail.com> | |
* @author Kamil Szymanski <kamilszymanski@gmail.com> | |
*/ | |
define('_SCRIPT_NAME_', basename(__FILE__)); | |
class KryptikPurger | |
{ | |
private $stamp = '0247a1'; | |
/** | |
* Contains infected paths that contained the stamp surrounded by # | |
* | |
* @var array|string[] | |
*/ | |
private $hashInfections = array(); | |
/** | |
* Contains infected paths that contained the stamp surrounded by | |
* typical C-style comments | |
* | |
* @var array|string[] | |
*/ | |
private $cInfections = array(); | |
/** | |
* Contains infected paths that contained the stamp surrounded by | |
* HTML-style comments | |
* | |
* @var array|string[] | |
* | |
*/ | |
private $htmlInfections = array(); | |
/** | |
* @var int | |
*/ | |
private static $filesScanned = 0; | |
/** | |
* @var array | |
*/ | |
private static $skipDirs = array('.', '..'); | |
/** | |
* Detects infected files | |
* | |
* @param string $dirName The name of the directory to start the scan with | |
* | |
* @return int Number of scanned files | |
*/ | |
public function scan($dirName) | |
{ | |
$dir = dir($dirName); | |
while ($row = $dir->read()) { | |
if (in_array($row, self::$skipDirs) || $row === _SCRIPT_NAME_) { | |
continue; | |
} | |
$entry = $dir->path . DIRECTORY_SEPARATOR . $row; | |
if (is_dir($entry)) { | |
// Recursive call | |
$this->scan($entry); | |
} else { | |
$f = file_get_contents($entry); | |
if ($f === false) { | |
echo 'Could not open file: ' . $entry; | |
} | |
// Typical PHP infection mark | |
if (strpos($f, '#' . $this->stamp . '#')) { | |
$this->hashInfections[] = $entry; | |
} // JS infection mark | |
else if (strpos($f, '/*' . $this->stamp . '*/')) { | |
$this->cInfections[] = $entry; | |
} else if (strpos($f, '<!--' . $this->stamp . '-->')) { | |
$this->htmlInfections[] = $entry; | |
} else if (preg_match('/\#\/([a-zA-Z0-9]+)\#/', $f) || preg_match('/\/\*\/([a-zA-Z0-9]+)\*\//', $f)) { | |
echo "Possible infection in $entry\n"; | |
} | |
unset($f); | |
++self::$filesScanned; | |
} | |
} | |
unset($dir); | |
return self::$filesScanned; | |
} | |
/** | |
* Cleans up all infected files | |
* | |
* @return int The number of purged files | |
*/ | |
public function purge() | |
{ | |
$pCount = 0; | |
foreach ($this->hashInfections as $entry) { | |
$start = '#' . $this->stamp . '#'; | |
$end = '#/' . $this->stamp . '#'; | |
$this->doPurge($entry, $start, $end); | |
++$pCount; | |
} | |
foreach ($this->cInfections as $entry) { | |
$start = '/*' . $this->stamp . '*/'; | |
$end = '/*/' . $this->stamp . '*/'; | |
$this->doPurge($entry, $start, $end); | |
++$pCount; | |
} | |
foreach ($this->htmlInfections as $entry) { | |
$start = '<!--' . $this->stamp . '-->'; | |
$end = '<!--/' . $this->stamp . '-->'; | |
$this->doPurge($entry, $start, $end); | |
++$pCount; | |
} | |
return $pCount; | |
} | |
protected function doPurge($fileName, $startMark, $endMark) | |
{ | |
$f = file_get_contents($fileName); | |
$sPos = strpos($f, $startMark); | |
$ePos = strpos($f, $endMark) + strlen($endMark); | |
$cutLen = $ePos - $sPos; | |
$substr = substr($f, $sPos, $cutLen); | |
$f = str_replace($substr, '', $f); | |
// Check to be sure | |
$sPos = strpos($f, $startMark); | |
if ($sPos !== false) { | |
echo "File $fileName was not cleaned entirely!" . PHP_EOL; | |
} | |
$data = file_put_contents($fileName, $f); | |
if ($data === false) { | |
echo "Could not save changes to $fileName" . PHP_EOL; | |
} | |
} | |
/** | |
* Returns the array containing infected paths | |
* | |
* @return array|string[] | |
*/ | |
public function getInfectedFiles() | |
{ | |
return array_merge($this->hashInfections, $this->cInfections, $this->htmlInfections); | |
} | |
/** | |
* Returns the number of files that have been marked as infected | |
* | |
* @return int | |
*/ | |
public function getNumberOfInfectedFiles() | |
{ | |
return count($this->hashInfections) + count($this->cInfections) + count($this->htmlInfections); | |
} | |
/** | |
* Returns the number of files that have been scanned | |
* | |
* @return int | |
*/ | |
public function getNumberOfScannedFiles() | |
{ | |
return self::$filesScanned; | |
} | |
} | |
$purger = new KryptikPurger(); | |
$purger->scan('.'); | |
// Notify the users | |
echo "Found {$purger->getNumberOfInfectedFiles()} infected files among {$purger->getNumberOfScannedFiles()}" . PHP_EOL; | |
// List all infections | |
foreach ($purger->getInfectedFiles() as $entry) { | |
echo "$entry\n"; | |
} | |
// Purge | |
$purger->purge(); | |
echo "Done." . PHP_EOL; | |
exit(0); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment