Skip to content

Instantly share code, notes, and snippets.

@grisha87
Last active July 27, 2022 12:16
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save grisha87/4106151 to your computer and use it in GitHub Desktop.
Save grisha87/4106151 to your computer and use it in GitHub Desktop.
PHP.Kryptik.AB removal script
<?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