И опять атака на сайты Wordpress — перебор + XMLRPC

    С полудня субботы на моем сервере, где хостится около 25 сайтов на Wordpress, начались дикие тормоза. Так как мне удалось пережить предыдущие атаки (атака 1 — ровно год назад, атака 2 — в марте) не замеченными, то я не сразу понял, в чем дело.

    Когда разобрался, то выяснилось, что идет перебор паролей + множество запросов к XMLRPC.

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

    Эти приемы скорее всего всем известны, но я наступил на пару граблей, которых не нашел в описаниях — вдруг это кому-то сэкономит время.

    1. Останавливаем перебор, плагин Limit Login Attempts — ставим именно его, так как другие защиты сильно подвешивают сервер, например, при использовании плагина Login Security Solution сервер умер через полчаса, плагин сильно грузит базу.

    В настройке обязательно включите галочку «За прокси» — иначе он будет для всех определять ip вашего сервера и автоматически блокировать всех.
    UPDATE, спасибо DarkByte, подробности ниже в комментах — галочку «За прокси» включаем только если не работает определение при включенном «Прямое подключение»



    2. Отключаем XML-RPC — плагин Disable XML-RPC (его просто активировать и всё).

    3. Закрываем wp-login.php — если обращаться к сайту через ip, то плагин не срабатывает и подборщики продолжают долбить сайт. Чтобы этого избежать, в .htaccess добавляем:

    <Files wp-login.php>
    Order Deny,Allow
    Deny from all
    </Files>
    


    Файл wp-login копируем, переименовываем в любое странное имя, например poletnormalny.php и внутри файла автозаменой меняем все надписи wp-login.php на poletnormalny.php.
    Все, теперь к админке можно обратиться только по вашему файлу.

    После этих 3 несложных шагов сайты опять начали летать и пришло спокойствие.

    Ну и вдруг интересно


    Один из вариантов как посмотреть, что вас атакуют. Это можно увидеть в логах nginx (например, вот путь для Debian /var/log/nginx файл access.log).

    Если идет перебор, то вы увидите множество строк вида:
    87.230.87.xx — - [04/Aug/2014:06:35:53 +0400] «POST /wp-login.php HTTP/1.0» 200 5791 "-" "-"

    Запросы XMLRPC:
    95.0.83.xx — - [04/Aug/2014:06:48:03 +0400] «POST /xmlrpc.php HTTP/1.0» 499 0 "-" «Mozilla/4.0 (compatible: MSIE 7.0; Windows NT 6.0)»
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 21
    • –6
      А не было идеи ни у кого всем договориться и включить диапазоны все адреса хецнеров и других крупных хостингов сразу в access deny? Кому нужно смотреть сайт с ip хостеров, кроме как боту или анонимайзеру?
      • +20
        Мне. У меня VPN на Хецнере.
        Благодаря таким, как вы, я не могу ходить на auto.ru, Доброчан и кучу всего еще.
        • –7
          Ну и сколько таких как вы людей? Сайт не много потеряет, тем более можно добавить статический маршрут мимо ВПН и без проблем смотреть нужные сайты, я думаю для человека который пользуется ВПН, это не проблема.
        • +3
          Мне, нужен. Держу VPN у хецнера и на некоторых администрируемых ресурсах (в том числе WP), вход в админку разрешен только с IP адреса сервера.
        • 0
          fail2ban вам в помощь, люди для ленивых уже даже плагин сделали (правда насколько рабочий не знаю, т.к. обычно ручками — новый jail и регулярка для фильтра делается для fail2ban за пару минут)…
          • 0
            В настройке обязательно включите галочку «За прокси» — иначе он будет для всех определять ip вашего сервера и автомат блокировать всех.

            Эта галочка случаем не использует заголовок X-Real-IP (X-Forwarded-For, и другие) вместо REMOTE_ADDR? Если так, то получился вредный совет, вместо полезного, и правильным выходом из ситуации будет корректная настройка веб сервера.
            • 0
              Проверил в коде плагина, да она использует
              define('LIMIT_LOGIN_PROXY_ADDR', 'HTTP_X_FORWARDED_FOR');

              Однако у меня без ее включения не работает корректно определение ip адреса. Быть может вы поделитесь почему это вредно и как поправить, буду очень благодарен!

              Из описания плагина
              What is this option about site connection and reverse proxy?
              A reverse proxy is a server in between the site and the Internet (perhaps handling caching or load-balancing). This makes getting the correct client IP to block slightly more complicated.The option default to NOT being behind a proxy — which should be by far the common case.
              • +4
                Насколько я понял, у вас используется связка nginx+apache, в таком случае до апача коннекты от всех клиентов доходят от адреса сервера (или 127.0.0.1). Правильно в таком случае со стороны nginx выставлять соответствующие заголовки:
                proxy_set_header X_REAL_IP $remote_addr;
                proxy_set_header X_FORWARDED_FOR $proxy_add_x_forwarded_for;

                А к апачу добавить модуль mod_rpaf2 и сказать ему, что реальный адрес пользователя находится в заголовке X_REAL_IP
                RPAFenable On
                RPAFsethostname On
                RPAFproxy_ips 127.0.0.1
                RPAFheader X-REAL-IP

                В RPAFproxy_ips указывается IP адрес сервера с nginx, если он находится на другим IP. Плюсом, после настройки модуля, в логах apache будут реальные адреса пользователей, а не адрес nginx или localhost.

                В противном случае, если включить опцию доверия заголовку HTTP_X_FORWARDED_FOR, а веб сервер будет не за прокси, то атакующий сможет с использованием данного заголовка обмануть плагин, отправляя с каждым запросом разномные IP адреса.
                • 0
                  спасибо за ценный совет! Текст статьи обновил.
            • 0
              Включить Limit Login Attempts и отключить XML RPC будет достаточно? Хочется какого-то быстрого универсального решения, на будущее.
              • 0
                да, достаточно. Я планирую на днях написать плагинчик, который делает сразу 3 действия:
                1. limit logins
                2. отключает XML RPC с вариантами, например, чтобы можно было или полностью опцию отключить или только pingback
                3. переименование wp-login.php в выбранное имя

                Там ничего сложного, но потом проще будет обновлять и дополнять в будущем кучи сайтов свои. Если напишу кину тут ссылку на репозиторий.
                • 0
                  Плагин iThemes security (бывший Better WP security) всё это умеет (и ещё много всего). Разве что потяжелее будет.
                  • 0
                    спасибо, он действительно тяжеловесный и большой, но оттуда можно взять несколько идей и текстов
              • +1
                location ~* /(wp-login\.php|administrator|admin\.php) {
                	set $humantest 0;
                	if ($http_cookie !~* "humans=checktest") {
                		set $humantest 1;
                	}
                	if ($args ~* (callback|logout|lostpassword)) {
                		set $humantest 0;
                	}
                	if ($humantest = 1) {
                		add_header Content-Type text/html;
                		return 200 "<html><body><script>document.cookie='humans=checktest;path=/';location.reload();</script></body></html>";
                	}
                	error_page 404 = @fallback;
                }
                
                

                Код не мой, но позволяет без всяких танцев с плагинами избавится от всякой живности, родился он примерно год назад и зомби еще не научились его парсить…
                • 0
                  Иногда у nginx «default_type» выставлен в что то отличное от «text/html», и тогда мы можем получить в ответ что-то типа такого:
                  HTTP/1.1 200 OK
                  ...
                  Content-Type: application/octet-stream
                  Content-Length: 103
                  Connection: keep-alive
                  Keep-Alive: timeout=5
                  Content-Type: text/html
                  ...

                  Некоторые браузеры не понимаю что это и предлагают «сохранить файл». Что бы такого не было, можно сделать так:
                          location ~* /(wp-login\.php|administrator|admin\.php) {
                                  default_type text/html;
                                  set $humantest 0;
                                  if ($http_cookie !~* "humans=checktest") {
                                          set $humantest 1;
                                  }
                                  if ($args ~* (callback|logout|lostpassword)) {
                                          set $humantest 0;
                                  }
                                  if ($humantest = 1) {
                                          return 200 "<html><body><script>document.cookie='humans=checktest;path=/';location.reload();</script></body></html>";
                                  }
                                  error_page 404 = @fallback;
                          }
                  
                  
                  • 0
                    Если ставить код после (кода ниже) то не работает, а если перед, то PHP не исполняется. Куда его ставить?

                       location ~ \.php$ {
                            try_files $uri =404;
                            fastcgi_split_path_info ^(.+\.php)(/.+)$;
                            fastcgi_pass unix:/var/run/php5-fpm.sock;
                            fastcgi_index index.php;
                            fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                            fastcgi_read_timeout 120;
                            include fastcgi_params;
                        }
                    
                  • 0
                    А я когда-то прописал в .htaccess:

                    #Защита от подбора пароля	
                    <Files wp-login.php>
                    Order Deny,Allow
                    Deny from all
                    allow from домашний_ip
                    allow from рабочий_ip
                    </Files>
                    
                    # protect xmlrpc
                    <Files xmlrpc.php>
                    	Order Deny,Allow
                    	Deny from all
                    </Files>	
                    


                    Если ip выдается динамически можно указать сеть провайдера.
                    Вызов удаленных процедур, за который отвечает xmlrpc.php, мне не нужен
                    • –1
                      Спасибо! Отличный вариант
                    • 0
                      Буквально сегодня установил All In One WP Security & Firewall. Очень широкий функционал и никаких танцев с бубном.

                    • 0
                      Нужно обновить WordPress (уязвимость в XML-парсере). Подробности: wordpress.org/news/2014/08/wordpress-3-9-2/
                      Советую подписаться, чтобы получать подобные новости первыми.

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