Анализатор атак на сайт

Это новая функция в плагине 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). Он еще мал, но со временем вырастет.

/**
 * Description: Analyzes attacks targeting a website.
 *
 * @category    wms7-attack-analyzer.php
 * @package     WatchMan-Site7
 * @author      Oleg Klenitskiy <klenitskiy.oleg@mail.ru>
 * @version     3.0.3
 * @license     GPLv2 or later
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit();
}
/**
 * Block a visitor.
 *
 * @param string $ban_notes Ban notes.
 */
function wms7_block_visitor( $ban_notes ) {
	// baned user ip.
	$arr        = array(
		'ban_start_date' => date( 'Y-m-d' ),
		'ban_end_date'   => date( 'Y-m-d', ( strtotime( 'next month', strtotime( date( 'Y-m-d' ) ) ) ) ),
		'ban_message'    => 'Attack analyzer',
		'ban_notes'      => $ban_notes,
	);
	$black_list = wp_json_encode( $arr );

	return $black_list;
}

/**
 * Analyzes the nature of the site visit.
 *
 * @param string $login_result     Login result.
 * @param string $_log             Login.
 * @param string $user_role        User role.
 * @param string $page_visit       Page visit.
 * @param string $_http_user_agent User agent.
 * @param string $user_ip          User IP.
 */
function wms7_attack_analyzer( $login_result, $_log, $user_role, $page_visit, $_http_user_agent, $user_ip ) {
	$black_list = '';
	// Если пустой User Agent - баним на 1 месяц.
	if ( '' === $_http_user_agent ) {
		// Insert to black_list.
		$black_list = wms7_block_visitor( 'Empty User Agent' );
		// Insert to htaccess.
		wms7_ip_insert_to_file( $user_ip );

		return $black_list;
	}
	// Если доступ через xmlrpc - баним на 1 месяц.
	if ( strpos( $page_visit, 'xmlrpc' ) ) {
		// Insert to black_list.
		$black_list = wms7_block_visitor( 'Access via xmlrpc' );
		// Insert to htaccess.
		wms7_ip_insert_to_file( $user_ip );

		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 );
				// Insert to htaccess.
				wms7_ip_insert_to_file( $user_ip );

				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' );
		// Insert to htaccess.
		wms7_ip_insert_to_file( $user_ip );

		return $black_list;
	}
	// Если Сканирование авторов сайта - баним IP.
	if ( strpos( $page_visit, 'author=' ) ) {
		// Insert to black_list.
		$black_list = wms7_block_visitor( 'Scan authors site' );
		// Insert to htaccess.
		wms7_ip_insert_to_file( $user_ip );

		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 часа она будет восстановлена, если дата окончания блокировки еще не наступила.

Leave a Reply

Your email address will not be published. Required fields are marked *