二開背景
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會導致打印不全。