OSSIM开源安全信息管理系统(十三)

2021SC@SDUSC




本周内容是上周的延续,在本周的文章里,完成了对 OSSIM 安全信息管理系统的 Frameworkd 模块的所有源码以及实现原理的分析。同时完成了 OSSIM 的日志分析部分的简要概述与分析。下周开始,将对 OSSIM 的关联分析机制进行源码分析。

一、OSSIM frameworkd 源码分析

1、OssimDB.py

这里主要实现的功能就是在 Framework 模块中有关数据库相关的操作

主要的类就是 OssimDB 类,这个类的主要实现如下:

首先导入所需的相关 python 自带模块

import sys
import time
from threading import Lock

try:
    import MySQLdb
    import MySQLdb.cursors
    import _mysql_exceptions
except ImportError:
    sys.exit("You need python MySQLdb module installed")

然后导入其他自定义的模块

from Logger import Logger

接下来就是具体类函数

__init__(self, host, database, user, password)

构造函数,初始化类相关属性

def __init__(self, host, database, user, password):
    self._host = host
    self._database = database
    self._user = user
    self._password = ""
    if password is not None:
        self._password = password
    self._conn = None
    self._connected = False
    self._mutex = Lock()

connect(self)

数据库连接函数

def connect(self):
    #先判断一下是否已经连接数据库
    if self._connected:
        return

调用 MySQLdb.connect 进行数据库连接相关操作,要求连接失败次数不能超过五次

    self._connected = False
	attempt = 1
   
	while not self._connected and attempt <= 5:
    try:
    	self._conn = MySQLdb.connect(host=self._host, user=self._user, passwd=self._password,db=self._database, cursorclass=MySQLdb.cursors.DictCursor)
        self._conn.autocommit(True)
        self._connected = True
    except Exception, e:
        logger.info("Can't connect to database (%s@%s) error: %s" % (self._user, self._host, e))
        logger.info("Retry in 2 seconds...")
        attempt += 1
        time.sleep(2)
return self._connected

exec_query(self, query)

该函数的主要功能为执行数据库相关查询工作,仅执行有返回结果的 SQL 语句

传入参数为查询语句,返回值为查询的结果

def exec_query(self, query):
    self._mutex.acquire()
    arr = [] #返回的查询结果
    max_retries = 3  #最大尝试次数
    retries = 0 #尝试次数
    retry_query = False
    cursor = None  
    continue_working = True

先判断一下是否已经连接数据库,如果没有连接则调用刚才分析的self.connect()进行数据库连接,然后执行数据库查询操作,根据尝试次数来判断是否继续执行

while continue_working:
	try:
		#先判断一下是否已经连接数据库,如果没有连接则调用刚才分析的self.connect()进行数据库连接
        if not self._connected or self._conn is None:
        	self.connect()

执行数据库查询操作

cursor = self._conn.cursor()
cursor.execute(query)
arr = cursor.fetchall()
continue_working = False

直接使得retries大于max_retries,然后在后面的代码中就会终止while循环,结束查询

retries = max_retries + 1
cursor.close()
#异常捕获
except _mysql_exceptions.OperationalError, (exc, msg):
	logger.debug('MySQL Operational Error executing query:\n----> %s \n----> [(%d, %s)]' % (query, exc, msg))
    if exc != 2006:
    	logger.error('MySQL Operational Error executing query')
        self.__close()
except Exception, e:
        logger.error('Error executing query:\n----> [{0}]'.format(e))
        self.__close()

超过最大次数则停止while循环

 if retries >= max_retries:
	continue_working = False
else:
    retries += 1
    time.sleep(1)
self._mutex.release()

if not arr:
    arr = []
        
return arr

execute_non_query(self, query, autocommit=False)

该函数的主要功能是用于执行没有查询结果返回的语句。
变量 autocommit 的值表示是否自动提交,默认情况下,这个值设为 true,即自动提交。
在执行完 SQL 语句后,if 判断是否是自动提交,如果不是自动提交,再调用函数 self._conn.commit() 实现提交。
同样也设置了最多尝试次数 max_retries ,其值初始为3,用于判断是否继续进行 while 循环。
返回值 returnvalue 表示是否执行成功,成功返回 true,否则返回 false

    def execute_non_query(self, query, autocommit=False):
        self._mutex.acquire()
        max_retries = 3
        retries = 0
        retry_query = False
        cursor = None
        continue_working = True
        returnvalue = False
        self._conn.autocommit(autocommit)
        while continue_working:
            try:
                if not self._connected or self._conn is None:
                    self.connect()
                cursor = self._conn.cursor()
                cursor.execute(query)
                if not autocommit:
                    self._conn.commit()
                continue_working = False
                retries = max_retries + 1
                cursor.close()
                returnvalue = True
            except _mysql_exceptions.OperationalError, e:
                logger.error('Operation Error:\n%s\n[%s]' % (query, e))
                self._conn.rollback()
                self.__close()
                returnvalue = False
            except Exception, e:
                logger.error('Error executing query:\n %s \n [%s]' % (query, e))
                self._conn.rollback()
                self.__close()
                returnvalue = False
            if retries >= max_retries:
                continue_working = False
            else:
                retries += 1
                time.sleep(1)
        self._mutex.release()
        return returnvalue

