昨天 Day 9,我開始替 BehaviorGuard 加入 File Detection。
當時已經可以透過 watchdog 看到:
也建立了第一條:
BG-FILE-001
Sensitive File Modification
不過昨天還有一個很大的問題。
當時的架構其實是:
File Monitor
↓
看到 File Event
↓
顯示 Telemetry
Detection Rule 雖然寫好了,但測試時還是需要自己建立:
event = {
"action": "MODIFIED",
"path": "/tmp/behaviorguard_test/etc/passwd"
}
再手動送進 Detection Engine。
所以今天 Day 10 的目標就是:
把 File Monitor、Detection Engine 和 File Rules 真正串起來,並擴充 File Detection Rules。
昨天的 BG-FILE-001 同時處理:
MODIFIED
DELETED
但仔細想想,這兩個行為的意義並不完全相同。
例如:
/etc/passwd 被修改
跟:
/etc/passwd 被刪除
嚴重程度明顯不同。
所以今天首先把它拆成:
BG-FILE-001
Sensitive File Modification
Severity:HIGH
BG-FILE-002
Sensitive File Deletion
Severity:CRITICAL
目前 BehaviorGuard 關注的敏感檔案包括:
SENSITIVE_FILES = [
"/etc/passwd",
"/etc/shadow",
"/etc/sudoers",
"/etc/ssh/sshd_config"
]
這些檔案分別與:
使用者帳號
密碼驗證
sudo 權限
SSH Server
有關。
因此如果這些檔案出現非預期的修改或刪除,就比一般文字檔案值得注意。
第一條規則專門處理:
Sensitive File
+
MODIFIED
↓
BG-FILE-001
↓
HIGH
例如:
/etc/passwd
被修改時:
BG-FILE-001
Sensitive File Modification
HIGH
但如果只是:
notes.txt
被修改,就不應該產生這條 Alert。
這就是我這幾天一直在練習的一個觀念:
Event ≠ Alert
看到事件不代表一定要警告。
第二條規則則專門處理敏感檔案遭到刪除:
def detect_sensitive_file_deletion(event):
action = event.get("action", "").upper()
path = event.get("path", "")
test_prefix = "/tmp/behaviorguard_test"
normalized_path = path
if path.startswith(test_prefix):
normalized_path = path[len(test_prefix):]
if (
action == "DELETED"
and normalized_path in SENSITIVE_FILES
):
return {
"rule_id": "BG-FILE-002",
"rule_name": "Sensitive File Deletion",
"severity": "CRITICAL",
"description": (
f"Sensitive system file {normalized_path} "
f"was deleted."
)
}
return None
測試:
event = {
"action": "DELETED",
"path": "/tmp/behaviorguard_test/etc/passwd"
}
成功得到:
BG-FILE-002
Sensitive File Deletion
CRITICAL
而普通檔案遭到刪除則不會命中這條規則。
接下來開始觀察另一種行為:
系統的暫存位置突然出現 Script。
例如:
/tmp/update.sh
/tmp/install.py
/var/tmp/run.pl
/dev/shm/test.py
攻擊者有可能把下載或產生的腳本暫時放在這些位置。
但這裡要特別注意:
Script ≠ Malware
正常的系統管理員、開發人員或程式也可能在 /tmp 建立 Script。
所以目前這條 Rule 只設定:
MEDIUM
而不是看到 .sh 就直接 HIGH。
規則:
def detect_suspicious_script_creation(event):
action = event.get("action", "").upper()
path = event.get("path", "").lower()
if action != "CREATED":
return None
script_extensions = [
".sh",
".py",
".pl",
".rb"
]
suspicious_directories = [
"/tmp/",
"/var/tmp/",
"/dev/shm/"
]
is_script = any(
path.endswith(extension)
for extension in script_extensions
)
in_suspicious_directory = any(
path.startswith(directory)
for directory in suspicious_directories
)
if is_script and in_suspicious_directory:
return {
"rule_id": "BG-FILE-003",
"rule_name": "Suspicious Script Creation",
"severity": "MEDIUM",
"description": (
f"A script file was created in a temporary "
f"location: {path}"
)
}
return None
測試:
/tmp/update.sh
結果:
BG-FILE-003
Suspicious Script Creation
MEDIUM
但是:
/tmp/notes.txt
結果:
No Alert
因為它雖然在 /tmp,但不是 Script。
這代表規則開始加入多個條件,而不是只看單一特徵。
Linux 裡面,以 . 開頭的檔案通常會被視為 Hidden File,例如:
.bashrc
.profile
.gitconfig
所以:
Hidden File ≠ Malware
正常 Linux 系統本來就存在大量 Hidden Files。
因此我沒有設計成:
看到 .xxx
→ Alert
而是加入另一個條件:
Hidden File
+
Temporary Location
↓
BG-FILE-004
例如:
/tmp/.payload
就會產生:
BG-FILE-004
Hidden File Creation
MEDIUM
規則如下:
def detect_hidden_file_creation(event):
action = event.get("action", "").upper()
path = event.get("path", "")
if action != "CREATED":
return None
suspicious_directories = [
"/tmp/",
"/var/tmp/",
"/dev/shm/"
]
in_suspicious_directory = any(
path.startswith(directory)
for directory in suspicious_directories
)
filename = path.rsplit("/", 1)[-1]
is_hidden = (
filename.startswith(".")
and filename not in [".", ".."]
)
if in_suspicious_directory and is_hidden:
return {
"rule_id": "BG-FILE-004",
"rule_name": "Hidden File Creation",
"severity": "MEDIUM",
"description": (
f"A hidden file was created in a temporary "
f"location: {path}"
)
}
return None
測試:
/tmp/.payload
成功:
BG-FILE-004
Hidden File Creation
MEDIUM
但:
/tmp/payload
則:
No Alert
到這裡,BehaviorGuard 已經有四條 File Rules:
File Detection
│
├── BG-FILE-001
│ Sensitive File Modification
│ HIGH
│
├── BG-FILE-002
│ Sensitive File Deletion
│ CRITICAL
│
├── BG-FILE-003
│ Suspicious Script Creation
│ MEDIUM
│
└── BG-FILE-004
Hidden File Creation
MEDIUM
但是做到這裡,其實還只是:
自己建立 Event
↓
Detection Engine
↓
Rule Match
↓
Alert
所以今天最重要的一步,是把它真正接到 File Monitor。
我把:
from detection.engine import analyze_file_event
加入 file_monitor.py。
接著 watchdog 每次發現檔案事件時,不再只是:
print()
而是建立 BehaviorGuard Event:
event = {
"action": action,
"path": path
}
然後:
alerts = analyze_file_event(event)
整個架構因此變成:
Linux File System
↓
watchdog
↓
file_monitor.py
↓
File Event
↓
Detection Engine
↓
FILE_RULES
↓
Rule Match?
↓ ↓
YES NO
↓
Alert
這是今天最大的改變。
啟動 BehaviorGuard:
PYTHONPATH=. python agent/file_monitor.py
看到:
[BehaviorGuard] File Monitor started...
[BehaviorGuard] Watching: /tmp/behaviorguard_test
接著從另外一個 Terminal 開始製造檔案行為。
touch /tmp/behaviorguard_test/notes.txt
BehaviorGuard 看到了:
CREATED
MODIFIED
但:
No Alert
這是正確結果。
因為建立普通文字檔本來就是很正常的行為。
執行:
touch /tmp/behaviorguard_test/update.sh
BehaviorGuard 自動看到:
========== BehaviorGuard File Alert ==========
Rule : BG-FILE-003
Name : Suspicious Script Creation
Severity : MEDIUM
Action : CREATED
Path : /tmp/behaviorguard_test/update.sh
==============================================
代表:
watchdog
↓
File Monitor
↓
Detection Engine
↓
BG-FILE-003
整條流程成功。
執行:
touch /tmp/behaviorguard_test/.payload
成功:
Rule : BG-FILE-004
Name : Hidden File Creation
Severity : MEDIUM
我沒有真的去修改:
/etc/passwd
而是在 Lab 裡建立:
/tmp/behaviorguard_test/etc/passwd
讓 BehaviorGuard 在測試時把它視為:
/etc/passwd
這樣可以測試 Detection Logic,又不需要破壞自己的 Kali。
首先:
mkdir -p /tmp/behaviorguard_test/etc
touch /tmp/behaviorguard_test/etc/passwd
接著:
echo "test" >> /tmp/behaviorguard_test/etc/passwd
BehaviorGuard 自動產生:
Rule : BG-FILE-001
Name : Sensitive File Modification
Severity : HIGH
Action : MODIFIED
最後:
rm /tmp/behaviorguard_test/etc/passwd
則得到:
Rule : BG-FILE-002
Name : Sensitive File Deletion
Severity : CRITICAL
Action : DELETED
四條 File Detection Rules 全部成功進入即時偵測流程。
今天測試的時候還發現一件很有趣的事情。
我只執行一次:
echo "test" >> /tmp/behaviorguard_test/etc/passwd
但 BehaviorGuard 卻看到了不只一個:
MODIFIED
因此:
BG-FILE-001
也跟著出現兩次。
一開始我以為程式是不是寫錯了,但後來理解到:
使用者的一個操作,不一定只對應一個底層 File System Event。
這也是 Telemetry 很重要的一個問題。
可能變成:
使用者執行一次操作
↓
產生多個 Telemetry Events
↓
Rule 重複命中
↓
Alert
Alert
Alert
如果放到真實企業環境,這會產生非常大的問題。
假設某個行為實際只發生一次,但 Detection System 產生:
HIGH
HIGH
HIGH
HIGH
HIGH
SOC 分析師就需要面對很多其實是在描述同一件事情的 Alert。
當系統每天處理大量端點事件時,如果沒有控制這些重複 Alert,就可能造成:
大量 Telemetry
↓
大量 Detection
↓
大量 Alert
↓
SOC 分析師負擔增加
↓
Alert Fatigue
這也是我開始發現:
Detection 不是「規則越多越好」。
真正困難的是:
怎麼降低雜訊?
怎麼降低 False Positive?
怎麼避免 Duplicate Alert?
怎麼保留真正重要的訊號?
因此今天測試完之後,下一個問題已經自然出現了:
同一個 Rule
+
同一個 File
+
同一個 Action
+
短時間重複出現
是不是應該一直 Alert?
例如:
10:00:01
BG-FILE-001
/etc/passwd
MODIFIED
→ ALERT
10:00:01
BG-FILE-001
/etc/passwd
MODIFIED
→ ALERT
10:00:02
BG-FILE-001
/etc/passwd
MODIFIED
→ ALERT
未來希望能變成:
第一個
→ ALERT
短時間內重複
→ SUPPRESSED
這就是:
Deduplication
Alert Suppression
也會成為 Day 11 要處理的問題。
今天也先整理一個之後很重要的觀念。
Deduplication 是:
這幾個 Alert
是不是其實同一件事情?
目的是:
減少重複 Alert
Correlation 則是:
這幾個「不同」的 Alert
是不是其實屬於同一條攻擊鏈?
例如未來 BehaviorGuard 可能看到:
curl 下載內容
↓
建立 update.sh
↓
Python / Shell 執行
↓
External Connection
↓
修改系統設定
這些不能 Deduplicate,因為它們是不同的事件。
但未來可以透過 Correlation 把它們關聯:
Command Alert
+
File Alert
+
Process Alert
+
Network Alert
↓
Correlation
↓
Suspicious Attack Chain
這也是 BehaviorGuard 後面想繼續發展的方向。
目前 Detection Rules 已經逐漸增加:
BehaviorGuard Detection
Process Detection
├── BG-PROC-001
└── BG-PROC-002
Command Detection
├── BG-CMD-001
└── BG-CMD-002
Network Detection
├── BG-NET-001
├── BG-NET-002
├── BG-NET-003
├── BG-NET-004
├── BG-NET-005
└── BG-NET-006
File Detection
├── BG-FILE-001
├── BG-FILE-002
├── BG-FILE-003
└── BG-FILE-004
目前共:
14 條 Detection Rules
今天最大的進展不是單純把 File Rule 從一條增加到四條。
真正重要的是把:
File Telemetry
和:
Detection Engine
正式串起來。
現在 BehaviorGuard 的 File Detection 已經可以:
Linux File System
↓
Telemetry
↓
Detection Engine
↓
Detection Rules
↓
Security Alert
而今天實際測試又發現了新的問題:
Duplicate Alert
這讓我開始理解,EDR / Detection System 並不是:
「抓越多越好」
而是要思考:
哪些是正常事件?
哪些值得 Alert?
哪些 Alert 是重複的?
哪些不同 Alert 其實有關聯?
所以目前 BehaviorGuard 正慢慢從:
單純監控
進入:
Telemetry
↓
Detection
↓
Alert
↓
Deduplication
↓
Correlation
↓
Risk
↓
Response
Day 11,我會先處理今天實際遇到的 Duplicate Alert,加入 Alert Deduplication / Suppression,讓 BehaviorGuard 開始學會「不是每一次 Rule Match 都需要重新吵一次」。