Это новая функция в плагине WatchMan-Site7 (v.3.0.3). Я хочу создать некое интеллектуальное ядро, которое анализировало каждый вид и характер атаки на сайт и принимало решение по противодействию этим атакам. Естественно – атаки со временем меняются, совершенствуются. Следовательно – будет изменятся и анализатор атак (Attack analyzer).
Перед написанием этой статьи я подумал: а стоит ли описывать методы противодействия хакерам, “помогая” тем самым им совершенствовать свои атаки. Подумав не раз, я все-таки решил написать. И вот почему:
1. Противодействие анти-хакеров и хакеров – будет всегда. Каждая сторона совершенствует свои методы. Это похоже на бег по вертикали. Пока кто-то первым не устанет.
2. Каждый хакер, как бы он этого не хотел – оставляет следы. Задача анти-хакера – найти их и как можно больше.
3. Код плагина – открытый (Open source). Поэтому, при желании злоумышленник может изучить методы противодействия ему всегда.
Еще до создания Attack analyzer в плагине WatchMan-Site7 был написан код, считывающий информацию о посетителе сайта:
/**
* Forms IP data from global variables.
*
* @return string data of IP visitor.
*/
private function wms7_get_user_ip() {
// We get the headers or use the global SERVER.
if ( function_exists( 'apache_request_headers' ) ) {
$headers = apache_request_headers();
$list = '---Apache request headers-------------<br>';
foreach ( $headers as $header => $value ) {
$list = $list . $header . ': ' . $value . '<br>';
}
} else {
$headers = filter_input_array( INPUT_SERVER, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$list = '---$_SERVER request headers-----------<br>';
foreach ( $headers as $header => $value ) {
if ( substr( $header, 0, 5 ) === 'HTTP_' ) {
$header = substr( $header, 5 );
$header = str_replace( '_', ' ', $header );
$header = strtolower( $header );
$header = ucwords( $header );
$header = str_replace( ' ', '-', $header );
$list = $list . $header . ': ' . $value . '<br>';
}
}
}
$the_ip = '';
// We get the redirected IP-address, if it exists.
$_x_forwarded_for = filter_input( INPUT_SERVER, 'X-Forwarded-For', FILTER_SANITIZE_STRING );
if ( $_x_forwarded_for ) {
$the_ip .= 'X-Forwarded-For = ' . $_x_forwarded_for . '<br>';
}
$_http_x_forwarded_for = filter_input( INPUT_SERVER, 'HTTP_X_FORWARDED_FOR', FILTER_SANITIZE_STRING );
if ( $_http_x_forwarded_for ) {
$the_ip .= 'HTTP_X_FORWARDED_FOR = ' . $_http_x_forwarded_for . '<br>';
}
$_http_x_forwarded = filter_input( INPUT_SERVER, 'HTTP_X_FORWARDED', FILTER_SANITIZE_STRING );
if ( $_http_x_forwarded ) {
$the_ip .= 'HTTP_X_FORWARDED = ' . $_http_x_forwarded . '<br>';
}
$http_x_cluster_client_ip = filter_input( INPUT_SERVER, 'HTTP_X_CLUSTER_CLIENT_IP', FILTER_SANITIZE_STRING );
if ( $http_x_cluster_client_ip ) {
$the_ip .= 'HTTP_X_CLUSTER_CLIENT_IP = ' . $http_x_cluster_client_ip . '<br>';
}
$_http_forwarded_for = filter_input( INPUT_SERVER, 'HTTP_FORWARDED_FOR', FILTER_SANITIZE_STRING );
if ( $_http_forwarded_for ) {
$the_ip .= 'HTTP_FORWARDED_FOR = ' . $_http_forwarded_for . '<br>';
}
$_http_forwarded = filter_input( INPUT_SERVER, 'HTTP_FORWARDED', FILTER_SANITIZE_STRING );
if ( $_http_forwarded ) {
$the_ip .= 'HTTP_FORWARDED = ' . $_http_forwarded . '<br>';
}
$_http_client_ip = filter_input( INPUT_SERVER, 'HTTP_CLIENT_IP', FILTER_SANITIZE_STRING );
if ( $_http_client_ip ) {
$the_ip .= 'HTTP_CLIENT_IP = ' . $_http_client_ip . '<br>';
}
$_remote_addr = filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_STRING );
if ( $_remote_addr ) {
$the_ip .= 'REMOTE_ADDR = ' . $_remote_addr;
}
return $list . '---' . $the_ip . '---';
}
Результат работы этого кода:
---Apache request headers------------- Host: adminkov.bcr.by User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://adminkov.bcr.by/still/ Cookie: wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_3ccfd98e86faaa1abd5f45846aa6bc93= user1%7C1541751799%7C6nLDA3iptBYHTekh0n47KYuzjPiEIcrsYxqgh3dmtCO%7Caec6e0f4028811976212e4b7cdc2cb465ebc125e8b50ce1cc8eb05d683cd3e37 Connection: keep-alive ---REMOTE_ADDR = 93.115.86.4--- ---Information about the Cookie visitor--- wordpress_test_cookie=WP Cookie check wordpress_logged_in_3ccfd98e86faaa1abd5f45846aa6bc93= user1|1541751799|6nLDA3iptBYHTekh0n47KYuzjPiEIcrsYxqgh3dmtCO|aec6e0f4028811976212e4b7cdc2cb465ebc125e8b50ce1cc8eb05d683cd3e37
Помимо этого – плагин WatchMan-Site7 собирает данные о геолокации посетителя сайта и его провайдера.
🙂 Возвращаюсь к описанию Attack analyzer.
1. Замечено, что злоумышленник готовя атаку Brute force, сначала сканирует перечень зарегистрированных пользователей с ролью: author или administrator. Иногда, быает, что это “чудо в штанишках” производит это действие с одного IP. В этом случае, вероятность поймать истинный адрес злоумышленника (а не прокси) вырастает многократно.
2. Насколько мне известно: разработчики WordPress готовы отказаться от использования xmlrpc.php и создают нечто другое в архитектуре этой CMS. Предвидя это я уже ввел в Attack analyzer – блокирование IP посетителей, которые обращаются к этому файлу. Более того, за три года изучения CMS WordPress я не видел где-либо активного использования xmlrpc.php Хлопот от него много, а пользы мало.
3. При первой же попытке залогиниться под именем администратора или автора – произойдет блокировка IP посетителя.
Важно: чтобы не забанить самого себя (администратора, автора) прежде всего пропишите IP адреса, исключенные для регистрации посещения (п.2 Do not register visits for:) в настройках плагина !
Ниже приводится код анализатора атак (Attack analyzer). Он еще мал, но со временем вырастет.
<?php
/**
* Description: Analyzes attacks targeting a website.
*
* PHP version 7.4
*
* @category wms7-attack-analyzer.php
* @package WatchMan-Site7
* @author Oleg Klenitskiy <klenitskiy.oleg@mail.ru>
* @version 4.0.0
* @license GPLv2 or later
*/
if ( ! defined( "ABSPATH" ) ) {
exit();
}
/**
* Block a visitor.
*
* @param string $ban_notes Ban notes.
* @param boolean $ban_user_agent Ban user agent.
*/
function wms7_block_visitor( $ban_notes, $ban_user_agent ) {
// baned user ip.
$arr = array(
"ban_start_date" => date( "Y-m-d" ),
"ban_end_date" => date( "Y-m-d", ( strtotime( "next week", strtotime( date( "Y-m-d" ) ) ) ) ),
"ban_message" => "Attack analyzer",
"ban_notes" => $ban_notes,
"ban_login" => false,
"ban_user_agent" => $ban_user_agent,
);
$black_list = wp_json_encode( $arr );
return $black_list;
}
/**
* Analyzes the nature of the site visit.
*
* @param string $_log Login.
* @param string $page_visit Page visit.
* @param string $_http_user_agent User agent.
* @param string $user_ip User IP.
*/
function wms7_attack_analyzer( $_log, $page_visit, $_http_user_agent, $user_ip ) {
$_http_user_agent = filter_input( INPUT_SERVER, "HTTP_USER_AGENT", FILTER_SANITIZE_STRING );
$black_list = "";
$ban_user_agent = false;
if ( "" == get_option( "user_agent_attack" ) ) {
update_option( "user_agent_attack", $_http_user_agent );
update_option( "user_ip_attack", $user_ip );
} else {
if ( get_option( "user_agent_attack" ) == $_http_user_agent &&
get_option( "user_ip_attack" ) !== $user_ip ) {
$ban_user_agent = true;
// Delete item from options.
update_option( "user_agent_attack", "" );
update_option( "user_ip_attack", "" );
} else {
$ban_user_agent = false;
update_option( "user_agent_attack", $_http_user_agent );
update_option( "user_ip_attack", $user_ip );
}
}
// Если пустой User Agent - баним на 1 неделю.
if ( "" == trim( $_http_user_agent ) ) {
// Insert to black_list.
$black_list = wms7_block_visitor( "Empty User Agent", $ban_user_agent );
// Insert to htaccess.
wms7_agent_ins_to_file( "" );
wms7_ip_ins_to_file( $user_ip );
update_option( "user_agent_attack", "" );
return $black_list;
}
// Если доступ через xmlrpc - баним на 1 неделю.
if ( strpos( $page_visit, "xmlrpc" ) ) {
// Insert to black_list.
$black_list = wms7_block_visitor( "Access via xmlrpc", $ban_user_agent );
// Insert to htaccess.
wms7_ip_ins_to_file( $user_ip );
// Insert user_agent into .htaccess.
if ( $ban_user_agent && "" !== trim( $_http_user_agent ) ) {
wms7_agent_ins_to_file( $_http_user_agent );
}
return $black_list;
}
// Если Brute force - баним IP.
if ( $_log ) {
$user_info = get_user_by( "login", $_log );
if ( $user_info ) {
$user_role = array_shift( $user_info->roles );
if ( ( "administrator" == $user_role ) || ( "author" == $user_role ) ) {
// Insert to black_list.
$black_list = wms7_block_visitor( "Brute force: " . $user_role, $ban_user_agent );
// Insert to htaccess.
wms7_ip_ins_to_file( $user_ip );
// Insert user_agent into .htaccess.
if ( $ban_user_agent && "" !== trim( $_http_user_agent ) ) {
wms7_agent_ins_to_file( $_http_user_agent );
}
return $black_list;
}
}
}
// Если Сканирование структуры сайта - баним IP.
if ( strpos( $page_visit, "wp-content" ) || strpos( $page_visit, "wp-includes" ) ) {
// Insert to black_list.
$black_list = wms7_block_visitor( "Scan the site structure", $ban_user_agent );
// Insert to htaccess.
wms7_ip_ins_to_file( $user_ip );
// Insert user_agent into .htaccess.
if ( $ban_user_agent && "" !== trim( $_http_user_agent ) ) {
wms7_agent_ins_to_file( $_http_user_agent );
}
return $black_list;
}
// Если Сканирование авторов сайта - баним IP.
if ( strpos( $page_visit, "author" ) || strpos( $page_visit, "/wp-json/wp/v2/users" ) ) {
// Insert to black_list.
$black_list = wms7_block_visitor( "Scan authors site", $ban_user_agent );
// Insert to htaccess.
wms7_ip_ins_to_file( $user_ip );
// Insert user_agent into .htaccess.
if ( $ban_user_agent && "" !== trim( $_http_user_agent ) ) {
wms7_agent_ins_to_file( $_http_user_agent );
}
return $black_list;
}
return $black_list;
}
p.s.: Даже, если Вы забанили самого себя (любимого), то можете зайдя на свой хостинг по FTP, убрать блокирующую запись из htaccess. Но нужно это сделать достаточно быстро, т.к. работает крон-событие: wms7_htaccess. Это событие срабатывает 1 раз в 1 час. За этот промежуток времени нужно почистить поле Black List в нужной строке таблицы посещений основного экрана плагина WatchMan-Site7.
p.p.s: Крон-событие wms7_htaccess занимается тем, что приводит в соответствие записи о блокировках IP с параметрами блокировок (начало и окончание блокировки IP). В данном случае: если строка блокировки будет удалена из htaccess в ручную, то в течении 1 часа она будет восстановлена, если дата окончания блокировки еще не наступила.
