介绍
suricata所有的协议都是通过向框架(AppLayerParserRegisterProtocolParsers)提供注册回调完成的。
开发一个新的协议,按照相同结构格式完成即可。
一、编写协议解析文件
suricata可以通过工具脚本执行直接生成协议解析文件,文章使用的suricata 4.1.3版本。那么下载同版本工具,工具我已经clone一份到我的git了,default 分支为4.1x版本
git clone https://github.com/Liuchunhui0526/suricata-1.git
下载完成放在系统路径下并完成解压,解压后的内容是
1、生成协议解析文件
在工具路径执行
python scripts/setup-app-layer.py Liu |
成功生成对应协议文件
两个文件生成在工具文件下的src目录,手动把文件提出来放在suricata4.1.3编译环境即可
scp ../../suricata-1-master-4.1.x/src/app-layer-liu.* . |
2、分析生成的文件内容
生成的c文件,RegisterxxxParsers接口就是用来提供给框架的注册接口。
2.1、suricata.yaml配置文件中是否存在协议且enable
suricata.yaml配置文件app-layer部分存在对应使能配置
2.2、协议注册
suricata协议解析存在PM、PP、PE三种模式,其中PM为数据报关键特征匹配,即匹配报文字段(类似规则中的content字段),PP为端口匹配,即服务器目的端口值匹配命中即确定为协议,最后一个PE为字节流匹配,目前常规只有FTP-DATA协议,其协议会根据FTP commend计算并创建紧跟的子协议。
本篇文章以工具生成内容介绍,默认为PP模式注册;
RunmodeIsUnittests这个不重要,判断系统以什么模式启动,这里判断是否为测试状态。
AppLayerProtoDetectPPParseConfPorts这个接口作用是判断yaml配置文件中“liu”这个协议是否存在默认端口号,如果类似存在443,则以配置文件设置的端口为准,不通过AppLayerProtoDetectPPRegister注册。(AppLayerProtoDetectPPRegister这个接口的作用是注册了一个服务器方向匹配LIU_DEFAULT_PORT端口的规则,还附加了最小有效长度为LIU_MIN_FRAME_LEN:即小于LIU_MIN_FRAME_LEN长度就默认不是这个协议)
2.3、协议处理接口注册
当一条流量被解析成对应的协议,在双边流量经过设备时,需要通过每方向的处理逻辑进行检测或信息搜集。
可以看到这里注册了很多的回调,用于框架不同功能和阶段。本篇文章,只简单使用双边处理接口,其他接口在协议开发后续章节提供。
2.4、双边数据包接口
请求处理接口实现的是将数据包payload部分,放进一块申请的空间中;如果遇到长度大于0且首位值为0的数据包,就产生事件
static int LiuParseRequest(Flow *f, void *statev, SCLogNotice("Parsing liu request: len=%"PRIu32, input_len); /* Likely connection closed, we can just return here. */ /* Probably don't want to create a transaction in this case /* Normally you would parse out data here and store it in the /* Also, if this protocol may have a "protocol data unit" span /* Allocate a transaction. if (unlikely(tx == NULL)) { //这有打印信息,可以证明收到数据包 SCLogNotice("Allocated Liu tx %"PRIu64".", tx->tx_id); /* Make a copy of the request. */ if (unlikely(tx->request_buffer == NULL)) { /* Here we check for an empty message and create an app-layer //产生事件 if ((input_len == 1 && tx->request_buffer[0] == '\n') || end: |
响应数据包
遍历请求构成的状态数据,这里应存在事件处理。将响应数据包保存到对应请求结构中的响应空间中。
static int LiuParseResponse(Flow *f, void *statev, AppLayerParserState *pstate, SCLogNotice("Parsing Liu response."); /* Likely connection closed, we can just return here. */ /* Probably don't want to create a transaction in this case /* Look up the existing transaction for this response. In the case /* We should just grab the last transaction, but this is to //这里遍历结构查看是否存在异常,比如请求处理中加入的事件。 tx = ttx; if (tx == NULL) { SCLogNotice("Found transaction %"PRIu64" for response on state %p.", /* If the protocol requires multiple chunks of data to complete, you may //这里申请空间,数据同样保存到对应请求的结构中 /* Make a copy of the response. */ /* Set the response_done flag for transaction state checking in end: |
二、编译
加入协议宏:在app-layer-protos.h文件中加入对应宏变量
注册协议接口:在AppLayerParserRegisterProtocolParsers接口中插入协议的注册接口,在这个文件中要加入头文件。
Makefile添加源文件:在am_suricata_OBJECTS变量中加入我们的文件。
三、测试
1、数据包
有一个简单的tcp通信数据包,客户端向服务器push了一段字符串。服务器端口为1001
2、yaml文件配置
加入协议并给定服务器端口为1001
liu: enabled: yes detection-ports: dp: 1001 |
将日志级别设置为debug
3、提供一个对应协议规则
alert liu any any -> any any (msg:"Detect www in payload"; content:"HTTP";sid:1000001;) |
4、启动suricata
以af-packet模式运行suricata
suricata -c suricata.yaml --af-packet |
5、验证
监视fast.log文件,查看告警状态