Created
October 21, 2015 10:59
-
-
Save vpietri/eb61264ff85c475f9cf9 to your computer and use it in GitHub Desktop.
Magento shell script to detect and neutralize malware injection code. By now work only for guruincsite. Should be set in a cronjob task.
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 | |
require_once 'abstract.php'; | |
/** | |
* Magento Malware Shell Script Check | |
* | |
* This file should be save in the shell directory of Magento | |
* Basic usage samples: | |
* php malware.php | |
* php malware.php list | |
* php malware.php clean --mail XX.YY.com | |
* | |
* @author Vincent Pietri <www.vincent-pietri.fr> | |
*/ | |
class Mage_Shell_Malware extends Mage_Shell_Abstract | |
{ | |
protected $_malwares = array('guruincsite'); | |
protected $_connections = array(); | |
protected $_tablePrefix = ''; | |
protected $_logMsg = array(); | |
/** | |
* Parse string with indexers and return array of indexer instances | |
* | |
* @param string $string | |
* @return array | |
*/ | |
protected function _parseIndexerString($string) | |
{ | |
if (!empty($string)) { | |
$codes = explode(',', $string); | |
$codes = array_map('trim', $codes); | |
$processes = $this->_getIndexer()->getProcessesCollectionByCodes($codes); | |
foreach($processes as $key => $process) { | |
if ($process->getIndexer()->getVisibility() === false) { | |
unset($processes[$key]); | |
} | |
} | |
if ($this->_getIndexer()->hasErrors()) { | |
echo implode(PHP_EOL, $this->_getIndexer()->getErrors()), PHP_EOL; | |
} | |
} | |
return $processes; | |
} | |
/** | |
* | |
*/ | |
protected function _getConnection($type) | |
{ | |
if (empty($this->_connections[$type])) { | |
$this->_connections[$type] = Mage::getSingleton('core/resource')->getConnection('core_read'); | |
} | |
return $this->_connections[$type]; | |
} | |
/** | |
* Run script | |
* | |
*/ | |
public function run() | |
{ | |
if ($this->getArg('mail')) { | |
$mails = $this->getArg('mail'); | |
} else { | |
$mails = false; | |
} | |
if ($this->getArg('admin_users')) { | |
$this->adminUsersNumber($this->getArg('admin_users')); | |
} | |
$this->_tablePrefix = (string)Mage::getConfig()->getTablePrefix(); | |
if ($this->getArg('list')) { | |
foreach($this->_malwares as $code) { | |
echo $code . PHP_EOL; | |
} | |
} else if ($this->getArg('detect')) { | |
foreach($this->_malwares as $code) { | |
$method = strtolower($code).'Check' ; | |
if(method_exists($this, $method)) { | |
$this->$method(); | |
} | |
} | |
} else if ($this->getArg('clean')) { | |
foreach($this->_malwares as $code) { | |
$method = strtolower($code).'Check' ; | |
if(method_exists($this, $method)) { | |
$this->$method(true); | |
} | |
} | |
} else { | |
echo $this->usageHelp(); | |
return; | |
} | |
echo '---- Final report' . PHP_EOL; | |
if(!empty($this->_logMsg)) { | |
echo implode(PHP_EOL, $this->_logMsg) . PHP_EOL; | |
if($mails) { | |
$mailsArr = explode(',', $mails); | |
$mail = new Zend_Mail(); | |
$mail->setFrom(Mage::getStoreConfig("trans_email/ident_general/email"),Mage::getStoreConfig("trans_email/ident_general/name")); | |
foreach($mailsArr as $recipient) { | |
$mail->addTo($recipient,$recipient); | |
} | |
$mail->setSubject("Magento malware suspected for '" . Mage::getStoreConfig("web/secure/base_url") . "'"); | |
$body = "Warning," . PHP_EOL . PHP_EOL; | |
$body .= implode(PHP_EOL, $this->_logMsg) . PHP_EOL . PHP_EOL; | |
$body .= 'From: ' . __FILE__; | |
$body = str_replace(PHP_EOL, '<br/>', $body); | |
$mail->setBodyHtml($body); | |
$mail->send(); | |
echo '-- send report to ' . $mails . PHP_EOL; | |
} | |
} else { | |
echo 'all seems right' . PHP_EOL; | |
} | |
} | |
protected function _log($message) | |
{ | |
$this->_logMsg[] = $message; | |
} | |
protected function adminUsersNumber($number) | |
{ | |
$readConnection = $this->_getConnection('core_read'); | |
$query = "select count(*) from {$this->_tablePrefix}admin_user"; | |
$count = (int)$readConnection->fetchOne($query); | |
if ($count>$number) { | |
$this->_log(sprintf('expected %s admin users and found %s. Check real number in back office.', $number, $count)); | |
} | |
} | |
/** | |
* @see : https://blog.sucuri.net/2015/10/massive-magento-guruincsite-infection.html | |
*/ | |
protected function guruincsiteCheck($clean=false) | |
{ | |
$readConnection = $this->_getConnection('core_read'); | |
if ($clean) { | |
$writeConnection = $this->_getConnection('core_write'); | |
} | |
$query = "select * from {$this->_tablePrefix}core_config_data where value like '%guruincsite%' or value like '%function LCWEHH%'"; | |
$result = $readConnection->fetchAll($query); | |
if ($result) { | |
foreach($result as $data) { | |
$this->_log('core_config_data infected: ' . $data['path']); | |
} | |
$query = "UPDATE {$this->_tablePrefix}core_config_data SET value = REPLACE(value, 'guruincsite', 'mykindyfallbackerrorsite') WHERE value LIKE '%guruincsite%'; | |
UPDATE {$this->_tablePrefix}core_config_data SET value = REPLACE(value, 'function LCWEHH', 'function mykindyfallbackfunction') WHERE value LIKE '%function LCWEHH%'"; | |
if ($writeConnection->query($query)) { | |
$this->_log('-- core_config_data neutralized, you should manual cleaning it (search for term "mykindyfallback").'); | |
} | |
} | |
$query = "select * from {$this->_tablePrefix}cms_block where content like '%guruincsite%' or content like '%function LCWEHH%'"; | |
$result = $readConnection->fetchAll($query); | |
if ($result) { | |
foreach($result as $data) { | |
$this->_log('cms_block infected: ' . $data['identifier']); | |
} | |
$query = "UPDATE {$this->_tablePrefix}cms_block SET content = REPLACE(content, 'guruincsite', 'mykindyfallbackerrorsite') WHERE content LIKE '%guruincsite%'; | |
UPDATE {$this->_tablePrefix}cms_block SET content = REPLACE(content, 'function LCWEHH', 'function mykindyfallbackfunction') WHERE content LIKE '%function LCWEHH%'"; | |
if ($writeConnection->query($query)) { | |
$this->_log('-- all cms_block neutralized, you should manual cleaning it (search for term "mykindyfallback").'); | |
} | |
} | |
$query = "select * from {$this->_tablePrefix}cms_page where content like '%guruincsite%' or content like '%function LCWEHH%'"; | |
$result = $readConnection->fetchAll($query); | |
if ($result) { | |
foreach($result as $data) { | |
$this->_log('cms_page infected: ' . $data['identifier']); | |
} | |
$query = "UPDATE {$this->_tablePrefix}cms_page SET content = REPLACE(content, 'guruincsite', 'mykindyfallbackerrorsite') WHERE content LIKE '%guruincsite%'; | |
UPDATE {$this->_tablePrefix}cms_page SET content = REPLACE(content, 'function LCWEHH', 'function mykindyfallbackfunction') WHERE content LIKE '%function LCWEHH%'"; | |
if ($writeConnection->query($query)) { | |
$this->_log('-- all cms_page neutralized, you should manual cleaning it (search for term "mykindyfallback").'); | |
} | |
} | |
} | |
/** | |
* Retrieve Usage Help Message | |
* | |
*/ | |
public function usageHelp() | |
{ | |
return <<<USAGE | |
Usage: php -f malware.php -- [options] | |
list Show all malware code | |
detect Detect malwares | |
clean Clean specific malware | |
--mail <emails> Send email | |
--admin_users <nbr> Check admin users number | |
help This help | |
<emails> Comma separated emails | |
<nbr> Integer | |
USAGE; | |
} | |
} | |
$shell = new Mage_Shell_Malware(); | |
$shell->run(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment