Bro

目录

Bro简介
Bro特点
Bro基本架构
Bro内部架构
Dynamic Protocol Detection(DPD)
Bro集群部署
Bro脚本
Bro日志记录
Bro http日志中记录额外字段
提升Bro抓包性能
Bro从一台机器的多个网卡同时抓取流量
实际使用中解决的问题
安装部署
参考

Bro简介

Bro是一款被动的开源流量分析器。它主要用于对链路上所有深层次的可疑行为流量进行一个安全监控,其支持在安全域之外进行大范围的流量分析。更通俗一点,Bro是一款集成了TCPDUMP(抓包),WIRESHARK(流量分析),SNORT(×××检测),SYSLOG(日志记录),PYTHON/PERL(有灵活抽象的数据结构,支持脚本自定义处理)功能的网络流量分析利器。

Bro特点

  • 部署

    • 在Unix-like系统上运行
    • 基于端口或者网络分流器的被动流量分析
    • 使用libpcap的抓包,也支持性能更好的PF_RING抓包
    • 支持实时分析和离线分析
    • 支持集群化部署
    • 单机或者集群化部署都是使用统一的管理工具
    • 使用BSD开源协议
  • 分析
    • 离线分析也支持日志记录
    • 应用层协议支持Port-independent分析
    • 支持多种应用层协议,包含DNS,FTP,HTTP,IRC,SMTP,SSH,SSL等
    • 能够分析应用层协议交换的文件内容
    • 全IPv6支持
    • 隧道检测与分析,包含Ayiya, Teredo, GTPv1等
    • 分析协议期间会进行完整性检测
    • 支持IDS风格的正则匹配
  • 脚本语言
    • 能完成任意分析任务的语言
    • 基于事件的编程
    • 特定于域的数据类型,如IP地址(透明地处理IPv4和IPv6)、端口号和计时器
    • 支持跟踪和管理网络状态
  • 接口
    • 默认输出为结构化的ASCII日志
    • 可以使用ElasticSearch等存储数据(通过收集json日志或者es plugin)
    • 将外部的输入实时整合分析
    • Bro提供扩展的C库,让事件能与外部程序交换传输
    • 通过脚本可以触发任意外部处理逻辑

Bro部署架构

  • 部署方式和其它NIDS相似
  • 检测出入的所有流量
  • 采用被动检测方式

部署架构图:
Bro浅析_第1张图片

Bro基本架构

Bro浅析_第2张图片

从官方给的架构图来看我们发现Bro主要有两大组件:

  • 事件引擎:它将传入的数据包流转化为一系列高级事件。这些事件反映了网络活动,即描述了我们所看到的,但不关心其中的问题或者它是否重要。例如,连接上的一个HTTP请求转换为对应的http_request事件,该http_request事件会包含记录相关的IP地址和端口、被请求的URI和正在使用的HTTP版本等信息。然而,该事件并不会进行进一步的安全或者检测操作,例如判断该URI是否对应于一个已知的恶意软件站点,判断URI中是否有命令注入,判断URI中是否有敏感词等一些其它的自定义行为等,要做这些异常检测需要依赖Bro script来完成。
    ps:事件引擎采用c/c++编译,性能很好,了解具体的事件种类可以查看如下链接(查看以event.bif.bro结尾的脚本):
    https://www.bro.org/sphinx/script-reference/scripts.html

  • 脚本解释器:脚本解释器执行一组用Bro的自定义脚本语言编写的事件处理程序,即执行Bro script。这些脚本可以定义event handler编写站点的安全策略,例如解决如上事件引擎中抛出来的自定义检测等问题,即当检测到指定类型的问题时采取指定的行动。更广泛地说,它们可以从输入流中派生任何想要的属性和统计信息。Bro的语言具有广泛的领域特定类型和支持功能,至关重要的是它允许脚本随时间保持状态,使它们能够跟踪和关联它们在连接和主机边界上观察到的事物的演化。Bro脚本可以生成实时警报,也可以根据需要执行任意外部程序,例如,触发对×××的主动响应。

