Logger для OSSIM. Как сделать бесплатно.

Одним из недостатков Open Source версии AlienVault OSSIM является отсутствие логгера. Он есть только в версии Enterprise, которая не всем по карману. Оказывается этот недостаток можно устранить очень легко и, главное, очень эффективно. В самом OSSIM для этого уже почти всё есть, надо только научиться использовать и чуть-чуть добавить. А поможет нам в этом MongoDB и десяток строк кода (ну, может два десятка, лень пересчитывать).

Немного теории

OSSIM состоит из двух основных компонент: агент и сервер. Агент занимается обработкой логов, поступающих от разных источников, и приведением их к единому формату. Из записей сырых логов он создает объект класса Event, который отдает серверу. Объект Event в одном из своих атрибутов содержит и строку сырого лога от источника. Передачей события серверу занимается класс OutputPlugins, кот которого лежит в /usr/share/alienvault/ossim-agert/Output.py. Так вот, если мы почитаем этот код, мы увидим, что вывод данных предусмотрен не только на сервер, есть и другие варианты. OSSIM «из коробки» может выводить данные в текстовый файл, в файл в формате csv, в SQL базу данных (в любую, которую поддерживает модуль питона adoDB). Эти опции можно просто включить в файле конфигурации агента в /etc/ossim/agent/config.cfg. Различные «выводы» можно включать одновременно. Таким образом вы можете включить параллельную передачу событий внешнему логгеру.

А вот здесь уже возникает другой вопрос: что выбрать для хранения логов? Я подумал, что лучше использовать базу данных. Так будет удобнее работать с записями. Теперь переходим к экспериментальной части.

Немного экспериментов

Первым делом я решил отправить логи во внешнюю базу MySQL. После двух дней тестирования под нагрузкой и малоуспешных попыток справиться с ошибкой Lost connection during query, я понял что мой кун-фу не достаточно хорош для того, чтобы заставить сервер MySQL принимать данные из системы, выдающей немногим более двух миллионов событий в сутки. Я отступил с позором. Если не перевелись богатыри на земле Русской, пусть они сразятся с этим змием.

Позор поражения вверг меня в задумчивость. Озарение пришло минут через десять. Я решил, что реляционная СУБД в принципе может быть не лучшим решением для хранения логов. Надо посмотреть на что-нибудь для big data. Mongo — вот что должно сработать. И сработало. Сервер MongoDB, запущенный в среде Debian 8 на VirtualBox на скромном офисном десктопе, работает как часы. Там старенькая Mongo 2.4 из стандартного репозитария Debian. Для рабочей системы, наверно, возьму Mongo 3.2.

События пишутся. Поиск работает великолепно, в том числе по русскому тексту в логах. Ресурсов эта штука практически не ест. И вы, конечно, знаете, но не лишне напомнить, что Mongo поддерживает текстовый поиск с учетом морфологии и для русского языка тоже.

Изменения в коде OSSIM

Кое-что я дописал. Совсем чуть-чуть. Прежде всего я добавил в Output.py код своего класса для создания объекта «вывод». Сначала в секции GLOBAL IMPORTS.

# GLOBAL IMPORTS
#
import os
import re
import string
import sys
import uuid
from pymongo import MongoClient
from bson import BSON

Здесь добавлены две последние строки. Понятно зачем. И сам класс выглядит вот так:

class OutputESGuard(OutputPlugins):


    def __init__(self, conf):

        logger.info("Added ESGuard output")
        logger.debug("OutputDB options: %s" % (conf.hitems("output-esguard")))

        self.conf = conf

        self.dbhost = self.conf.get('output-esguard', 'host')
        self.dbport = self.conf.get('output-esguard', 'port')
        self.dbschema = self.conf.get('output-esguard', 'base')
        self.dbuser = self.conf.get('output-esguard', 'user')
        self.dbpass = self.conf.get('output-esguard', 'pass')


        mongodbURI = "mongodb://" + self.dbuser + ":" + self.dbpass + "@" + self.dbhost + ":" + self.dbport + "/" + self.dbschema
        try :
            self.conn = MongoClient(mongodbURI)
            self.log_db = self.conn[self.dbschema]
            self.event_coll = self.log_db['logger']
            self.activated = True
        except Exception, e:
            logger.error(": Error connecting to Mongodb %s" % (e))


    def event(self, e):          

        if e["event_type"] == "event"  and self.activated:            

            try :
                self.event_coll.insert_one(BSON.decode(e.to_bson_esguard()))
            except :
                logger.error(": Error insert data to mongodb log_coll. Plugin_id is %s. Retry as binary" % (e['plugin_id']))  
                self.event_coll.insert_one(BSON.decode(e.to_bson()))


    def shutdown(self):
        logger.info("Closing ESGuard output ..")
        self.conn.close()
        self.activated = False

