在Bro中完成第一个协议分析器—RIP协议
前言
熟悉代码结构最好的方式,就是尝试自己去写一个模块加入到整个系统中,在调试代码的过程中,熟悉代码。
实现流程
使用Binpac quick start脚本生成自己的Analyzer目录结构
下载Binpac Quick Start脚本
git clone https://github.com/grigorescu/binpac_quickstart.git
下载完成之后,进入该目录,目录结构如下图所示:
Guoze@node-0:~/00_Workbench$ cd binpac_quickstart/
Guoze@node-0:~/00_Workbench/binpac_quickstart$ ls -al
total 32
drwxr-xr-x 4 Guoze senfv-PG0 4096 May 22 19:30 .
drwxr-xr-x 11 Guoze senfv-PG0 4096 May 23 12:15 ..
drwxr-xr-x 8 Guoze senfv-PG0 4096 May 22 19:30 .git
-rw-r--r-- 1 Guoze senfv-PG0 21 May 22 19:30 __init__.py
-rw-r--r-- 1 Guoze senfv-PG0 128 May 22 19:30 README.md
-rwxr-xr-x 1 Guoze senfv-PG0 7151 May 22 19:30 start.py
drwxr-xr-x 2 Guoze senfv-PG0 4096 May 22 19:30 templates
使用脚本生产分析器目录结构
start.py的python就是我们可以用来生成bro中Analyzer的python脚本,使用方式:
Guoze@node-0:~/00_Workbench/binpac_quickstart$ ./start.py
Usage:
start.py NAME DESCRIPTION PATH_TO_BRO_SRC (--tcp|--udp) [--buffered] [--plugin]
Example:
./start.py RIP "Routing Internet Protocl" ../bro --udp
协议名称:RIP; 协议介绍:Routing Internet Protocl Bro源代码的路径:../bro 底层的网络协议:–udp
我们书写的第一个脚本就是实现RIP协议的解析,RIP协议的详细内容请参考。
在终端输入:./start.py RIP "Routing Internet Protocl" ../bro --udp
执行结束之后分别在bro源代码下两个位置生产文件:
bro/scripts/base/protocols/rip/
Guoze@node-0:~/00_Workbench/bro/scripts/base/protocols/rip$ ls -l
total 12
-rw-r--r-- 1 Guoze senfv-PG0 245 May 23 12:49 dpd.sig
-rw-r--r-- 1 Guoze senfv-PG0 66 May 23 12:49 __load__.bro
-rw-r--r-- 1 Guoze senfv-PG0 1327 May 23 12:49 main.bro
load.bro: This allows all the contents of the directory to be loaded via @load base/protocols/sip. dpd.sig: This file contains a signature that can be used to attach the analyzer to connections if their content matches. main.bro: Contains the base script-layer functionality for processing events emitted from the analyzer.
src/analyzer/protocol/sip/
Guoze@node-0:~/00_Workbench/bro/src/analyzer/protocol/rip$ ls -l
total 32
-rw-r--r-- 1 Guoze senfv-PG0 301 May 23 12:50 CMakeLists.txt
-rw-r--r-- 1 Guoze senfv-PG0 472 May 23 12:50 events.bif
-rw-r--r-- 1 Guoze senfv-PG0 480 May 23 12:50 Plugin.cc
-rw-r--r-- 1 Guoze senfv-PG0 738 May 23 15:27 rip-analyzer.pac
-rw-r--r-- 1 Guoze senfv-PG0 721 May 23 12:50 RIP.cc
-rw-r--r-- 1 Guoze senfv-PG0 715 May 23 12:50 RIP.h
-rw-r--r-- 1 Guoze senfv-PG0 1005 May 23 12:50 rip.pac
-rw-r--r-- 1 Guoze senfv-PG0 939 May 23 15:03 rip-protocol.pac
CMakeLists.txt: Informs the CMake build system how to compile the analyzer. Plugin.cc: Analyzers in Bro are a type of plugin. This file does what’s necessary to register the new analyzer plugin with Bro. RIP.h: Defines the API for the new analyzer which derives from one of Bro’s already-existing analyzer classes. RIP.cc: mplementation of the analyzer. It’s mostly just responsible for handing off data to the protocol parser that’s been generated by BinPAC. events.bif: Defines events that the analyzer will generate. rip.pac: The main entry point for the BinPAC definition of the protocol that you want to parse. rip-protocol.pac: Where the message format is defined.
rip-analyzer.pac: Defines a connection, flow, and other processing functions for the analyzer.
在这些文件当中,我们主要需要完成:
- events.bif
- rip.pac
- rip-protocol.pac
- rip-analyzer.pac
代码实现
rip-protocol.pac文件
这个文件实现的是对RIP协议的组成部分进行定义,以type的方式定义协议数据传输的各个部分。其中RIP_PDU
函数是将需要处理的部分传递到分析仪去。
1 # Generated by binpac_quickstart
2 # ## TODO: Add your protocol structures in here.
3 # ## some examples:
4
5 # Types are your basic building blocks.
6 # There are some builtins, or you can define your own.
7 # Here's a definition for a regular expression:
8 # type RIP_WHITESPACE = RE/[ \t]*/;
9
10 # A record is a collection of types.
11 # Here's one with the built-in types
12
13 enum Rip_Command {
14 RIP_REQUEST = 1,
15 RIP_RESPONSE = 2,
16 }
17
18 enum Rip_Version {
19 RIP_V1 = 1,
20 RIP_V2 = 2,
21 }
22
23 type Rip_Message = record {
24 command : uint8;
25 version : uint8;
26 pad : padding[2];
27 entry : Rip_Entry[] &until($input.length()) == 0;
28 };
29
30 type Rip_Entry = record {
31 af : uint16;
32 rt : uint16;
33 ip : uint32;
34 mask : uint32;
35 gateway : uint32;
36 metric : uint32;
37 };
38
39 type RIP_PDU(is_orig: bool) = record {
40 command : uint8;
41 version : uint8;
42 pad : padding[2];
43 } &byteorder=bigendian;
rip_analyzer.pac文件实现
该文件主要完成对命令做出对RIP_PDU
函数传递过来的数据进行处理解析, 如果有RIP数据包出现那么就进入这个处理流程。
1 # Generated by binpac_quickstart
1
2 refine flow RIP_Flow += {
3 function proc_rip_message(msg: RIP_PDU): bool
4 %{
5 // Check for RIP commands
6 if ( ${msg.command} == RIP_REQUEST) {
7 BifEvent::generate_rip_request(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(),
8 ${msg.command},
9 ${msg.version});
10 return true;
11 }
12 if ( ${msg.command} == RIP_RESPONSE) {
13 BifEvent::generate_rip_response(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(),
14 ${msg.command},
15 ${msg.version});
16 return true;
17 }
18 %}
19 };
20
21 refine typeattr RIP_PDU += &let {
22 proc: bool = $context.flow.proc_rip_message(this);
23 };
~
events.bif文件实现
1 # Generated by binpac_quickstart
1
2 # In this file, you'll define the events that your analyzer will
3 # generate. A sample event is included.
4
5 # ## TODO: Edit the sample event, and add more events.
6
7 ## Generated for RIP connections
8 ##
9 ## See `Google <http://lmgtfy.com/?q=RIP>`__ for more information about RIP
10 ##
11 ## c: The connection
12 ##
13 event rip_request%(c: connection, command: count, version: count%);
14 Event rip_response%(c: connection, command: count, version: count%);
测试
配置bro的工作环境
首先需要配置好bro的可执行文件的路径问题:
Bro可执行文件的路径在:bro/build/src/bro
Guoze@node-0:~/00_Workbench/bro$ ./build/src/bro -h
bro version 2.5-598
usage: ./build/src/bro [options] [file ...]
<file> | policy file, or read stdin
-a|--parse-only | exit immediately after parsing scripts
-b|--bare-mode | don't load scripts from the base/ directory
-d|--debug-policy | activate policy file debugging
-e|--exec <bro code> | augment loaded policies by given code
-f|--filter <filter> | tcpdump filter
Bro已经提供了可执行脚本给你,让你可以方便的配置环境变量,所以我们可以直接执行配置脚本就好了。 配置环境变量的shell脚本为:
Guoze@node-0:~/00_Workbench/bro/build$ cat bro-path-dev.sh
export BROPATH=`/users/Guoze/00_Workbench/bro/build/bro-path-dev`
export BRO_PLUGIN_PATH="/users/Guoze/00_Workbench/bro/build/src":
export PATH="/users/Guoze/00_Workbench/bro/build/src":$PATH
执行脚本完成配置
Guoze@node-0:~/00_Workbench/bro$ source ./build/bro-path-dev.sh
检测脚本执行情况,判断是否完成配置,在终端输入:bro -h
, 如果执行结果和执行./build/src/bro -h
的结果一致,那么就表示已经配置成功了。
Guoze@node-0:~/00_Workbench/bro$ bro -h
bro version 2.5-598
usage: bro [options] [file ...]
<file> | policy file, or read stdin
-a|--parse-only | exit immediately after parsing scripts
-b|--bare-mode | don't load scripts from the base/ directory
-d|--debug-policy | activate policy file debugging
-e|--exec <bro code> | augment loaded policies by given code
-f|--filter <filter> | tcpdump filter
-g|--dump-config | dump current config into .state dir
-h|--help|-? | command line help
测试代码
下载RIP的网络数据抓包
直接下载一个RIPv2的数据包就可以用于测试了
$ wget http://packetlife.net/captures/RIPv2.cap
判断数据包是否是包含的RIP数据,能否符合我们的要求?
Guoze@node-0:~/00_Workbench$ tcpdump -nr RIPv2.cap
reading from file RIPv2.cap, link-type EN10MB (Ethernet)
23:06:26.942558 IP 10.0.0.1.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:06:30.158769 IP 10.0.0.2.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:06:52.663855 IP 10.0.0.1.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:06:58.416478 IP 10.0.0.2.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:07:19.709681 IP 10.0.0.1.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:07:24.974047 IP 10.0.0.2.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:07:45.389720 IP 10.0.0.1.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:07:53.891896 IP 10.0.0.2.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:08:14.625084 IP 10.0.0.1.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:08:21.933550 IP 10.0.0.2.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:08:41.410659 IP 10.0.0.1.520 > 224.0.0.9.520: RIPv2, Response, length: 84
23:08:47.731064 IP 10.0.0.2.520 > 224.0.0.9.520: RIPv2, Response, length: 84
修改代码,加入测试打印数据
12 refine flow RIP_Flow += {
11 function proc_rip_message(msg: RIP_PDU): bool
10 %{
9 // Check for RIP commands
8 if ( ${msg.command} == RIP_REQUEST) {
7 printf("In rip_request\n");
6 BifEvent::generate_rip_request(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(),
5 ${msg.command},
4 ${msg.version});
3 return true;
2 }
1 if ( ${msg.command} == RIP_RESPONSE) {
15 printf("In rip_response\n");
1 BifEvent::generate_rip_response(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(),
2 ${msg.command},
3 ${msg.version});
4 return true;
5 }
6 %}
修改代码完成之后,重新编译代码:
Guoze@node-0:~/00_Workbench/bro$ sudo make
make -C build all
make[1]: Entering directory '/users/Guoze/00_Workbench/bro/build'
make[2]: Entering directory '/users/Guoze/00_Workbench/bro/build'
make[3]: Entering directory '/users/Guoze/00_Workbench/bro/build'
make[3]: Leaving directory '/users/Guoze/00_Workbench/bro/build'
........
........
[100%] Built target rst
make[2]: Leaving directory '/users/Guoze/00_Workbench/bro/build'
make[1]: Leaving directory '/users/Guoze/00_Workbench/bro/build'
结尾和我上述结果类似的话,表示编译通过。
使用网络抓包数据进行测试
使用Bro导入这个数据包进行测试
Guoze@node-0:~/00_Workbench$ bro -r RIPv2.cap
In rip_response
In rip_response
In rip_response
In rip_response
In rip_response
In rip_response
In rip_response
In rip_response
In rip_response
In rip_response
In rip_response
In rip_response
提升理解
在前面的部分,并没有去处理scripts/base/protocols/rip/
目录下面的文件,接下来我们需要来理解这几个文件。
Guoze@node-0:~/00_Workbench/bro/scripts/base/protocols/rip$ ls -l
total 12
-rw-r--r-- 1 Guoze senfv-PG0 245 May 23 12:49 dpd.sig
-rw-r--r-- 1 Guoze senfv-PG0 66 May 23 12:49 __load__.bro
-rw-r--r-- 1 Guoze senfv-PG0 1327 May 23 12:49 main.bro
load.bro: This allows all the contents of the directory to be loaded via @load base/protocols/sip. dpd.sig: This file contains a signature that can be used to attach the analyzer to connections if their content matches. main.bro: Contains the base script-layer functionality for processing events emitted from the analyzer.
load.bro理解
这个文件加载了所有的内容到Bro中去。
dpd.sig (digital protocol detection scripts)
当你找出来匹配你定义的特殊的协议的时候,他就会生成和调用对应的分析器去处理,我们可以这里定义它需要处理的接口
main.bro
这个文件包含了所有的基本工作和所有分析器内容,Bro首先云心的内容
<未完待续>