如上官网给的架构图是不是特别简单,在实际情况下一个完整请求的通常要经过多个事件和对应的脚本去处理。我们以一个http请求大概来描述一下:
Bro浅析_第3张图片

Bro内部架构

Bro浅析_第4张图片

Dynamic Protocol Detection(DPD)

Port-based Protocol Analysis

了解DPD之前,我们先了解一下Port-based Protocol Analysis。这是传统NIDS的检测协议的方式,根据端口来判断使用的是哪一种协议。如80端口认为是http协议,443端口认为是https协议等。这种方式有点是简单,但是缺点也是显而易见,这种方式像ftp协议也是分析不了的。

DPD简介

Bro使用动态协议检测框架,我们将分析器树与每个连接关联起来。此树可以包含任意数量的各种分析器,并且可以在连接的整个生命周期内进行修改。即我们可以动态启用/禁用分析器。它提供了两个功能:

  • 可以独立于端口执行协议分析。通过使用一组匹配典型协议对话的签名,Bro通过查看payload以匹配正确的分析器。当这样的签名匹配时,它将打开相应的分析器。
  • 当分析程序明显地解析错误的协议时,我们可以关闭它们。这允许我们使用松散的协议签名,如果有解析错误,可以并行多个分析程序分析。

DPD协议签名

有固定格式协议协议通过特征提取即可识别,而对于无固定格式协议,无法采用通用方法提取协议指纹,而只能针对特定协议特定分析提取协议指纹的可能性。所幸的是,属于该类型的应用层协议很少。因此,对于这种情形可以单独对待。如下为http协议签名样例:

signature dpd_http_client {
  ip-proto == tcp
  payload /^[[:space:]]*(GET|HEAD|POST)[[:space:]]*/
  tcp-state originator
}

signature dpd_http_server {
ip-proto == tcp
payload /^HTTP\/[0-9]/
tcp-state responder requires-reverse-signature dpd_http_client
enable "http"
}

Bro 集群架构

集群架构简介

Bro浅析_第5张图片

  • Frontend:前端是一个分离的硬件设备或主机技术,能够将流量划分为许多的stream或flow。并且使用基于ip地址的hash算法给后端Worker转发请求。

  • Worker:嗅探网络流量并对重新组装的数据包进行协议分析的进程。集群的大部分工作都发生在Worker身上,由于所有的协议解析和大多数分析都将在这里进行,所以推荐使用大内存和多CPU的机器。由于几乎所有的日志都会发送到Manger,所以磁盘很小即可。

  • Proxy:代理是一个管理同步状态的Bro进程。变量可以在连接的进程之间自动同步。Proxy帮助Worker直接共享信息,而不需要Worker彼此直连。同步的信息有完整的主机或者服务列表(例如这台主机或这个服务被标识为需要执行完整的TCP握手)或者共享某个连接需要应用的协议分析器等。

  • Manager:进程有两个主要任务,即从该集群的其他节点接收日志消息以及notices信息。所有数据会输出到一个单独的日志,而不是许多离散的日志。管理器还利用机会去复制通知,并且它有能力这样做,因为它是通知的阻塞点,以及通知如何被处理为操作(例如,电子邮件、分页或阻塞)。管理端进程首先由BroControl启动,仅开放特定端口等待连接,他不会初始任何对其他集群的连接,一旦worker启动并连接到Manager,日志和notices信息将开始从工作端抵达管理端进程。

Berkeley Lab Cyber Security Team(伯克利实验室网络安全团队)Bro集群部署规模

分析流量:100g
使用的机器数量:5台物理机
每台机器配置:128g内存,12核心cpu,120g SSD盘+1T机械硬盘
部署情况:每台机器部署一个Proxy和10个Worker
参考地址:https://commons.lbl.gov/display/cpp/100G+Intrusion+Detection

Bro脚本

需求:如果http的get请求的uri中包含passwd敏感词则报警。
脚本如下:

event http_request(c: connection, # Connection. 
                                method: string, # HTTP method.
                                original_URI: string, # Requested URL.
                                unescaped_URI: string, # Decoded URL.
                                version: string) # HTTP version.
{
    if ( method == "GET" && unescaped_URI == /.*passwd/ )
        NOTICE(...); # Alarm.
}

Bro日志记录

默认Bro输出结构化的ASCII日志到文件中,通过配置也可以使输出日志的格式为json。默认情况下,Bro会记录http协议相关的数据到http.log中。http.log默认的格式如下:

#separator \x09
#set_separator  ,
#empty_field    (empty)
#unset_field    -
#path   http
#open   2018-05-17-23-00-00
#fields ts  uid id.orig_h   id.orig_p   id.resp_h   id.resp_p   trans_depth method  host    uri referrer    version user_agent  request_body_len    response_body_len   status_code status_msg  info_code   info_msgtags    username    password    proxied orig_fuids  orig_filenames  orig_mime_types resp_fuids  resp_filenames  resp_mime_types
1526569221.715086   Cjtygm3Q2270olTjWa  116.55.236.99   39084   192.168.2.23    80  1   GET m.sda.cn    /   -   1.1 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; NetworkBench/8.0.1.332-6700490-2725395) 0   10431   200 OK  -   -   (empty) -   -   CDN-SRC-IP -> 116.54.1.107  -   -   -   Fp0zSeJlVZ10p7ZD2   -   text/html

Bro http日志中记录额外字段

参考链接:https://github.com/lishengjia/bro_scripts

提升Bro抓包性能

传统抓包

默认Bro使用libpcap抓包。而传统的libpcap抓包方式, CPU的多数时间都被用在把网卡接收到的数据包经过内核的数据结构队列发送到用户空间的过程中。也就是说是从NIC-->kernel,kernel-->用户空间(这两个步骤数据包的拷贝花去了大量CPU时间),然后应用程序在用户空间读取数据包。而这种方式会导致大量的中断和kernel到用户空间的数据切换,从而造成大量的cpu开销。

PF_RING抓包

PF_RING是Luca研究出来的基于Linux内核级的高效数据包捕获技术。简单来说PF_RING 是一个高速数据包捕获库,通过它可以实现将通用 PC 计算机变成一个有效且便宜的网络测量工具箱,进行数据包和现网流量的分析和操作。同时支持调用用户级别的API来创建更有效的应用程序。

相比传统抓包方式,主要特点是减少了数据包在传输中的拷贝次数,来降低cpu的消耗。而PF_RING主要分为两种类型。
官网链接:https://www.ntop.org/pf_ring/introducing-pf_ring-dna-direct-nic-access/

PF_RING

从NIC上通过Linux NAPI获取数据包拷贝,拷贝到PFring 环状缓存空间,然后用户空间的应用直接从环状缓存空间读取数据包。 PF_RING 有一次数据包拷贝操作,从NIC到环状缓存空间(Linux 内核里面),之后用户空间直接从环状缓存空间读取数据包。

PF_RING+DNA

PF_RING+DNA实现了PF_RING™ DNA(Direct NIC Access 直接网卡访问)技术,是一种映射网卡内存和寄存器到用户态的方法,除了由网卡的网络处理单元完成DMA传输之外,没有任何额外的数据包复制,绕过了PF_RING模块和Linux 内核缓存,进一步节省了一次数据拷贝操作。这将性能更好,因为CPU周期的仅用于操作数据包,而不是把数据包从网卡挪走。DNA模式下通过NIC 的NPU(网络处理器)拷贝数据包到网卡上的缓存空间。
缺点:目前使用DNA这种方式系统虽然很好,但是需要购买licence才能长期使用。

Bro支持

Bro默认使用libpcap抓包,但是也支持PF_RING和PF_RING + DNA方式抓包。具体见如下链接:https://www.bro.org/documentation/load-balancing.html

Bro从一台机器的多个网卡同时抓取流量

修改配置bro的node配置文件如下:

vim /usr/local/bro/etc/node.cfg
[logger]
type=logger
host=1.1.1.1

[manager]
type=manager
host=1.1.1.1

[proxy-1]
type=proxy
host=1.1.1.1

[worker-1]
type=worker
host=1.1.1.1
interface=eth0

[worker-2]
type=worker
host=1.1.1.1
interface=eth1

