二开背景
suricata是一款高性能的开源网络入侵检测防御引擎,旨在检测、预防和应对网络中的恶意活动和攻击。suricata引擎使用多线程技术,能够快速、准确地分析网络流量并识别潜在的安全威胁,是众多IDS和IPS厂商的底层规则检测模块。
前段时间搭了个suricata引擎播包测试流量规则,发现原生的suricata引擎并不能获取规则匹配的位置、命中的字符串等信息。因suricata引擎并不会输出命中的信息,遂修改源码,改了命中详情(下文简称高亮)出来,今天想跟大家分享一下修改和使用的过程。
1、suricat编译安装
参考官方文档https://docs.suricata.io/en/suricata-6.0.0/install.html#install-advanced
先装库,装rust支持,装make
然后下载源码make
编译后的二进制程序在/src/.libs/suricata查看依赖库,然后补齐到默认so库目录中即可运行。
2、vscode+gdb调试suricata环境搭建
然后就是装插件,除了必备的c语言插件全家桶之外还需要装GDB Debug这个插件。
接着任意新建一个运行配置。
修改lauch.json为:
`{`    `// Use IntelliSense to learn about possible attributes.`    `// Hover to view descriptions of existing attributes.`    `// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387`    `"version": "0.2.0",`    `"configurations": [`                `{`            `"name": "(gdb) Launch",`            `"type": "cppdbg",`            `"request": "launch",`            `"program": "${fileDirname}/../src/.libs/suricata",``   `            `//以下为监听网卡模式。`            `// "args": [`            `//     "-i", "ens33", "-c", "/home/lalala/Desktop/suricata/6/suricata.yaml", "-v", "-l","/home/lalala/Desktop/suricata/6/log6/","--runmode", "single"`            `// ],`                        `//以下为读包模式。`            `"args": [`                `"-r", "/home/lalala/Desktop/suricata/6/6-27/48040.pcap", "-c", "/home/lalala/Desktop/suricata/6/suricata.yaml", "-v", "-l","/home/lalala/Desktop/suricata/6/log6/","--runmode", "single"`            `],`            `"stopAtEntry": true,`            `"cwd": "${fileDirname}",`            `"environment": [],`            `"externalConsole": false,`            `"MIMode": "gdb",`            `"setupCommands": [`                `{`                    `"description": "Enable pretty-printing for gdb",`                    `"text": "-enable-pretty-printing",`                    `"ignoreFailures": true`                `},`                `{`                    `"description": "Set Disassembly Flavor to Intel",`                    `"text": "-gdb-set disassembly-flavor intel",`                    `"ignoreFailures": true`                `}`            `]`        `},`            `]``}`
选择配置好的配置运行,看到断在入口,调试环境完成。
3、suricata流程分析,寻找关键位置
流程过于复杂,简单理解就是匹配和记录日志的地方是分在不同线程,但是又有结构体可以从匹配带到那里。
4、关键位置代码分析,获取高亮内容
根据流程,在初始化后慢慢摸索找到关键函数DetectEngineContentInspection
smd为传入规则,根据type的不同走不同的代码块儿匹配。本次加高亮重点关注CONTENT和PCRE这两个最常用的类型。
CONTENT代码块里,重点在于这个found。分析得出最后两个else里都是命中。
根据原字符串,偏移,长度即可组合出高亮字符串。
f为flow结构体也就是会带到打印日志那边的结构体,在结构体中新加一个字符串,即可达成带数据到日志流程的目的。
高亮函数代码:
`static int Get_gaoliang(const char* data,u_int32_t end, u_int32_t len,char* res){`    `char tmp[1024] = "";`        `if (len<1024)`    `{`        `memcpy(tmp, data + end-len, len);`    `}else{`        `memcpy(tmp, data + end-len, 1024);`    `}`    `strncat(res, tmp,4096);`    `strncat(res, "\n\0",4096);`    `return 1;``}`
pcre同理,在命中流程中加入写高亮字符串即可。
5、高亮加到日志
高亮字符已经写入到了flow结构体。下一步就是在打印日志的时候读到,写出来。
最优先的当然是fastlog,因为fastlog本就是触发规则会进行输出的日志,且没有其他干扰。
从Packet结构体找到flow结构体找到其中的gaoliang字符串,打印即可。
最终效果,fastlog会在正常展示命中的同时,讲高亮内容展示。
6、修改汇总
汇总代码放在github 上链接https://github.com/webraybtl/suricata\_gaoliang
修改文件详情:
> alert-fastlog.c
加打印
修改 AlertFastLogger
添加如下代码:
PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, "=========ruleid:%" PRIu32 "高亮字段展示=======:\n%s====================================\n",pa->s->id,p->flow->gaoliang);
> detect-engine-content-inspection.c
加Get_gaoliang函数
修改DetectEngineContentInspection函数 加入 写入高亮字符串逻辑。
`static int Get_gaoliang(const char* data,u_int32_t end, u_int32_t len,char* res){ `   `char tmp[1024] = "";`       `if (len<1024)`   `{`       `memcpy(tmp, data + end-len, len);`   `}else{`       `memcpy(tmp, data + end-len, 1024);`   `}`   `strncat(res, tmp,4096);`   `strncat(res, "\n\0",4096);`   `return 1;` `} ``int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, `                                 `const Signature *s, const SigMatchData *smd,`                                 `Packet *p, Flow *f,`                                 `const uint8_t *buffer, uint32_t buffer_len,`                                 `uint32_t stream_start_offset, uint8_t flags,`                                 `uint8_t inspection_mode)` `{ `   `...`   `...`   `...`           `if (found == NULL && !(cd->flags & DETECT_CONTENT_NEGATED)) {`               `if ((cd->flags & (DETECT_CONTENT_DISTANCE|DETECT_CONTENT_WITHIN)) == 0) {`                   `/* independent match from previous matches, so failure is fatal */`                   `det_ctx->discontinue_matching = 1;`               `}`               `goto no_match;`           `} else if (found == NULL && (cd->flags & DETECT_CONTENT_NEGATED)) {`               `goto match;`           `} else if (found != NULL && (cd->flags & DETECT_CONTENT_NEGATED)) {`               `if(f){`               `Get_gaoliang((char*)buffer,match_offset,cd->content_len,f->gaoliang);`               `}`               `SCLogInfo("content %"PRIu32" matched at offset %"PRIu32", but negated so no match", cd->id, match_offset);`               `/* don't bother carrying recursive matches now, for preceding`                `* relative keywords */`               `if (DETECT_CONTENT_IS_SINGLE(cd))`                   `det_ctx->discontinue_matching = 1;`               `goto no_match;`           `} else {`               `match_offset = (uint32_t)((found - buffer) + cd->content_len);`               `if(f){`                   `Get_gaoliang((char*)buffer,match_offset,cd->content_len,f->gaoliang);`                   `}`   `...``   `
> flow.h
flow结构体加一个gaoliang字符串成员。
`typedef struct Flow_` `{ `   `...`   `...`   `...`       `char gaoliang[4096];`   `} Flow;` 
遗留问题
1、因只开辟了4096字节存高亮字符,会有溢出。
2、直接按字符串打印展示出来的,对十六进制展示不理想,00会导致打印不全。