Здесь следует пояснить код метода event. Именно он занимается передачей события на сервер Mongo. Я поправил класс Event (его код лежит в /usr/share/alienvault/ossim-agert/Event.py). Добавил туда метод to_bson_esguard(). На самом деле это копия имеющегося там метода to_bson с одним отличием. В стандартном методе атрибут log (именно в нем содержится сырой лог источника) объявляется как бинарный и записывается в Base64. А мне этого совсем не надо. Мне там нужен текст в utf8. Именно это я и поменял.

Но есть одна маленькая засада. Дело в том, что не все плагины пишут в payload текст. Есть по крайней мере одна негодяйка Suricata, которая может поместить туда действительно бинарные данные. Она это делает не всегда. Обычно тоже текст, но иногда чисто поток байтов. При попытке сунуть серверу бинарник в поле, описанном как текст, он возвращает ошибку парсера utf8. Не мудрствуя лукаво, я включил передачу в блок try и, при возникновении ошибки, перекодирую event, используя стандартный метод to_bson(), и повторно отправляю на сервер. Это, быть может, не оптимально, но просто.

Еще в Outup.py я добавил в код класса Output метод add_esguard_output:

    @staticmethod
    def add_esguard_output(conf):
        if Output.esguard_output is False:
            Output._outputs.append(OutputESGuard(conf))
            Output.esguard_output = True

И наконец я приписал в Agent.py, в секцию чтения и обработки файла конфигурации, проверку наличия в нем раздела [output-esguard]

    def init_output(self):
        '''
            Initialize Outputs
        '''

        printEvents = True

        if self.conf.has_section("output-properties"):
            printEvents = self.conf.getboolean("output-properties", "printEvents")
        Output.print_ouput_events(printEvents)

        if self.conf.has_section("output-plain"):
            if self.conf.getboolean("output-plain", "enable"):
                Output.add_plain_output(self.conf)

        # output-server is enabled in connect_server()
        # if the connection becomes availble

        if self.conf.has_section("output-csv"):
            if self.conf.getboolean("output-csv", "enable"):
                Output.add_csv_output(self.conf)

        if self.conf.has_section("output-db"):
            if self.conf.getboolean("output-db", "enable"):
                Output.add_db_output(self.conf)

        if self.conf.has_section("output-esguard"):
            if self.conf.getboolean("output-esguard", "enable"):
                Output.add_esguard_output(self.conf)

В самом файле конфига (/etc/ossim/agent/config.cfg) новая секция выглядит вот так:

[output-server]
enable=True
ip=172.17.2.10
port=40001
send_events=True

[output-esguard]
enable=False
host=your_mongoDB_host_ip
port=27017
base=ossim
user=your_mongoDB_username
pass=your_mongoDB_userpassword

Вот и всё.
Весь код в совокупности лежит в моём репозитарии на bitbucket только пока не в главной ветке, надо заглянуть в ветку v.-2.1.1.

На досуге сделаю какой-нибудь веб-интерфейс к логгеру. Пока я пользуюсь халявным вьювером для MongoDB их в Инете много. Разумеется, вы можете своим способом решить проблему с логгером, я всего лишь хотел сказать, что она может быть решена очень просто.

Реклама

Logger для OSSIM. Как сделать бесплатно.: Один комментарий

  1. Уведомление: OSSIM. Обзор. | ESGUARDIAN

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

w

Connecting to %s