实际使用中解决的问题

问题一:

1,问题:
请求通过CDN,CDN把请求转发到我们机房nginx,而客户端的真实ip通过CDN-SRC-IP这个header传给nginx。我们从nginx连接的交换机做了端口镜像,把nginx的流量通过端口镜像给一台部署了Bro的流量分析服务器copy了一份。但是,发现http.log中并没有记录客户端的真实ip(即CDN-SRC-IP的值)。

2,解决:
看Bro的文档介绍,其能自动识别代理,并把代理ip打印到log中,但是实际上并没有自动识别到CDN-SRC-IP这个header。然后查看分析http协议的bro脚本,发现自动识别经过代理的请求是通过获取几个特定的header来实现的,而这些header不包括自定义的CDN-SRC-IP。故通过修改如下脚本添加CDN-SRC-IP这个header,然后重启Bro即可。

# vim /usr/local/bro/share/bro/base/protocols/http/main.bro  +99
        ## A list of HTTP headers typically used to indicate proxied requests.
        const proxy_headers: set[string] = {
                "FORWARDED",
                "X-FORWARDED-FOR",
                "X-FORWARDED-FROM",
                "CLIENT-IP",
                "VIA",
                "XROXY-CONNECTION",
                "PROXY-CONNECTION",
                "CDN-SRC-IP",
        } &redef;

问题二:

1,问题:
我们想过滤https的流量,来分析https流量中的相关信息。但是通过查看官网文档和实际测试未能如愿
2,解决:
1),像Bro,snort这种IDS工具都不支持https
2),wireshark(命令行有tshark工具)可以通过导入https server端私钥,来解密密钥交换算法是RSA的流量,从而解密https流量。

问题三:

1,问题:
发现bro有一些网络包没有capture到,但是通过tcpdump的确是能抓到丢失的数据包。
2,原因分析:
由于现在网卡基本都支持offload特性,offload 是将本来该操作系统进行的一些数据包处理(如分片、重组等)放到网卡硬件中去做,降低系统 CPU 消耗的同时,提高处理的性能。而这台部署bro的server网卡开启了gro或者lro,而libpcap抓包默认只能抓到gro或者lro优化后的包,从而导致有的数据包大于MTU被libpcap直接丢弃。
3,解决:
关闭镜像流量那块网卡的gro和lro,命令如下:

# ethtool -K em2 gro off lro off

4,总结:
使用bro或者suricata或者snort等IDS软件,使用前把gro和lro都关闭
5,参考:
https://www.bro.org/documentation/faq.html#how-can-i-reduce-the-amount-of-captureloss-or-dropped-packets-notices

问题四:

1,问题:
在bro产生的http log中发现有一些请求没有response信息,例如状态码,响应header,响应时间等。
2,原因分析:
1)使用tcpdump抓了5min的数据包并保存,然后找到bro http log中一条没有response信息。然后,发现tcpdump抓的包里面,也只找到了http request,在接下来的几分钟都没有找到有对应的response。故猜测只能是server段没有response给client。
2)验证1)中的猜测:
搭建一个nginx+php的测试环境,使用tcpdump抓包发现一种情况:
(1)当nginx server出现499的时候,nginx不会发送response 给client,这样就不会有状态码。您可以看一下咱们的原始日志。如果是nginx server的,看下没有status的情况能不能对应到nginx的499日志。
(2)如果server端直接崩溃或者挂掉,一般也是没有response的。
ps:
499一般是客户端主动断开连接了。原因可能是服务端响应慢,导致客户端主动断开或者用户操作太快,服务器还没有响应,客户端直接断开或者切到其它页面。

安装部署

参见官方文档:
https://www.bro.org/sphinx/install/install.html
https://www.bro.org/sphinx/quickstart/index.html

参考文章

https://www.bro.org/documentation/index.html
https://www.bro.org/development/howtos/dpd.html
https://www.bro.org/bro-workshop-2011/
https://www.bro.org/sphinx/script-reference/log-files.html
https://www.bro.org/sphinx/logs/index.html
https://www.bro.org/sphinx/scripts/base/protocols/http/main.bro.html