接續前面的內容
先告訴一個小秘密,再告訴大家一個神奇的地方
第一個小祕密就是
wazuh的log蒐集是可以用Wildcard的形式去表達
這個非常好用!
讓我解釋一下為什麼
因為實務上某些服務可能會做cluster或replica set
所以會有很多個log
目錄結構可能類似這樣
/var/log/c1/service.log
/var/log/c2/service.log
/var/log/c3/service.log
又或者
/data/log/service1.log
/data/log/service2.log
/data/log/service3.log
又甚至是一個目錄下有很多log
/data/service-log/app.log
/data/service-log/error.log
/data/service-log/service.log
這樣的情況我們就可以通過wildcard方式一次蒐集到全部
例如使用
/var/log/c*/service.log
or
/data/log/service*.log
or
/data/service-log/*.log
去捕捉到上面目錄底下的log
下一個要告訴大家的是 wazuh dashboard 消失的密室
你可以在 wazuh dashboard 找到詳細的config資訊
看到這個agent有蒐集那些log
點選指定的Agent之後,右方的Configuration,然後左側的Log collection
就可以看到有目前有收集那些Log檔案
我們有注意到,在nginx的agent中,
我們先前指定的nginx log已經有被推送過來
我們也有測試過,確認nginx的alert觸發是正常的
這個地方我自己覺得有夠難找啦 XD
以前第一次不小心點進來過,後來花好久時間找不到在哪裡
接下來
我們到mongodb的主機,
把/data/mongo/mongod.log加入到ossec.conf當中
我們測試一下登入成功或失敗的操作
mongosh -u userAdmin -p 'wrongPassword' --authenticationDatabase admin
mongosh -u userAdmin -p 'userPassword' --authenticationDatabase admin
會發現沒有觸發alert
記得確認mognodb主機上是否有產生log
確實有,但是居然卻沒有觸發
真相只有一個,BUG卻有好多個
總之我們又要來debug了
我們在wazuh github當中
先確認其實是有針對於mongodb的decoder跟rule的
我們這邊來做兩件事情測試
第一個是我們將log進行test
會發現沒有成功觸發
2023-09-27T12:14:50.498+0000 I ACCESS [conn2] SASL SCRAM-SHA-256 authentication failed for userAdmin on admin from client 172.25.0.1:55036 ; AuthenticationFailed: SCRAM authentication failed, storedKey mismatch
2023-09-27T12:14:53.735+0000 I ACCESS [conn4] Successfully authenticated as principal userAdmin on admin from client 172.25.0.1:55054
第二個是我們在server上面利用tcpdump錄封包
我們來確認看看agent是否有將log推送到server
所以我們可以排除問題不在agent
這邊要有個觀念
agent會負責將log當中每一行給推送到server (無論內容是甚麼)
server負責解析內容是否符合decoder會成為event,
而每一個event符合特定rult達到一定等級的level才會成為alert
alert才會推到wazuh indexer顯示在我們的wazhu dashboard
接著來介紹關於decoder的部分
首先所有的decoder內容我們可以在系統上的檔案中看到
也可以從dashboard上看到
也可以從github source code看到
個人覺得從網頁來看是滿方便的,我經常會到github去看
不過要注意這種方式不是最恰當的
因為你不確定你系統上的設定跟github上是否完全相同
https://github.com/wazuh/wazuh/tree/master/ruleset/decoders
跟rule一樣,wazuh也允許我們自定義,
自行撰寫屬於我們客製的decoder,語法可以參考官網
https://documentation.wazuh.com/current/user-manual/ruleset/ruleset-xml-syntax/decoders.html
寫法基本上也不算太困難
首先一定要定義一個decoder name
接下來通常會使用prematch來決定符合甚麼樣格式的log
會被歸類在這一個decoder
如果premtach有符合了,就會列入屬於該decoder
接下來我們才利用regex區分欄位
premtach以及regex可以寫在同一條或是不同條都可以
有regex,就需要有另一個欄位order來定義每個欄位的名稱
這樣其實已經足以應付許多簡單的場景
當然要做到更加詳細的分組、分析、比對,就需要了解更多其他的欄位有甚麼用途
以官方的教學範例來說
假設LOG的格式如下
date=2019-10-10 time=17:01:31 devname="FG111E-INFT2"
利用prematch寫parse去匹配每一個進來的LOG
假設有匹配到,這一行就會被列為fortigate-custom這個decoder
<decoder name="fortigate-custom">
<prematch>^date=\d\d\d\d-\d\d-\d\d time=\d\d:\d\d:\d\d devname="\S+"</prematch>
</decoder>
接著我們要去建立event的欄位
利用parent去觸發fortigate-custom進入這條規則
然後透過regex搭配order去建立欄位
可以看到在regex的地方有三個 括號()
order的地方定義了date, time, devname
所以第一個()中的內容會是data這個欄位,以此類推
這樣就建立完欄位
<decoder name="fortigate-custom1">
<parent>fortigate-custom</parent>
<regex>^date=(\d\d\d\d-\d\d-\d\d) time=(\d\d:\d\d:\d\d) devname="(\S+)"</regex>
<order>date, time, devname</order>
</decoder>
在撰寫alert rule時,就需要去指定觸發的decoder
<rule id="222000" level="3">
<decoded_as>fortigate-custom</decoded_as>
<description>Fortigate messages grouped.</description>
</rule>
我們在剛剛rule測試的過程中
會發現,讚唷,mongodb的Log真的解析不到
2023-09-27T12:14:50.498+0000 I ACCESS [conn2] SASL SCRAM-SHA-256 authentication failed for userAdmin on admin from client 172.25.0.1:55036 ; AuthenticationFailed: SCRAM authentication failed, storedKey mismatch
但我看過官方寫的regex是沒有錯的
感覺可能是pre-decode那邊把timestamp拉出來導致的錯誤
總之我自己是重寫了一個decoder跟rule來強制match內容
但因為作法很骯髒我就不教了
教一個更簡單省事的方法
就是阿...我們直接升級mongodb!!!
monogodb升級到4.4版本之後
預設使用JSON格式的log
我們在登入成功跟失敗會得到以下的LOG
{"t":{"$date":"2023-09-27T12:30:35.133+00:00"},"s":"I", "c":"ACCESS", "id":20249, "ctx":"conn6","msg":"Authentication failed","attr":{"mechanism":"SCRAM-SHA-256","speculative":true,"principalName":"userAdmin","authenticationDatabase":"admin","remote":"172.18.0.1:57220","extraInfo":{},"error":"AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"}}
{"t":{"$date":"2023-09-27T12:30:27.019+00:00"},"s":"I", "c":"ACCESS", "id":20250, "ctx":"conn2","msg":"Authentication succeeded","attr":{"mechanism":"SCRAM-SHA-256","speculative":true,"principalName":"userAdmin","authenticationDatabase":"admin","remote":"172.18.0.1:46248","extraInfo":{}}}
你可以想說,欸這樣跟官方預設的decoder不是不同嗎
沒錯!這表示我們還是得自己來
但JSON就很好寫規則了
而且可以稍微照抄一下原本Wazuh Mongodb的規則
這邊除了操作跟撰寫規則以外
其實很重要的一個觀念還是你要監控”甚麼”
在撰寫之前其實要想想看你希望甚麼樣的事件被觸發?
例如我們想要監控登入成功跟登入失敗
接著就要知道登入成功跟失敗會有甚麼特徵跟pattern
然後這個特徵跟pattern不會被其他誤觸
例如我們不能監控一個fail 就當成登入失敗
有可能是sql command fail, connection fail …許多類似場景都有fail這個pattern
以下的內容, 我們透過規則100501
去匹配符合json decoder,然後JSON有名稱為c,ctx,msg,s的欄位
欄位內容是使用 .+ 去作為全匹配
也就是說有這個欄位就好,不管內容是甚麼
100501觸發之後
會經過100502跟100503去檢查
如果欄位msg內容有包含Authentication succeeded就觸發100502
如果欄位msg內容有包含Authentication failed就觸發100503
我們也可以直接測試看看
<!-- Rule for Mongodb JSON -->
<rule id="100501" level="0">
<decoded_as>json</decoded_as>
<field name="c">\.+</field>
<field name="ctx">\.+</field>
<field name="msg">\.+</field>
<field name="s">\.+</field>
<field name="t.$date">\.+</field>
<description>MongoDB JSON LOG messages.</description>
<group>mongodb</group>
</rule>
<rule id="100502" level="3">
<if_sid>100501</if_sid>
<field name="msg">Authentication succeeded</field>
<description>MongoDB: Successfully authentication.</description>
<group>mongodb</group>
</rule>
<rule id="100503" level="3">
<if_sid>100501</if_sid>
<field name="msg">Authentication failed</field>
<description>MongoDB: Failed authentication.</description>
<group>mongodb</group>
</rule>
提醒一下
規則撰寫完之後可以先Save 不用restart
Ruleset Test確認有work之後才Restart
然後Ruleset Test會keep住前一次的Session
所以每次測試的時候建議多clear session避免用到的是之前的rule