⚓ Геолокация хакеров, взламывающих по SSH в режиме реального времени |

⚓ Геолокация хакеров, взламывающих по SSH в режиме реального времени

Мануал

Пока вы читаете эту статью, совершаются тысячи, если не сотни тысяч кибератак.

Некоторые из них более изощренные, чем другие: от троянов, попыток фишинга, заражения вредоносным ПО до атак ботнетов (также известных как 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, его обслуживание и администрирование является ключевым фактором в любой системе.

см. также:

 

Пожалуйста, не спамьте и никого не оскорбляйте. Это поле для комментариев, а не спамбокс. Рекламные ссылки не индексируются!
Добавить комментарий

  1. серж

    не совсем понятно что такое Node

    Ответить
    1. cryptoparty автор

      nodejs

      Ответить