OSSIM传感器Agent传送机制初探

OSSIM Agent的主要职责是收集网络上存在的各种设备发送的所有数据,然后按照一种标准方式有序发给OSSIM Server,Agent收集到数据后在发送给Server之前要对这些数据进行归一化处理,本文主要就如何有序发送数据与如何完成归一化进行讨论。

OSSIM传感器在通过GET框架实现OSSIM代理和OSSIM服务器之间通信协议和数据格式的之间转换。下面我们先简要看一下ossim-agent脚本:

#!/usr/bin/python -OOtimportsyssys.path.append('/usr/share/ossim-agent/')sys.path.append('/usr/local/share/ossim-agent/')fromossim_agent.AgentimportAgentagent = Agent()agent.main()

这里需要GET作为OSSIM代理向OSSIM服务器输送数据。实现紧密整合所需的两个主要操作是“生成”(或)OSSIM兼容事件的“映射Mapping”)和此类数据向OSSIM的“传输”服务器。它负责此类操作的GET框架的两个组件是EventHandler和Sender Agent,如图1所示。

图1 将Get框架内容集成到OSSIM

Event Handler的主要任务是映射数据源插件采集的事件到SIEM实例警报的OSSIM标准化事件格式。为了执行这样的过程,原始消息经历由RAW LOG转换为现有归一化数据字段格式的一个转变;在上图中我们将这些机制表示为“归一化Normalization”和“OSSIM消息”。部分日志归一化代码:

from Logger import Loggerfrom time import mktime, strptimelogger = Logger.loggerclassEvent:EVENT_TYPE ='event'EVENT_ATTRS = ["type","date","sensor","interface","plugin_id","plugin_sid","priority","protocol","src_ip","src_port","dst_ip","dst_port","username","password","filename","userdata1","userdata2","userdata3","userdata4","userdata5","userdata6","userdata7","userdata8","userdata9","occurrences","log","data","snort_sid",# snort specific"snort_cid",# snort specific"fdate","tzone"]def__init__(self):self.event = {}self.event["event_type"] =self.EVENT_TYPEdef__setitem__(self, key, value):ifkeyinself.EVENT_ATTRS:self.event[key] =self.sanitize_value(value)ifkey =="date":# 以秒为单位self.event["fdate"]=self.event[key]try:self.event["date"]=int(mktime(strptime(self.event[key],"%Y-%m-%d %H:%M:%S")))except:logger.warning("There was an error parsing date (%s)"%\                        (self.event[key]))        elif key !='event_type':            logger.warning("Bad event attribute: %s"% (key))def__getitem__(self, key):returnself.event.get(key, None)# 事件表示def__repr__(self):        event =self.EVENT_TYPEforattrinself.EVENT_ATTRS:ifself[attr]:                event +=' %s="%s"'% (attr,self[attr])returnevent +"\n"# 返回内部哈希值defdict(self):returnself.eventdefsanitize_value(self, string):returnstr(string).strip().replace("\"","\\\"").replace("'","")classEventOS(Event):EVENT_TYPE ='host-os-event'EVENT_ATTRS = ["host","os","sensor","interface","date","plugin_id","plugin_sid","occurrences","log","fdate",    ]classEventMac(Event):EVENT_TYPE ='host-mac-event'EVENT_ATTRS = ["host","mac","vendor","sensor","interface","date","plugin_id","plugin_sid","occurrences","log","fdate",    ]classEventService(Event):EVENT_TYPE ='host-service-event'EVENT_ATTRS = ["host","sensor","interface","port","protocol","service","application","date","plugin_id","plugin_sid","occurrences","log","fdate",    ]classEventHids(Event):EVENT_TYPE ='host-ids-event'EVENT_ATTRS = ["host","hostname","hids_event_type","target","what","extra_data","sensor","date","plugin_id","plugin_sid","username","password","filename","userdata1","userdata2","userdata3","userdata4","userdata5","userdata6","userdata7","userdata8","userdata9","occurrences","log","fdate",    ]classWatchRule(Event):EVENT_TYPE ='event'EVENT_ATTRS = ["type","date","fdate","sensor","interface","src_ip","dst_ip","protocol","plugin_id","plugin_sid","condition","value","port_from","src_port","port_to","dst_port","interval","from","to","absolute","log","userdata1","userdata2","userdata3","userdata4","userdata5","userdata6","userdata7","userdata8","userdata9","filename","username",    ]classSnort(Event):EVENT_TYPE ='snort-event'EVENT_ATTRS = ["sensor","interface","gzipdata","unziplen","event_type","plugin_id","type","occurrences"]

日志编码代码:

importthreading, timefromLoggerimportLoggerlogger = Logger.loggerfromOutputimportOutputimportConfigimportEventfromThresholdimportEventConsolidationfromStatsimportStatsfromConnProimportServerConnProclassDetector(threading.Thread):def__init__(self, conf, plugin, conn):self._conf = conf        self._plugin = plugin        self.os_hash = {}        self.conn = conn        self.consolidation = EventConsolidation(self._conf)        logger.info("Starting detector %s (%s).."% \                    (self._plugin.get("config","name"),                    self._plugin.get("config","plugin_id")))        threading.Thread.__init__(self)def_event_os_cached(self, event):ifisinstance(event, Event.EventOS):importstring            current_os = string.join(string.split(event["os"]),' ')            previous_os = self.os_hash.get(event["host"],'')ifcurrent_os == previous_os:returnTrueelse:# 失败并添加到缓存self.os_hash[event["host"]] = \                    string.join(string.split(event["os"]),' ')returnFalsedef_exclude_event(self, event):ifself._plugin.has_option("config","exclude_sids"):            exclude_sids = self._plugin.get("config","exclude_sids")ifevent["plugin_sid"]inConfig.split_sids(exclude_sids):                logger.debug("Excluding event with "+\"plugin_id=%s and plugin_sid=%s"%\                    (event["plugin_id"], event["plugin_sid"]))returnTruereturnFalsedef_thresholding(self):self.consolidation.process()def_plugin_defaults(self, event):# 从配置文件中获取默认参数ifself._conf.has_section("plugin-defaults"):# 1) 日期default_date_format = self._conf.get("plugin-defaults","date_format")ifevent["date"]isNoneanddefault_date_formatand\'date'inevent.EVENT_ATTRS:                event["date"] = time.strftime(default_date_format,                                              time.localtime(time.time()))# 2) 传感器default_sensor = self._conf.get("plugin-defaults","sensor")ifevent["sensor"]isNoneanddefault_sensorand\'sensor'inevent.EVENT_ATTRS:                event["sensor"] = default_sensor# 3) 网络接口default_iface = self._conf.get("plugin-defaults","interface")ifevent["interface"]isNoneanddefault_ifaceand\'interface'inevent.EVENT_ATTRS:                event["interface"] = default_iface# 4) 源IPifevent["src_ip"]isNoneand'src_ip'inevent.EVENT_ATTRS:                event["src_ip"] = event["sensor"]# 5) 时区default_tzone = self._conf.get("plugin-defaults","tzone")ifevent["tzone"]isNoneand'tzone'inevent.EVENT_ATTRS:                event["tzone"] = default_tzone# 6) sensor,source ip and dest != localhostifevent["sensor"]in('127.0.0.1','127.0.1.1'):                event["sensor"] = default_sensorifevent["dst_ip"]in('127.0.0.1','127.0.1.1'):                event["dst_ip"] = default_sensorifevent["src_ip"]in('127.0.0.1','127.0.1.1'):                event["src_ip"] = default_sensor# 检测日志的类型ifevent["type"]isNoneand'type'inevent.EVENT_ATTRS:            event["type"] ='detector'returneventdefsend_message(self, event):ifself._event_os_cached(event):returnifself._exclude_event(event):return#对于一些空属性使用默认值。event = self._plugin_defaults(event)# 合并之前检查ifself.connisnotNone:try:                self.conn.send(str(event))except:                id = self._plugin.get("config","plugin_id")                c = ServerConnPro(self._conf, id)                self.conn = c.connect(0,10)try:                    self.conn.send(str(event))except:returnlogger.info(str(event).rstrip())elifnotself.consolidation.insert(event):            Output.event(event)        Stats.new_event(event)defstop(self):#self.consolidation.clear()pass#在子类中重写defprocess(self):passdefrun(self):self.process()classParserSocket(Detector):defprocess(self):self.process()classParserDatabase(Detector):defprocess(self):self.process()

… …

从上可以看出,传感器的归一化主要负责对每个LOG内数据字段进行重新编码,使其生成一个全新的可能用于发送到OSSIM服务器的完整事件。为达成这种目的GET框架中包含了一些特定的功能,以便将所有的功能转换需要BASE64转换的字段。“OSSIM消息”负责填充GET生成的原始事件中不存在的字段。所以上面讲的plugin_id、plugin_sid是用来表示日志消息来源类型和子类型,这也是生成SIEM事件的必填字段。为事件格式完整性考虑,有些时候在无法确认源或目标IP时,系统默认会采用0.0.0.0来填充该字段。

注意:这种必填字段我们可利用phpmyadmin工具查看OSSIM的MySQL数据库。

Sender Agent负责完成下面两个任务:

发送由GET收集并由事件格式化的事件发送到OSSIM服务器,这项任务由Event Hander创建的消息组成消息队列发送到消息中间件实现,时序图如图2所示。

图2 序列图: 从安全探测器的日志转换到OSSIM服务器事件

2)管理GET框架和OSSIM服务器之间的通信,通信端口为TCP 40001通过双向握手实现。归一化原始日志是规范化过程的一个重要环节,OSSIM在归一化处理日志的同时保留了原始日志,可用于日志归档,提供了一种从规范化事件中提取原始日志的手段。

