從海量安全事件中挖掘有用的威脅信息與情報是當今討論的熱門話題,同時這也是一個難點?怎麼實現呢?這裏用到一種技術叫做關聯分析,他也是SIEM(Security Information Event Management安全信息和事件管理)系統中最常見的事件檢測手段,這並不是什麼新鮮事物,20年前就已經有人提出來了。通常基於時序來對相同數據源或來自不同數據源的安全事件,使用關聯規則來進行綜合的關聯分析,下面介紹關聯分析的具體功能。
通常來說,一次惡意Gong JI會在多個安全設備或應用程序(如網絡防火牆,交換機,Web 應用日誌,SQL 日誌,審覈日誌等)中留下痕跡. 然而,所有這些信息都是孤立隔絕的,被保存在不同的設備日誌中,如果利用了關聯分析技術就可以快速定位故障。
關聯分析爲什麼有如此神通廣大呢?其實後臺有很多複雜的關聯規則最爲基礎的,這些檢測規則可以識別 A t t a c k 事件,實際上這些規則是人工在大量實踐中總結出來生成對Gong JI事件的一種語言描述,並對其進行了精確分類,分類越細描述越準確,識別率就越高。
Tips: 下文中“Gong Ji”“**”代表銘感詞彙,你懂得。
一、關聯分析核心思想
關聯分析技術的核心思想是通過對某一類事件進行訓練建立行爲基線,基線範圍外的事件視爲異常事件來進行分類. 該算法較適合於本文檢測場景,通常 SIEM 系統中絕大多數的日誌爲正常事件,通過對正常事件訓練建模,來檢測異常或Gong JI事件,這就是理論上說的One-Class SVM(單類支持向量機)。OSSIM系統中需要更多維度特徵向量,才能準確判斷Gong JI源,避免檢測精度低或過擬合情況. 算法輸入是經過 OSSIM 歸一化後具備相同數據結構的安全事件,輸出則爲帶有標記的安全事件,標記分爲兩類:正常(Negative)與Gong JI(Positive). 而OSSIM關聯分析引擎的輸出就是 One-Class SVM分類算法輸出的帶標記的正常與Gong JI事件。
通過深入分析 SIEM 系統的關聯規則,其中最常見的配置字段如:event_id,timestamp,plugin_id,plugin_sid,src_ip,src_port,des_ip,des_port,protocol 等。 爲了使關聯分析規則不依賴於傳感器配置,本文從 OSSIM 的規則庫中抽取了幾個重要的字段 plugin_id_name,plu-gin_id_description,sid_name,並將所有字段拆分成關鍵詞標籤,然後針對每一條檢測規則生成其關鍵詞標籤統計模型,利用規則統計模型來代替原始的規則來檢測Gong JI。
關聯分析的核心通過一個或一組關聯指令來完成,下面用SSH**破解的例子加以說明,如圖1所示,SSH**破解(Brute Force)大約自UNIX誕生之後,就衍生出來的一種Gong JI行爲,據統計發現大約有50%以上的用戶名是root。一個低可靠性(low reliability)的SSH 服務器,在經過100登錄嘗試之後成功登錄,而高可靠性(high reliability)的SSH服務器,則經過10000次登錄才成功,那麼關聯引擎可通過在一定時間內,登錄的次數,以及這些時間的不同源地址和相同目標IP地址,以及這些IP地址來自於那些國家,它們信譽度如何等信息來綜合判定Gong JI以及作出響應。
圖1
下面大家將親生經歷關聯引擎的關聯指令的組成結構。
二、 關聯指令配置界面
OSSIM中關聯指令的界面通過Configuration->Threat Intelligence->Directives打開,經過前面幾節的內容的學習,大家或多或少的已經接觸過關聯指令的界面,下面我們進行一下歸納,如下圖2所示。
圖2 OSSIM 關聯指令界面
關鍵功能解釋:
New Directive:單擊此選項以從頭開始創建一個新的指令。
Test Directives:單擊此按鈕,將檢測當前新建/修改的指令是否正確。
Restart Server:單擊此按鈕,將重啓ossim-server進程,凡是修改了任何一條關聯指令都需重新啓動Server,按這個按鈕比你重啓整個USM服務器更明智。
需要注意的是,雖然重啓時間短暫,但重啓期間所有關聯數據會丟失。
圖3 一條完整指令
● Sensor:傳感器,用於收集各種事件信息。
● Protocol:協議,包括ANY、TCP、UDP、ICMP。
● Sticky different:
還記得Linux基礎是指中,用於文件及目錄屬性設定的sticky位嗎?從OSSIM 4.3起在關聯指令中添加了新屬性,Sticky different(不同的粘粘位)域,規則中Sticky different爲None。它是用來設定指令規則的屬性,
有關Sticky different的取值大家可參考/etc/ossim/server/directives.xsd文件
<xs:simpleType name="stickydifferenttype">
... ...略
</xs:simpleType>
當新收集的事件到達關聯引擎時,它將和已有的事件相關聯,如果事件屬性(如IP地址和端口號)相同,但一個指令的屬性裏可以設置不同的粘粘位,比如None、DST_PORT、SRC_IP、PLUGIN_ID等,用來區別收到的不同事件,以便進行相互關聯。例如在端口掃描類Gong JI中,如果你設置目標端口爲Sticky different,那麼只有來自不同目標端口的事件被關聯。
三、在OSSIM 的Web UI中查看效果
下面我們查看實際的例子,如圖4所示。
圖4 STICKY DIFF
打開/etc/ossim/server/alienvault-dos.xml查看關聯指令AvAttacks,Possible DDOS
● Username:事件中指定的用戶名
● Pass: 事件中指定的口令
● Userdata1~Userdata8:事件中指定的數據域。
圖5 查看更對關聯規則屬性
注意,From、To、Data source 、Event Type 列下方的號表示可修改,Action下的號代表可添加規則 ,但系統默認指令中的規則不允許修改。
四、深入關聯規則
1. 基本操作
在OSSIM利用預先定義的規則(/etc/ossim/server/*.xml)來進行關聯分析。那麼我們如何操作呢,首先,我們通過Web界面,新建一個Correlation Directives,新建兩個規則ssh和test,然後我們看看詳細文件內容,路徑在/etc/ossim/server目錄,名爲user.xml文件。其他默認規則由/etc/ossim/server/directives.xml定義,如圖6所示。
圖6 自定義指令
當系統調用Directive下的策略是,首先根據categories.xml配置文件讀取相應的XML配置文件,這些文件功能如下:
策略文件存儲位置:/etc/ossim/server/及說明
Ø alienvault-attacks.xml AlienVault Gong JI類策略
Ø alienvault-bruteforce.xml AlienVault**破解類Gong JI
Ø alienvault-dos.xml Alienvault拒絕服務類
Ø alienvault-malware.xml Alienvault 惡意軟件(包括檢測各種蠕蟲的規則)
Ø alienvault-misc.xml Alienvault各種失誤類(Miscellaneous)
Ø alienvault-network.xml Alienvault網絡類 (開源版無此項)
Ø alienvault-policy.xml Alienvault策略
Ø alienvault-scan.xml Alienvault掃描
Ø user.xml Alienvault用戶自定義
如果OSSIM關聯引擎讀不到這些策略配置文件,在Analysis→Alarm就不會生成報警。接下來我們詳細看看一個xml的例子。
2.理解規則樹
關聯引擎通過規則來實現對安全事件的關聯分析,讀者需要能夠看懂OSSIM的規則,其中採用了特有的樹形規則,在規則樹中的每一個節點對應一條關聯規則(rules)。在匹配時關聯引擎將某段時間內收到的統一格式的報警,從根節點開始往葉子節點逐次匹配,系統根據匹配的結果可以進行事件聚合和再次提升報警級別。下面看個實例:
圖7 自定義指令內容
從上圖可以看出,這種基於事件序列的關聯方法中的每條指令相當於一顆由規則組成的樹,所以可以把它叫做基於樹形指令(Directive)的關聯方法,其基本思想是根據相關事件序列創建一系列的規則來表示Gong JI場景,在OSSIM系統中採用了XML來定義關聯序列,關聯分析引擎啓動時就將所有關聯導入每個關聯規則序列由下面標籤組成將上面的實際xml提煉一下,得到如下模板:
<directive id="" name="" priority="">
<rule type="" name="" reliability="" occurence="” from="" to="" port_from="" port_to="" plugin_id=""plugin_sid="">
<rules>
<rules>
......
</rules
......
</rule>
</directive>
每個序列開頭包括兩個標籤“directive_id”和“directive name”,而每個序列,又包括很多規則,規則之中又可以嵌套規則,即遞歸方法。
其中Rule 代表規則,規則後面代表一個可能發生的Gong JI場景,Event 代表在當前已發生的Gong JI場景下,一個Gong JI場景由若干條規則組成,這些規則可能是“與”和“或”的關係。這樣表示的好處是,我們清楚的知道,如果一個Gong JI場景發生,那麼只需要滿足哪些規則即可。
通過計算每個Rule 裏的Reliability 來確認這個Gong JI發生的可信度是多少。其中Scene 的id用directive_id來表示;前面講過Reliability 可以是0~10之間的數,直接給可靠性賦值,也可以使一個修改量,表示當這個規則滿足時將前一步Gong JI場景的可靠性做修改,將結果存入New_Reliability中;規則部分的其它屬性代表了將和它做匹配的Event 的屬性值;而和數據庫的具體交互是通過Action 來表示。
下面我們看個實際的例子,下面這段指令主要是用來檢測公網服務器是否可用,其中包含了兩個規則。
<directive id="500000" name="Public Web Server unavailable" priority="1">
<rule type="detector" name="server unavailable" reliability="1"
occurrence="1" from="192.168.11.100" to="ANY" port_from="ANY" port_to="ANY"
plugin_id="1525" plugin_sid="1,7,9">
<rules>
<rule type="monitor" name="Ping Baidu Server in order to check internet connection"
reliability="10" from="www.baidu.com" to="www.baidu.com" plugin_id="2009" plugin_sid="1" condition="gt" value="0" interval="20" time_out="120" />
</rules>
</directive>
關鍵參數解釋:
● Detector: 探測器規則自動收集從代理髮來的記錄,包括Snort、Apache、Arpwatch等。
● Monitor:監控器負責查詢Ntop服務發來的數據和會話。
● Name:事件數據庫中的規則名稱。
● Reliability:可靠性
● Plugin_id:插件ID,查看更多插件ID請參考《開源安全運維平臺OSSIM最佳實踐》第一章內容。
● Plugin_sid:插件子ID號,分配給每個插件事件的子ID,比如Snort這個插件ID號爲1001,而1501就是它的子ID號,代表Apache事件的響應代碼,當然可不止這一件。
● Condition:條件參數和下面6個邏輯有關係,必須符合的邏輯條件匹配規則如下:
Ø eq – 等於(Equal)
Ø ne – 不等於(Not equal)
Ø lt – 小於(Lesser than)
Ø gt – 大於(Greater than)
Ø le – 小於等於(Lesser or equal)
Ø ge – 大於等於(Greater or equal)
●Interval:間隔,這個值類似於time_out,用於監控類規則。
3.Alienvault-scan規則描述
再舉一個OSSIM自帶的例子,我們查看/etc/ossim/server/alienvault-scan.xml這個掃描Gong JI場景的策略文件,描述的結構就像個邏輯樹,基本格式如下:
Gree:level 1
Yellow : level2
Orange:level3
Red: level 4
下面給出部分代碼內容,如圖8所示
圖8 Gong JI掃描指令示例
● Occurrence,表示發生次數,默認爲1,Gong JI場景不同這個值也不一樣。這個值越大,越要引起管理員的警覺。這裏表示的發生次數,也就是計算具有相同的 "from、to、port_from、port_to、plugin_id、plugin_sid" 發生次數,用以進行到關聯模式中的下一規則。
這個數值在基於規則的關聯分析中非常有用,例如當目標IP地址發生的異常行爲事件數量的頻率達到了一定數值時(某人針對該系統發動Gong JI),OSSIM會發出預警提示,管理員就可以有針對性開展深入調查。當然對源IP也適用。
From表示來源,源地址有以下幾種形式:
①ANY,任意IP地址都可以匹配。
②小數點和數字的IPv4形式。
③以逗號隔開的IPv4地址,不帶掩碼。
④可以使用任意數目的IP地址,中間用逗號隔開。
⑤網絡名稱,可以使用網絡中事先定義好的網絡名稱。
⑥相對值,這種情況比較複雜,可以引用上條規則中的IP地址,例如:
l 1:SRC_IP 表示引用前一條規則的源地址
l 2:DST_IP 表示引用前第二條的目的地址作爲源地址
⑦否定形式,可以使用地址的否定形式如 :"!192.168.150.200,HOME_NET"。
如果 HOME_NET = 192.168.150.0/24 將匹配一個C類子網排除192.168.150.200。
l Time_out,表示超時,其等待一定時間以匹配規則,時間超出則匹配失敗。
l Port_from/Port_to ,表示來自哪裏/目的端口,Port_from可以是ANY,Port_to,可以是一個端口號或一個逗號分隔的端口序列,1:DST_PORT,也可以否定端口例如,port=“!22,25”。
注意:dst_ip表示目的ip地址,而dst_port則表示目的端口號,ipaddr本地ip地址。
l Protocol(協議),可以使用以下字符串:TCP、UDP、ANY。
l Plugin_id(插件ID),參考plugin中的plugin_id。
l Plugin_sid(插件SID),每個事件都是分配一個子ID。
圖9 規則樹的嵌套
在OSSIM系統運行前,必須爲已知的Gong JI場景建立對應的樹形規則集,在啓動時,系統將預先定義好的指令讀入內存,在接收到一個事件 (event)後,先將該event與之前已經匹配,而還沒有匹配完的指令中的規則進行匹配,然後在於其他規則匹配。那麼在一個複雜的Gong JI場景中一條Event就會與多條規則匹配,如果此事件的風險值超過預先設定的閾值,則將其alarm屬性設爲真,並在Alarm界面中顯示。
例如:plugin_id="1001" plugin_sid="2008609,2008641"。
在OSSIM 4.6系統中,有385個數據源,這裏ID=1001,代表Snort檢測插件,產品類型屬於IDS,主要適用於Snort規則,其它插件ID還記得嗎?如果忘了請返回本書第1章,查看“插件&功能”對應表。
實際上在OSSIM系統中,Snort插件ID範圍是1001~1145。在OSSIM 4.8 版中位於Configuration→Threat Intelligence→Data Source可以查看到所有數據源。如圖10所示。
圖10 數據源分類
在Ossim的關聯引擎運行之前,必須爲所有已知的Gong JI場景建立對應的樹形指令(在開源系統中提供了84條,在OSSIM 4.15的商業版本提供了1800餘條,OSSIM USM 5.x提供2100+條),這也是它的核心價值的體現,在OSSIM啓動時,系統會將所有預先定義好的指令讀入內存,在接收到一個directive_event後,先將該事件與之前已經匹配,而還沒有匹配完的指令中的規則匹配,然後再與其它指令的規則匹配。注意一個事件可以與很多指令中的規則匹配。
五、 完善規則
OSSIM系統中的關聯規則生成主要通過安全專家人工編寫,這種方式效率低下,且人工成本難以承受. 對於新出現的Gong JI和漏洞無法及時作出響應,檢測規則的編寫往往出現滯後的情況, 大家也許會考慮能否利用AI技術和數據融合技術進行智能化的數據挖掘呢,這些剛高級的黑科技在實際應用中往往生成的關聯規則檢測精度較低,檢測結果不理想,實際應用效果有限。利用人工神經網絡來自動生成關聯規則,是關聯分析研究領域今後發展的方向。
對於新手而言從一張白紙開始寫規則有些難了,但是對照系統給出的默認規則,照葫蘆畫瓢還是可以實現的,不管這個模型是否完善,先用起來,然後逐步修改。在合適的時間,對自己進行***,然後監控SIEM的反應,觀察它是否產生正確的警報,而警報是否提供足夠的信息來協助相應這弄清楚發生了什麼威脅,如果沒有那就需要修改規則,然後你需要不斷的優化閾值,你是否發現SIEM報警過於頻繁,或者非常稀少,你需要調節閾值來解決,順便說一句,面對動態的網絡Gong JI,這個調節的過程沒有終點如果讀者在學習關聯規則的過程中遇到各種問題也可以參考我的新書《開源安全運維平臺OSSIM疑難解析:提高篇》。
附件:
下面分享的是OSSIM關聯分析的一部分源代碼。
/* ** * 該指令是否與根節點指令匹配,這裏只檢查根節點,並不檢查指令的子節點** */gboolean sim_directive_match_by_event (SimDirective *directive, SimEvent *event) { SimRule *rule; gboolean match; g_return_val_if_fail (directive, FALSE); g_return_val_if_fail (SIM_IS_DIRECTIVE (directive), FALSE); g_return_val_if_fail (!directive->_priv->matched, FALSE); g_return_val_if_fail (directive->_priv->rule_root, FALSE); g_return_val_if_fail (directive->_priv->rule_root->data, FALSE); g_return_val_if_fail (SIM_IS_RULE (directive->_priv->rule_root->data), FALSE); g_return_val_if_fail (event, FALSE); g_return_val_if_fail (SIM_IS_EVENT (event), FALSE); rule = SIM_RULE (directive->_priv->rule_root->data); match = sim_rule_match_by_event (rule, event); return match; }/* ** *這將檢查事件是否可以與backlog中的某些數據匹配。backlog實際上是一個包含事件數據的指令。每個backlog條目都是一個樹,其中包含來自一個指令的所有規則(它相當於是一個指令克隆)。其中每個規則(simrule)還包含與規則匹配的事件的數據。** * */gboolean sim_directive_backlog_match_by_event (SimDirective *directive, SimEvent *event) { GNode *node = NULL; g_return_val_if_fail (directive, FALSE); g_return_val_if_fail (SIM_IS_DIRECTIVE (directive), FALSE); g_return_val_if_fail (!directive->_priv->matched, FALSE); g_return_val_if_fail (directive->_priv->rule_curr, FALSE); g_return_val_if_fail (directive->_priv->rule_curr->data, FALSE); g_return_val_if_fail (SIM_IS_RULE (directive->_priv->rule_curr->data), FALSE); g_return_val_if_fail (event, FALSE); g_return_val_if_fail (SIM_IS_EVENT (event), FALSE); node = directive->_priv->rule_curr->children; while (node) //**我們必須對照backlog中的所有規則節點檢查事件,除了根節點,因爲它簽入了sim_directive_match_by_event是從sim_organizer_correlation調用的.** { SimRule *rule = (SimRule *) node->data; if (sim_rule_match_by_event (rule, event)) { g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "sim_directive_backlog_match_by_event; sim_rule_match_by_event: True"); time_t time_last = time (NULL); directive->_priv->rule_curr = node; // 每次事件匹配時,該指令都下一級到匹配的節點。下次將根據此級別檢查事件。 //FIXME: 父節點中可能存在內存泄漏. directive->_priv->time_last = time_last; directive->_priv->time_out = sim_directive_get_rule_curr_time_out_max (directive); sim_rule_set_event_data (rule, event); //這裏我們將事件中的各個字段分配到規則中,所以每次我們進入規則時,我們可以看到匹配的事件. sim_rule_set_time_last (rule, time_last); if (!G_NODE_IS_LEAF (node)) { GNode *children = node->children; while (children) { SimRule *rule_child = (SimRule *) children->data; sim_rule_set_time_last (rule_child, time_last); sim_directive_set_rule_vars (directive, children); children = children->next; g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "sim_directive_backlog_match_by_event: There are childrens in %d directive", directive->_priv->id); } } else { directive->_priv->matched = TRUE; g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "sim_directive_backlog_match_by_event: The directive %d has matched", directive->_priv->id); } return TRUE; } else { g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "sim_directive_backlog_match_by_event: sim_rule_match_by_event: False"); } node = node->next; } return FALSE; }/* * 檢查指令中的所有節點規則,以查看....... */gboolean sim_directive_backlog_match_by_not (SimDirective *directive) { GNode *node = NULL; GNode *children = NULL; g_return_val_if_fail (directive, FALSE); g_return_val_if_fail (SIM_IS_DIRECTIVE (directive), FALSE); g_return_val_if_fail (!directive->_priv->matched, FALSE); g_return_val_if_fail (directive->_priv->rule_curr, FALSE); g_return_val_if_fail (directive->_priv->rule_curr->data, FALSE); g_return_val_if_fail (SIM_IS_RULE (directive->_priv->rule_curr->data), FALSE); node = directive->_priv->rule_curr->children; while (node) { SimRule *rule = (SimRule *) node->data; //如果規則已超時 && if ((sim_rule_is_time_out (rule)) && (sim_rule_get_not (rule)) && (!sim_rule_is_not_invalid (rule))) { time_t time_last = time (NULL); directive->_priv->rule_curr = node; directive->_priv->time_last = time_last; directive->_priv->time_out = sim_directive_get_rule_curr_time_out_max (directive); sim_rule_set_not_data (rule); if (!G_NODE_IS_LEAF (node)) //這不是最後的節點,他還有一些子節點. { children = node->children; while (children) { SimRule *rule_child = (SimRule *) children->data; sim_rule_set_time_last (rule_child, time_last); sim_directive_set_rule_vars (directive, children); children = children->next; } } else //last node! { directive->_priv->matched = TRUE; } return TRUE; } node = node->next; } return FALSE; }/* * backlog&directives幾乎是相同的:backlog是存儲指令並填充事件數據的地方。 *“node”是子節點函數。我們需要從引用其級別的節點向該節點添加src_ip、port等。如果“node”參數是根節點->子節點1->子節點2中的children2,並且我們在children2中有1:plugin-sid,那麼我們必須將根節點中的plugin-sid添加到children2中。 */void sim_directive_set_rule_vars (SimDirective *directive, GNode *node) { SimRule *rule; SimRule *rule_up; GNode *node_up; GList *vars; GInetAddr *ia; GInetAddr *sensor; gint port; gint sid; SimProtocolType protocol; gchar *aux = NULL; g_return_if_fail (directive); g_return_if_fail (SIM_IS_DIRECTIVE (directive)); g_return_if_fail (node); g_return_if_fail (g_node_depth (node) > 1); rule = (SimRule *) node->data; vars = sim_rule_get_vars (rule);