Пока вы читаете эту статью, совершаются тысячи, если не сотни тысяч кибератак.
Некоторые из них более изощренные, чем другие: от троянов, попыток фишинга, заражения вредоносным ПО до атак ботнетов (также известных как DDoS) – так что кибератаки буквально повсюду.
Сегодня мы рассмотрим очень специфический тип атак: SSH брутфорс.
В конечном итоге мы разработаем инструмент, который будет отслеживать, контролировать и находить злоумышленников в режиме реального времени.
Что такое SSH?
Прежде чем перейти к архитектурным проблемам и коду, рассмотрим основ.
SSH (что расшифровывается как Secure Shell) – это протокол безопасной связи.
Он позволяет компьютерам общаться друг с другом, используя защищенный туннель, который никто не может понять.
SSH является развитием протокола Telnet, который также обеспечивает коммуникационный уровень, но небезопасный.
SSH очень широко используется для доступа к удаленным машинам и выполнения некоторых задач администрирования на них.
Обратите внимание: если мы подключимся к нашим машинам с помощью Telnet, весь мир сможет увидеть наш пароль, и это будет так же просто, как открыть Wireshark и перехватить Telnet-пакеты.
К счастью, большинство атак не успевают пройти и блокируются брандмауэрами или антивирусными программами, которые могут быть встроены непосредственно в ваш компьютер или маршрутизатор.
Но поверьте, если у вас есть виртуальная машина в облаке, кто-то прямо сейчас может попытаться получить к ней доступ, используя атаку брутфорса по SSH, чтобы превратить ее в ботнет или украсть вашу личную информацию.
Сегодня мы положим этому конец.
Мы будем контролировать, отслеживать и геолоцировать атаки SSH-перебором, которые прямо сейчас происходят на вашей машине
Захват логов атак SSH
Прежде чем перейти непосредственно к нашей архитектуре и дизайну, как мы же сможем вручную отследить записи SSH-перебора, которые выполняются на нашей машине?
В этой статье используется Ubuntu с rsyslog для отслеживания логов.
Для тех, кто не очень хорошо знаком с системами Linux, rsyslog – это инструмент, используемый в дистрибутивах Linux для записи, стандартизации, преобразования и хранения логов в агрегированном инструменте (например, Logstash!).
Записи SSH относятся к разделу auth в rsyslog, который агрегируется в var/log/auth.log .
Выполнив простую операцию less /var/log/auth.log | grep ssh, вы увидите атаки перебором, которые могут происходить и на вашей машине.
Ключевым является сообщение Failed password for invalid user username.
Это кто-то пытается получить доступ к моей машине с недействительными учетными данными.
И они делают это очень часто, минимум десятки попыток в день.
Прямо рядом находится их IP-адрес вместе с портом, который был выделен SSH для попытки подключения.
Теперь, когда у нас есть способ фиксировать попытки входа по SSH, давайте построим систему, которая сможет отслеживать их в реальном времени и отображать на карте мира в реальном времени.
Архитектура и дизайн
Во-первых, нам нужно отследить журналы rsyslog и отфильтровать логи, специфичные для SSH.
Непосредственно перед тем, как TCP перешлет наше сообщение, нам нужно нормализовать наше сообщение в общий формат JSON.
Затем наше сообщение обрабатывается TCP-сервером, прослушивающим входящие логи.
Для удобства можно использовать для этого Node, но вы можете использовать любую технологию, которую считаете подходящей для этого.
Сообщение парсится, и IP отправляется в службу геолокации IP (в данном случае IPStack), которая предоставит нам широту и долготу.
Затем эта запись обрабатывается в InfluxDB и отображается в Grafana для мониторинга в реальном времени.
Фильтрация сообщений rsyslog
Прежде чем что-то делать, нам нужно уметь фильтровать входящие журналы Ubuntu и выбрать интересующий нас журнал: логи SSH, а точнее логи службы ssd.
Для удобства выбираем сообщения, начинающиеся с Failed, поскольку именно они содержат большую часть информации о происхождении атаки.
Для этого нужно зайти в /etc/rsyslog.d/50-default.conf, который содержит стандартный файл конфигурации для rsyslog.
Если вы не знакомы с этим файлом, то в нем вы настраиваете место хранения логов в вашей системе Linux.
В верхней части этого файла мы собираемся добавить красивый скрипт, который фильтрует сообщения sshd.
(Примечание: не забудьте про инструкцию stop, иначе они также будут храниться в ваших стандартных местах auth).
# Default rules for rsyslog.
#
# For more information see rsyslog.conf(5) and /etc/rsyslog.conf
#
# First some standard log files. Log by facility.
#
if $programname == 'sshd' then {
if $msg startswith ' Failed' then {
// Transform and forward data!
}
stop
}
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
#cron.* /var/log/cron.log
#daemon.* -/var/log/daemon.log
kern.* -/var/log/kern.log
#lpr.* -/var/log/lpr.log
mail.* -/var/log/mail.log
#user.* -/var/log/user.log
Нормализация наших данных
Теперь, когда наши сообщения sshd отфильтрованы и переданы, нам нужен способ их нормализации.
Для этого мы будем использовать шаблоны.
Шаблоны – это встроенные инструменты rsyslog, которые используются для преобразования входящего сообщения в заданный пользователем шаблон.
Для нашего проекта мы будем фильтровать соответствующую информацию в сообщении журнала и создавать из нее JSON.
В папке /etc/rsyslog.d/ создадим файл 01-basic-ip.conf, в котором будет размещен наш шаблон.
Чтобы извлечь необходимую информацию из лога, мы будем использовать regex в файле шаблона.
Этот regex должен соответствовать сообщениям, начинающимся с Failed, и имеет три группы захвата: одна для имени пользователя, одна для IP и одна для порта.
На языке regex это выглядит следующим образом:
^ Failed.*user([a-zA-Z]*).*([0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*).* port ([0-9]*)
Теперь, когда у нас есть наш regex, давайте инкапсулируем его в JSON-объект с помощью шаблона string.
Итоговый файл выглядит следующим образом.
template(name="ip-json" type="string" string="{\"username\":\"%msg:R,ERE,1,DFLT:^ Failed.*user ([a-zA-Z]*).* ([0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*).* port ([0-9]*)--end%\",\"ip\":\"%msg:R,ERE,2,DFLT:^ Failed.*user ([a-zA-Z]*).* ([0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*).* port ([0-9]*)--end%\",\"port\":\"%msg:R,ERE,3,DFLT:^ Failed.*user ([a-zA-Z]*).* ([0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*.[0-9][0-9]*[0-9]*).* port ([0-9]*)--end%\"}")
Пересылка нашего сообщения
rsyslog предлагает широкую панель модулей вывода для пересылки ваших логоа.
Один из них – это обычная TCP-пересылка, называемая omfwd.
Именно эту директиву мы будем использовать для пересылки нашего форматированного сообщения.
Вернемся к нашему файлу 50-default-conf.
if $programname == 'sshd' then {
if $msg startswith ' Failed' then {
action(type="omfwd" target="127.0.0.1" port="7070" protocol="tcp" template="ip-json")
}
stop
}
В этом случае наш JSON будет перенаправлен на TCP-хост, слушающий порт localhost 7070 (адрес нашего сервера Node!).
Отлично, у нас есть наш пайплайн rsyslog.
Создание TCP-сервера
Теперь давайте перейдем к нашему TCP-серверу.
TCP-сервер является получателем наших сообщений JSON.
Для удобства использования JSON я выбрал Node в качестве среды выполнения.
Итак, какова роль нашего TCP-сервера?
Слушать входящие сообщения, запрашивать внешний сервис для получения геолокации нашего нового друга и сохранять весь пакет в InfluxDB.
Вот код для нашего сервера.
var geohash = require("ngeohash");
const config = require("./config");
const axios = require("axios");
const Influx = require("influx");
// TCP handles
const net = require('net');
const port = 7070;
const host = '127.0.0.1';
const server = net.createServer();
server.listen(port, host, () => {
console.log('TCP Server is running on port ' + port + '.');
});
// InfluxDB Initialization.
const influx = new Influx.InfluxDB({
host: config.influxHost,
database: config.influxDatabase
});
let sockets = [];
server.on('connection', function(sock) {
console.log('CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort);
sockets.push(sock);
sock.on('data', function(data) {
//console.log(data);
let message = JSON.parse("" + data)
// API Initialization.
const instance = axios.create({
baseURL: "http://api.ipstack.com"
});
instance
.get(`/${message.ip}?access_key=${config.apikey}`)
.then(function(response) {
const apiResponse = response.data;
influx.writePoints(
[{
measurement: "geossh",
fields: {
value: 1
},
tags: {
geohash: geohash.encode(apiResponse.latitude, apiResponse.longitude),
username: message.username,
port: message.port,
ip: message.ip
}
}]
);
console.log("Intruder added")
})
.catch(function(error) {
console.log(error);
});
});
// Add a 'close' event handler to this instance of socket
sock.on('close', function(data) {
let index = sockets.findIndex(function(o) {
return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort;
})
if (index !== -1) sockets.splice(index, 1);
console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort);
});
});
Одно примечание к этому коду: широта и долгота кодируются в нечто под названием geohash, что является способом кодирования пары широта-долгота и используется плагином Grafana для рисования точки.
В качестве последнего штриха давайте инкапсулируем этот код в службу systemd и запустим ее.
Всемогущая визуализация
Если вы дочитали до этого момента, то вот хорошие новости: наступает самое интересное.
Теперь, когда мы храним наши живые данные в InfluxDB, давайте привяжем к ним Grafana и визуализируем их.
Вкратце, наши измерения в InfluxDB выглядят следующим образом:
Чтобы отслеживать наши геохэши на карте в реальном времени, мы будем использовать плагин WorldMap Panel от Grafana Labs.
Каждое отдельное значение, встречающееся в нашем измерении, будет представлять собой круг на карте.
Конечно, круги становятся больше, если на нашей машине больше вхождений определенных IP-адресов.
Мы можем очень точно, увеличив масштаб карты, увидеть, откуда именно исходила атака!
Заключение
Будьте очень осторожны, когда дело касается SSH, его обслуживание и администрирование является ключевым фактором в любой системе.
см. также:
- 🔫 MaskProcessor – Расширенный список паролей для брутфорса
- 🔫 Обзор инструментов брутфорса для тестирования на проникновение
- 👨🍳 cook: настраиваемый словарик для брутфорса и генератор паролей
- 🐍 Инструкция и скрипт на Python по брутфорсу FTP
- 🌐 Защита Apache от брутфорса и DDoS с помощью модулей Mod_Security и Mod_evasive
- 🖧 8 способов предотвратить атаки брутфорс на SSH на Linux (CentOS / RHEL)
- 🌐 Как изменить URL-адрес администратора WordPress для предотвращения атак брутфорса?