def __close(self)

最后一个函数的主要功能是调用self._conn.close()函数,断开数据库连接

    def __close(self):
        if self._conn:
            try:
                self._conn.close()
            except _mysql_exceptions.ProgrammingError as err:
                logger.error("Error while closing the connection: {}".format(err))
            except AttributeError as err:
                logger.info("Trying to close the connection to mysql: {}".format(err))
            except Exception as err:
                logger.error("Can't close the connection to the database: {}".format(err))
            finally:
                self._conn = None
                self._connected = False
        else:
            logger.info("Trying to execute close method on connection which doesn't exist")


二、OSSIM 日志收集与分析

3、日志中能看出什么

数据是企业的财富,同样日志蕴含着丰富的信息。Ping 命令是再平常不过的网管工具了,使用 ICMP 来 ping 对方主机,就知道是否存活。但在故障时,能够 ping 通对方的网络接口,不代表机器正常,也有可能系统已出现故障,这样就需要从日志中获取详细信息。日志不仅告诉你主机是否存活,还能够告诉你主机上运行应用程序的状态,以及它们在做什么,在真正宕机前发出各种日志报警信息。下面是一个主机遭受 SSH 攻击的日志,然后我们对其信息进行分析 :

Sep 17 07:00:02 webserver.com:sshd[20392]:Failed password for illegal user test from 192.168.11.2 port 33783 ssh2

从该日志可以看出,用户 test 登录失败,而且他是非法用户,这条消息表明,一个攻击者使用扫描器探测服务器。试图利用字典里的用户进行试探,但攻击还没成功。

当然,一旦攻击成功,黑客接管主机后完全有可能删除这条日志(为了避免日志被删除,可以将这条日志发送到远程的日志收集服务器集中存储)。接着看下面的日志。

Sep 17 10:09:10 webserver.com adduser [2341]: new user: name=test,uid=0,gid=0,home=/root/cgi,shell=/bin/bash

很显然,从这条消息看出,系统添加了系统管理员账户名称为 test,用户 ID 为 0 (相当于 root 权限用户)。

用户行为会被日志记录下来,比如用户登录、注销和启动进程等,系统审计工具能提供细颗粒的日志记录,而且这种日志一旦被系统记录并收集之后,就不会因系统故障恢复正常而被修改,也就是说日志记录了系统从正常→故障→正常的完整过程,由于每条日志都有时间戳,它们提供了每个事件的时间顺序,日志不仅告诉我们发生了什么,还告诉我们事件发生的时间和顺序,而且日志发送到日志服务器后也提供了独立的日志收集仓库,一旦原始主机上的日志遭到破坏(比如篡改和删除),独立的日志搜集服务就是可靠的日志附加来源。

例如,在 Linux 中普通用户通过 sudo 来执行管理员命令,无意间删除了重要的系统文件而导致故障,在取证时,sudo日志提供了取证日志。又如,用户张三在很短的时间内,从地域跨度很大的两个不同的位置,用 SSH 方式登录系统,这种异常行为就非常可疑。


4、日志分析的基本工具及缺陷

在 Unix/Linux 中内置了强大的命令行日志分析工具,例如 grep、awk、tail、sed 等,用它们分析简单的日志没有问题,然而随着日志尺寸的不断增大,这种分析工具也暴露出一些问题:

(1)不同日志之间无法关联,用人工分析法无法同时分析来自不同网络设备的日志,更无法搞清楚整个网络攻击是如何发生发展的。

(2)在超过 1 GB大小的日志中检索信息非常困难。

(3)Grep 这样的工具只能对明确的关键字信息检索,无法生成统计趋势和异常行为。

以上问题都可以在 OSSIM 系统的日志分析平台中得到解决。


5、海量日志收集方式

一个海量日志收集系统,首先要考虑采用什么样的日志采集模型。一般有两种方式,推送(PUSH)方式和拉(PULL)方式。我们常见的 Syslog、Rsyslog 就是采用推送(PUSH)方式,再比如 Facebook、Scribe 也采用了 PUSH 方式,这种方式要求日志收集存储容量大,至少要大于峰值时的数据生成量,否则主动推送过来的数据将来不及处理,另外如果设置不正确,会收到虚假的 syslog 信息,所以必须了解哪些设备启用了syslog。而拉(PULL)方式的日志收集并不常用。




上一篇:OSSIM开源安全信息管理系统(十二)
下一篇:

你可能感兴趣的:(2021SC@SDUSC,安全,运维,安全架构)