经过归一化处理的EVENTS,存储到MySQL数据库中,如图3所示。接着就由关联引擎根据规则、优先级、可靠性等参数进行交叉关联分析,得出风险值并发出各种报警提示信息。

图3 OSSIM平台日志存储机制

接下来我们再看个实例,下面是一段Apache、CiscoASA以及SSH的原始日志,如图4、图5、图6所示。

Apache插件中的正则表达式:

[0001 - apache-access] 访问日志

event_type=eventregexp=((?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(:(?P\d{1,5}))? )?(?P\S+) (?P\S+) (?P\S+) \[(?P\d{2}\/\w{3}\/\d{4}:\d{2}:\d{2}:\d{2})\s+[+-]\d{4}\] \"(?P[^\"]*)\" (?P\d{3}) ((?P\d+)|-)( \"(?P[^\"]*)\" \"(?P[^\"]*)\")?$src_ip={resolv($src)}dst_ip={resolv($dst)}dst_port={$port}date={normalize_date($date)}plugin_sid={$code}username={$user}userdata1={$request}userdata2={$size}userdata3={$referer_uri}userdata4={$useragent}filename={$id}

[0002 - apache-error] 错误日志

event_type=eventregexp=\[(?P\w{3} \w{3} \d{2} \d{2}:\d{2}:\d{2} \d{4})\] \[(?P(emerg|alert|crit|error|warn|notice|info|debug))\] (\[client (?P\S+)\] )?(?P.*)date={normalize_date($date)}plugin_sid={translate($type)}src_ip={resolv($src)}userdata1={$data}

图4 Apache原始日志

图5 一条Cisco ASA 原始日志

图6 Cisco ASA 事件分类

通过过OSSIM归一化处理后的实际再通过Web前端展现给大家方便阅读的格式。归一化处理后的事件和原始日志的对比方法我们在《开源安全运维平台OSSIM疑难解析:入门篇》一书中还会讲解。而在图7所示的例子当中,仅使用了Userdata1和Userdata2,并没有用到Userdata3~Userdata9这些是扩展位,主要是为了预留给其他设备或服务使用,这里目标地址会标记成IP地址的形式,例如:Host192.168.11.160。实际上归一化处理这种操作发生在系统采集和存储事件之后,关联和数据分析之前,在SIEM工具中把采集过程中把数据转换成易读懂的格式,采用格式化的数据,能更容易理解。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容