在 Day25,我們成功將 Process Monitor、Network Monitor、Correlation Engine 和 Response Dispatcher 整合成一套 Unified Event Pipeline。
當 Linux 出現可疑行為時,BehaviorGuard 已經可以自動偵測、建立 Event ID、記錄 Alert,並根據風險等級產生 Response 決策。
不過,當時還有一個很重要的問題:
我們的系統雖然能夠偵測可疑行為,卻還不能由正式監控事件直接觸發真正的防禦動作。
例如偵測到 HIGH Alert 時,系統只會顯示:
Decision : REVIEW_REQUIRED
Execution : DRY RUN
Executed : False
這代表系統認為事件值得處理,但實際上還沒有終止程序或阻斷連線。
因此,Day26 的目標是讓 BehaviorGuard 從 Detection(偵測)進一步走向 Auto Response(自動回應)。
今天主要完成:
本次所有實際處置都限制在 Kali Linux 的受控測試環境,沒有開放對任意程序或外部 IP 自動執行防禦。
在資安領域中,Detection 和 Response 是兩個不同的階段。
Detection 的工作是發現可疑行為。
例如:
Rule : BG-NET-001
Name : Suspicious Network Listener
Severity : HIGH
Process : socat
這只能代表系統發現某個網路程序符合可疑行為規則。
但發現問題後,還要決定該如何處理。
這就是 Response 的工作。
常見的端點回應方式包括:
如果 Response 需要分析人員手動執行,就屬於人工處置。
如果系統能在符合安全策略後自動執行,就屬於 Auto Response。
我們今天主要實作其中兩項:
SIGTERM:終止受控測試程序。
nftables:暫時阻斷指定測試 IP。
但 Auto Response 也有風險。
如果正常程序被誤判成惡意程序,系統又直接將它終止,可能造成正常服務中斷。
因此,真正的 Auto Response 不應該只是:
HIGH Alert
↓
直接終止程序
而應該是:
Detection Alert
↓
Response Policy
↓
檢查授權與目標
↓
ALLOW / DENY / DRY RUN
↓
執行符合條件的處置
↓
Response Verification
↓
Audit Log
這也是今天最重要的設計概念。
今天首先新增:
response/auto_policy.py
這個模組的工作不是直接執行防禦,而是決定某項處置是否被允許。
我們建立三種主要決策:
| Decision | 意義 |
|---|---|
| ALLOW | 通過目前這一層策略檢查 |
| DENY | 不符合授權或目標限制,拒絕處置 |
| DRY_RUN | 只模擬決策,不執行實際處置 |
其中 DRY_RUN 特別重要。
例如一筆真正的 HIGH Network Alert:
alert = {
"rule": "BG-NET-001",
"source": "NETWORK",
"severity": "HIGH",
"dst_ip": "8.8.8.8"
}
即使它的 Severity 是 HIGH,也不能代表 8.8.8.8 就是惡意 IP。
因此我們的 Policy 會判斷:
if source != "CONTROLLED_LAB":
result["decision"] = "DRY_RUN"
result["reason"] = (
"Live detection requires additional approval"
)
return result
也就是說,一般真實監控事件不會只因為 Severity 很高就直接執行破壞性操作。
另外,我們將 Network Blocking 的實驗目標限制為:
TEST_IP = "127.0.0.2"
如果要求封鎖其他 IP,Policy 就會拒絕。
執行:
PYTHONPATH=. python3 test_day26_policy.py
得到:
Test : Real HIGH Process Alert
Decision : DRY_RUN
[PASS]
Test : Real HIGH Network Alert
Decision : DRY_RUN
[PASS]
Test : Unauthorized Lab Process
Decision : DENY
[PASS]
Test : Authorized Lab Process
Decision : ALLOW
[PASS]
Test : Authorized Lab Network
Decision : ALLOW
[PASS]
Test : Unapproved IP
Decision : DENY
[PASS]
Total: 6/6 PASS
這次驗證了六種情況,包含正常監控告警、未授權處置、受控實驗及未核准 IP。
不過,要特別注意:
Policy 回傳 ALLOW,不代表可以直接終止任意 PID。
它只代表通過第一層策略,後面仍然需要確認程序身分、命令內容,以及它是否真的是預先註冊的測試程序。
接下來我們修改:
response/dispatcher.py
在原本的 Response Dispatcher 前面增加 Policy 檢查。
原本的 Dispatcher 可以根據 Severity 決定:
MEDIUM → INVESTIGATE
HIGH → REVIEW_REQUIRED
今天則增加:
policy = evaluate_auto_response(
alert,
action,
lab_authorized=False
)
這裡刻意將一般監控事件的 lab_authorized 設為 False。
這樣即使有人在 Alert 裡提供看似允許的資料,也不會單靠 Alert 內容就取得實際處置授權。
我們同時新增一筆 Policy Audit:
log_response(
rule=rule,
action="AUTO_POLICY",
target=policy["target"],
status=policy["decision"],
reason=policy["reason"],
event_id=alert.get("event_id"),
source=source
)
這裡的 Event ID 是 Day25 加入的功能。
有了 Event ID,我們就能知道某筆 Policy 決策是由哪一筆 Detection Alert 觸發。
實際輸出:
========== Day26 Auto Response Policy ==========
Rule : BG-NET-001
Source : NETWORK
Severity : HIGH
Action : BLOCK
Decision : DRY_RUN
Reason : Live detection requires additional approval
Executed : False
原本的 Dispatcher 也正常:
Decision : REVIEW_REQUIRED
Execution : DRY RUN
最後成功記錄:
[AUDIT] RESPONSE_DECISION -> REVIEW_REQUIRED
[AUDIT] AUTO_POLICY -> DRY_RUN
這代表新的 Policy 沒有破壞 Day25 的 Response 功能。
完成 Policy 後,我們開始實作今天最重要的功能之一:
讓真正的 Process Monitor 偵測到 Alert 後,自動終止符合嚴格條件的測試程序。
之前 Day22~24 雖然已經測試過 SIGTERM,但主要是測試程式直接呼叫終止函式。
這次的不同之處,是必須從真正的 Detection Alert 開始。
我們選擇使用 Day5 建立的:
BG-CMD-002
Python Inline Code Execution
這條規則可以偵測類似:
python3 -c 'import time; time.sleep(30)'
的 Python Inline Execution。
不過,python3 -c 並不一定是惡意行為。
正常開發、系統管理及自動化測試都可能使用。
所以我們不會把所有 BG-CMD-002 Alert 都設定成自動終止。
我們新增:
response/lab_process_registry.py
只有由測試程式使用 subprocess.Popen() 建立,且符合指定命令的程序,才可以註冊。
例如:
proc = subprocess.Popen([
sys.executable,
"-c",
"import time; time.sleep(30)"
])
我們會記錄該程序的 PID 與建立時的身分資訊。
在真正終止前,再重新確認程序仍是原本註冊的目標。
這麼做是因為 Linux PID 可能被重複利用。
假設 PID 5000 的程序已經結束,Linux 未來可能將 PID 5000 分配給其他程序。
如果只檢查 PID,就可能終止錯誤對象。
因此我們還會檢查程序名稱、執行檔、命令及建立時間等資訊。
這降低了錯誤處置風險,但仍不是完整消除 PID 競爭條件的正式產品級方案。
第一次執行:
PYTHONPATH=. python3 -u test_day26_live_terminate.py
結果顯示:
[TEST] Registered process PID: 2849139
[PASS] Test process registered
Detection Engine 也成功觸發:
[ALERT] BG-CMD-002
Rule : Python Inline Code Execution
Severity : MEDIUM
但是最後出現:
RuntimeError:
Monitor did not terminate the test process
為什麼 Detection 成功,程序卻沒有終止?
檢查後發現 process_monitor.py 仍然使用舊的 Response 流程。
所以雖然能觸發 Detection,也可以記錄 Response 決策,但沒有經過 Day26 新增的 Live Auto Response Hook。
我們將 Process Monitor 改為統一呼叫:
ingest_alert(
normalized_alert,
"PROCESS"
)
讓 Alert 進入 Unified Event Pipeline,再由 Pipeline 呼叫 Live Response。
重新測試後:
========== BehaviorGuard Pipeline ==========
Event ID : bd4aa6b8-bd33-4ce4-97f6-57bec739e9ab
Source : PROCESS
Rule : BG-CMD-002
接著一般 Policy 仍然顯示:
Decision : DRY_RUN
Executed : False
但系統另外確認這筆 Alert 的 PID 確實屬於事先註冊的測試程序,於是執行受控自動終止:
[AUDIT] AUTO_TERMINATE_LAB -> SUCCESS
[AUTO RESPONSE] Registered process: SUCCESS
最後測試成功:
[PASS] Real Monitor triggered termination
[PASS] Process exited
[PASS] Response Audit recorded
Event ID:
bd4aa6b8-bd33-4ce4-97f6-57bec739e9ab
這次最重要的成果,是完成真正的:
Linux Process
↓
Process Monitor
↓
BG-CMD-002
↓
Unified Pipeline
↓
受控程序身分驗證
↓
SIGTERM
↓
Response Audit
也就是讓真正的監控事件觸發實際程序終止,而不是只有人工呼叫測試函式。
完成 Process Auto Response 後,我們開始進行 Network Auto Response。
在 Day24,我們已經使用 nftables 成功阻斷指定 IP。
當時使用的是一般 Drop Rule:
ip daddr 127.0.0.2 counter drop
但這樣有一個問題:
只要規則沒有被手動刪除,就可能持續存在。
如果 Response 程式異常停止,或沒有執行解除函式,可能導致封鎖狀態持續。
因此今天我們改用 nftables 的 Timeout Set。
Set 可以理解成 nftables 管理的一組資料。
例如我們建立:
blocked_ips
用來保存目前需要封鎖的 IP。
再讓防火牆規則比對這個 Set。
封包目的 IP
↓
是否存在 blocked_ips?
↓
YES → DROP
NO → 不由此規則阻斷
我們還可以為 Set 元素指定 Timeout。
例如:
127.0.0.2 timeout 30s
表示這個 IP 的封鎖元素會在 30 秒後到期。
今天測試使用:
table ip bg_day26
其中包含:
table ip bg_day26 {
set blocked_ips {
type ipv4_addr
flags timeout
timeout 30s
}
chain output {
type filter hook output priority 0; policy accept;
ip daddr @blocked_ips counter drop
}
}
幾個重要名詞:
| 名詞 | 說明 |
|---|---|
| table | nftables 規則的管理容器 |
| chain | 定義封包要經過的規則鏈 |
| output | 處理由本機送出的封包 |
| set | 儲存要比對的 IP 集合 |
| timeout | 指定元素有效期限 |
| drop | 丟棄符合條件的封包 |
這裡的 output 代表我們阻斷的是 Kali Linux 本機對指定目的 IP 發出的流量。
它不是將整台電腦從網路中隔離。
我們新增:
response/timed_network_blocker.py
並先進行獨立測試。
結果:
[PASS] Temporary firewall table created
[PASS] Temporary block installed
查看 nftables Set:
elements = {
127.0.0.2 expires 29s988ms
}
這表示 nftables 正在倒數封鎖期限。
接著使用 Ping 測試:
[PASS] Ping blocked during active rule
等待封鎖到期後:
[PASS] Block element automatically expired
[PASS] Connectivity restored
[PASS] Test table removed
這次證明:
封鎖元素會由 Linux 核心管理到期,不需要依靠 Python 在指定時間手動刪除元素。
需要注意,到期的是 Set 裡面的 IP 元素,並不是整個 nftables Table。
所以我們也加入測試完成後的 Table 清理程序。
完成限時封鎖後,我們接著將它整合進:
response/live_auto_response.py
這次使用 Day7 建立的規則:
BG-NET-001
Suspicious Network Listener
這條規則會偵測 nc、ncat、socat 等工具建立 TCP Listener 的行為。
為了避免誤判造成不必要的封鎖,我們新增:
response/lab_network_registry.py
只有符合預先登記的實驗程序,才能進入真正的封鎖流程。
本次使用:
socat TCP-LISTEN:19999,bind=127.0.0.1,reuseaddr -
也就是讓 socat 在本機:
127.0.0.1:19999
建立 TCP Listener。
因為 BG-NET-001 偵測的是監聽 Socket。
一個正在 LISTEN 的 Socket,並不一定已經有遠端連線。
例如今天的事件:
State : LISTEN
Remote : 0.0.0.0:*:0
這並不是可直接當作惡意來源的 IP。
因此,我們沒有從 Alert 中猜測封鎖目標,而是另外指定受控實驗 IP:
127.0.0.2
真正的 Network Alert 只負責觸發受控實驗流程,封鎖目標則由事先設定的 Policy 限制。
這是本次測試的重要安全設計。
最後執行:
PYTHONPATH=. python3 -u test_day26_live_network.py
[PASS] Controlled socat registered
[TEST] PID: 2854656
Network Monitor 成功收集:
Process : socat
PID : 2854656
State : LISTEN
Local : 127.0.0.1:19999
========== BehaviorGuard Network Alert ==========
Rule : BG-NET-001
Name : Suspicious Network Listener
Severity : HIGH
Process : socat
PID : 2854656
這是真正的 Linux 網路行為,不是手動建立的假 Alert。
========== BehaviorGuard Pipeline ==========
Event ID : 96750ac5-292b-49e3-846c-3b8ba2bdf397
Source : NETWORK
Rule : BG-NET-001
[INFO] Alert saved to logs/alerts.jsonl
這代表 Network Detection 已經接進 Day25 建立的 Pipeline。
一般 Response Policy 顯示:
Decision : DRY_RUN
Executed : False
Dispatcher 則顯示:
Decision : REVIEW_REQUIRED
Execution : DRY RUN
但系統也會另外檢查:
全部通過,才允許這個受控實驗進行真正的 IP Blocking。
最重要的輸出:
[AUDIT] AUTO_BLOCK_LAB -> SUCCESS
[AUTO NETWORK] Temporary block: SUCCESS
[PASS] Real Network Alert triggered BLOCK
[PASS] Response Audit linked
這代表真正的 Network Alert 已經自動觸發 nftables 封鎖。
而且封鎖成功後,系統也確認限時元素確實存在:
[PASS] nftables timed element active
等待 30 秒後:
[AUDIT] AUTO_UNBLOCK_LAB -> SUCCESS
[PASS] Timed block expired
[PASS] Connectivity restored
[PASS] Unblock Audit linked
[PASS] Test table cleaned
這代表系統不只會執行封鎖,也會驗證封鎖是否到期,以及網路連線是否恢復。
最後清除本次測試建立的 nftables Table,避免影響後續實驗。
今天的 Process 和 Network Response 都有一個共同設計:
每筆 Detection Event 都有 Event ID。
例如這次 Network Alert:
96750ac5-292b-49e3-846c-3b8ba2bdf397
這個 ID 可以對應到不同階段的處置紀錄。
Detection Alert
↓
Event ID
↓
AUTO_POLICY
↓
AUTO_BLOCK_LAB
↓
AUTO_UNBLOCK_LAB
本次實際紀錄包含:
[AUDIT] AUTO_POLICY -> DRY_RUN
[AUDIT] AUTO_BLOCK_LAB -> SUCCESS
[AUDIT] AUTO_UNBLOCK_LAB -> SUCCESS
其中 DRY_RUN 與 SUCCESS 並不矛盾。
DRY_RUN 表示一般正式監控事件沒有獲得任意執行防禦的權限。
SUCCESS 則代表額外的受控實驗檢查通過後,對事先限定的測試目標成功執行了處置。
透過這些紀錄,我們可以追蹤:
對 SOC 分析人員來說,Response 不應該只留下「成功」兩個字,而是應該能追溯處置原因與結果。
今天我們完成了以下功能:
| 功能 | 測試結果 |
|---|---|
| Auto Response Policy | 6/6 PASS |
| Policy 整合 Dispatcher | PASS |
| 真實 Process Alert 觸發 SIGTERM | PASS |
| 受控程序身分驗證 | PASS |
| SIGTERM 結果驗證 | PASS |
| Process Response Audit | PASS |
| nftables Temporary Blocking | PASS |
| 真實 Network Alert 觸發 BLOCK | PASS |
| 30 秒限時封鎖 | PASS |
| 封鎖期間連線阻斷驗證 | PASS |
| 封鎖到期自動解除 | PASS |
| 解除後連線恢復 | PASS |
| Network Response Audit | PASS |
| 測試防火牆表格清理 | PASS |
不過目前還有一些限制。
首先,自動 SIGTERM 和 IP Blocking 只對預先註冊的受控測試目標開放,並不是任意真實威脅都能自動處置。
其次,目前的程序身分驗證仍有改進空間,例如進一步降低 PID 重複利用與檢查、終止之間的競爭條件。
最後,雖然限時阻斷元素可以自行到期,但異常狀況下的資源清理、權限隔離、重複封鎖及系統重啟復原,仍需要後續完善。
因此,BehaviorGuard 現階段仍然是研究與實驗用途的 Linux EDR 原型,而不是可直接部署到正式企業環境的防護產品。
今天是目前 BehaviorGuard 開發過程中,我認為非常重要的一天。
前面幾天,我們花了不少時間寫 Detection Rules,讓 Linux 能夠偵測可疑程序、Shell 指令、網路連線、檔案異動,以及 Persistence 行為。
但我最初規劃這個專題時,就不希望它最後只是顯示很多 Alert。
因為在真實的資安環境中,發現可疑行為只是第一步,後面還有判斷、處置與驗證的工作。
今天最大的進步,就是讓 BehaviorGuard 真正執行了兩種 Response:
第一種是透過真實 Process Alert,自動終止事先註冊的測試程序。
第二種是透過真實 Network Alert,自動執行 nftables 限時 IP Blocking。
而且這次不只驗證防禦是否執行,還確認程序是否真的退出、網路是否真的被阻斷,以及到期後能否恢復。
開發過程中也遇到不少問題。
例如第一次進行 Process Auto Response 時,雖然 BG-CMD-002 成功觸發,程序卻沒有被終止。
後來才發現 Process Monitor 還沒有接到正確的 Unified Pipeline。
這讓我更清楚理解,程式裡面即使已經寫好 Response 函式,也不代表實際的 Detection Alert 一定能走到那個函式。
另外,我也學到 nftables 不只能建立一般的 Drop Rule,還可以利用 Set Timeout 讓封鎖元素自動到期。
這對自動防禦來說很重要,因為如果只考慮如何封鎖,卻沒有考慮如何恢復,一旦發生誤判,防禦機制本身也可能造成服務中斷。
今天最大的心得是:好的資安自動防禦,不只是知道什麼時候要執行 Response,更重要的是知道什麼情況下不能執行,以及執行後如何安全恢復。
經過 Day26,BehaviorGuard 已經從原本以 Detection 為主的工具,逐步發展成具有真實受控 Auto Response 能力的 Linux Endpoint Security 原型。
接下來 Day27,我們將回頭檢查所有已建立的 Detection Rules,確認 Process、Network、File 和 Persistence Alert 是否都能進入 Unified Pipeline,並進一步完成 Multi-Source Correlation。
讓 BehaviorGuard 不只是看見單一可疑行為,也能分析多個行為之間是否形成一條完整的攻擊鏈。
Day26 完成。