1、前言
最近工作需要對網站的關鍵字進行檢測,找出敏感詞。這個過程需要對報文進行收集、解碼、檢測和記錄日志。當前只是簡單實現功能,根據關鍵字進行簡單的匹配,而沒有進行關鍵字的語義分析。導致的結果就是JAVA可以匹配AV這個敏感關鍵字。報文檢測這方面,開源項目已經做得非常好了,我所了解的有snort、suircata、bro,這三個都是非常優秀的IDS(入侵檢測系統)。由於對bro沒有深入了解,我們對比了snort和suricata,結合suricata的多線程和模塊化,全面兼容snort規則,我們選用了suricata進行關鍵字檢測。
剛開始接觸suricata的時候,壓根不知道這個單詞怎么發音,於是乎趕緊再詞典上查一下。suircata是一款支持IDS、IPS和NSM的系統。關於suircata的詳細介紹可以參考官網:https://suricata-ids.org/。
備注:
IDS:英文“Intrusion Detection Systems”的縮寫,中文意思是“入侵檢測系統”。依照一定的安全策略,通過軟、硬件,對網絡、系統的運行狀況進行監視,盡可能發現各種攻擊企圖、攻擊行為或者攻擊結果,以保證網絡系統資源的機密性、完整性和可用性。
IPS是英文“Intrusion Prevention System”的縮寫,中文意思是入侵防御系統。隨着網絡攻擊技術的不斷提高和網絡安全漏洞的不斷發現,傳統防火牆技術加傳統IDS的技術,已經無法應對一些安全威脅。在這種情況下,IPS技術應運而生,IPS技術可以深度感知並檢測流經的數據流量,對惡意報文進行丟棄以阻斷攻擊,對濫用報文進行限流以保護網絡帶寬資源。
NSM:英文“network security monitoring”的縮寫,中文意思是“網絡安全監控”。
2、總體架構
報文檢測系統通常四大部分,報文獲取、報文解碼、報文檢測、日志記錄;suricata不同的功能安裝模塊划分,一個模塊的輸出是另一個模塊的輸入,suricata通過線程將模塊串聯起來。
接下來以IDS為例來說明suircata的線程與模塊之間是如何連接起來的。
首先注冊runmods,運行方式指定suricata獲取報文的方式,例如libpcap、netmap、af-packet等,代碼如下圖所示:
然后再根據設置suricata的工作模式,找到對應獲取報文的處理模塊。suircata默認是通過af-packet mmap獲取報文,然后調用獲取報文模塊當然入口函數,
入口函數中函數添加了解碼模塊、流處理模塊(檢測報文)、日志處理模塊。通過slot鏈條安裝注冊順序串聯起來。每一個線程都包含一個slot的鏈表,每個結點都懸掛着不同的模塊,程序執行的時候會遍歷slot鏈表,按照加入鏈表的熟悉執行模塊。
創建線程,並將模塊添加到slot鏈表過程代碼如下所示:
1 /* create the threads */ 2 for (thread = 0; thread < threads_count; thread++) { 3 char tname[TM_THREAD_NAME_MAX]; 4 ThreadVars *tv = NULL; 5 TmModule *tm_module = NULL; 6 const char *visual_devname = LiveGetShortName(live_dev); 7 8 if (single_mode) { 9 snprintf(tname, sizeof(tname), "%s#01-%s", thread_name, visual_devname); 10 } else { 11 snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, 12 thread+1, visual_devname); 13 } 14 tv = TmThreadCreatePacketHandler(tname, 15 "packetpool", "packetpool", 16 "packetpool", "packetpool", 17 "pktacqloop"); 18 if (tv == NULL) { 19 SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed"); 20 exit(EXIT_FAILURE); 21 } 22 23 //添加收包模塊 24 tm_module = TmModuleGetByName(recv_mod_name); 25 if (tm_module == NULL) { 26 SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); 27 exit(EXIT_FAILURE); 28 } 29 TmSlotSetFuncAppend(tv, tm_module, aconf); 30 //添加解包模塊 31 tm_module = TmModuleGetByName(decode_mod_name); 32 if (tm_module == NULL) { 33 SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name); 34 exit(EXIT_FAILURE); 35 } 36 TmSlotSetFuncAppend(tv, tm_module, NULL); 37 //添加流處理模塊,用於檢測報文 38 tm_module = TmModuleGetByName("FlowWorker"); 39 if (tm_module == NULL) { 40 SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); 41 exit(EXIT_FAILURE); 42 } 43 TmSlotSetFuncAppend(tv, tm_module, NULL); 44 //添加阻斷模塊 45 tm_module = TmModuleGetByName("RespondReject"); 46 if (tm_module == NULL) { 47 SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName RespondReject failed"); 48 exit(EXIT_FAILURE); 49 } 50 TmSlotSetFuncAppend(tv, tm_module, NULL); 51 //添加日志處理模塊 52 SetupOutputs(tv); 53 54 TmThreadSetCPU(tv, WORKER_CPU_SET); 55 56 if (TmThreadSpawn(tv) != TM_ECODE_OK) { 57 SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); 58 exit(EXIT_FAILURE); 59 } 60 } 61
在AF-PACKET工作模式下提供三種工作方式:
關於工作方式可以參考:http://blog.csdn.net/firedb/article/details/7581853。
目前我只用過worker工作模式,整個流程通過一個線程來處理。
3、總結
這是目前對suricata的一個整體的認識,接下來認真研究每個模塊之間是如何交互。需要深入學習suricata是如何收集報文,如何將收集的報文傳遞給解碼模塊,解碼模塊做哪些工作,輸出是什么。
suricata各模塊功能:
Receive:從NFQUEUE中接收數據包,並將封裝在Packet結構中,然后放入下一個緩沖區。
Decode:對數據包進行解碼,主要是對數據包頭部信息進行分析並保存在Packet結構中。
StreamTCP:對數據包進行TCP流重組。
Detect:檢測數據包是否包含入侵行為。
Verdict:對檢測后的數據包進行判定,並將判定結果告訴內核(通過ipq_set_verdict函數),方便內核對數據包進行接收、丟棄等處理。
RespondReject:通過libnet對那些要執行Reject操作的數據包進行相應的回應。