iT邦幫忙

0

Day15 PID 不一樣也能看出關係-BehaviorGuard Process Tree Correlation

  • 分享至 

  • xImage
  •  

昨天 Day14,我替 BehaviorGuard 加入了 Correlation Engine。

原本獨立的 Alert:

BG-CMD-002
Python Inline Code Execution

BG-NET-005
Shell or Interpreter Network Activity

BG-NET-003
Unexpected External Connection

已經可以透過:

Time Window
+
Same PID
+
Rule Sequence
+
Duplicate Suppression

串成一條 Attack Chain。

例如:

BG-CMD-002
        ↓
BG-NET-005
        ↓
BG-NET-003
        ↓
BG-CORR-005
CRITICAL

但是昨天的版本其實還存在一個非常大的限制:

三個 Alert 必須來自同一個 PID。

也就是:

BG-CMD-002   PID 7000
        ↓
BG-NET-005   PID 7000
        ↓
BG-NET-003   PID 7000

才能被 BehaviorGuard 關聯。

但真實 Linux 系統裡,攻擊行為通常不會永遠待在同一個 Process。

因此 Day15 要解決的問題就是:

Process Tree Correlation

讓 BehaviorGuard 不只知道:

「這是不是同一個 PID?」

還能進一步知道:

「雖然 PID 不同,但這些 Process 是不是其實有 Parent / Child 關係?」

一、先重新理解 PID 與 PPID

Linux 裡,每一個 Process 都有自己的:

PID
Process ID

例如:

python3
PID = 2306118

PID 可以理解成這個 Process 的「編號」。

但是 Process 通常不是憑空產生的。

很多 Process 都是由另外一個 Process 建立。

因此 Linux 還有:

PPID
Parent Process ID

也就是:

建立我的 Process 是誰?

例如今天實際測試時,BehaviorGuard 抓到:

PID       : 2306118
PPID      : 2306074
Process   : python3
Parent    : bash
Ancestors : [2306074, 2306000, 2305992, 1]

這代表:

python3
PID 2306118

它的 Parent:
bash
PID 2306074

因此:

python3 的 PPID
=
bash 的 PID

也就是:

bash
PID 2306074
     ↓
python3
PID 2306118
PPID 2306074

這就是最基本的 Parent / Child Process 關係。


二、Process Tree 是什麼?

如果 Child Process 又建立新的 Process:

bash
↓
python3
↓
sleep

每一層都有自己的 PID。

例如:

bash
PID 7000
   ↓
python3
PID 7010
PPID 7000
   ↓
nc
PID 7020
PPID 7010

這就形成一棵:

Process Tree

也可以稱為:

Process Lineage

Lineage 可以理解成「血緣關係」。

如果從 PID 7020 往上找:

7020
↑
7010
↑
7000

那:

7010
7000

就是 PID 7020 的 Ancestors。

因此可以表示成:

ancestors = [7010, 7000]

三、為什麼 EDR 很重視 Process Tree?

只看單一 Process 時:

python3

不一定可疑。

只看到:

bash

也不一定可疑。

只看到:

nc

也不能直接說它一定是攻擊。

但是如果看到:

apache2
   ↓
bash
   ↓
python3
   ↓
nc

事情就完全不一樣了。

因為 Process Tree 提供了一個很重要的資訊:

Context

也就是:

「這個 Process 到底是誰啟動的?」

例如:

使用者 Terminal
↓
bash

很正常。

但:

Web Server
↓
bash

可能就比較值得注意。

再例如:

bash
↓
python3
↓
network connection

如果這些行為又同時命中多條 Detection Rule,就更有可能屬於同一條 Attack Chain。

所以 EDR 不應該只看:

Process Name

而是要一起看:

PID
PPID
Parent
Ancestor
Command
Network
File

這也是 Day15 要補上的資訊。


四、Day14 的問題:只按照 PID 分組

Day14 的 Correlation Engine 原本有:

alerts_by_pid = {}

收到 Alert 後:

pid = alert.get("pid")

if pid not in alerts_by_pid:
    alerts_by_pid[pid] = []

alerts_by_pid[pid].append(alert)

這個設計很容易理解:

PID 7000
→ 放進 7000 群組

PID 7010
→ 放進 7010 群組

PID 7020
→ 放進 7020 群組

問題就在這裡。

假設真正的 Process Tree 是:

PID 7000
   ↓
PID 7010
   ↓
PID 7020

它們明明是一家人。

但是 Day14 的程式會變成:

7000 一組

7010 一組

7020 一組

Correlation Engine 根本沒有機會把它們放在一起分析。

所以今天第一個改變就是:

不再把「PID 是否相同」當成唯一的 Process Relationship。


五、先讓 BehaviorGuard 收集 Ancestor

我的 process_monitor.py 本來就已經會從:

/proc/<pid>/status

取得:

PID
PPID

因此不用重新設計整個 Process Monitor。

我加入了一個:

get_process_lineage()

概念如下:

def get_process_lineage(process, process_map, max_depth=4):

    ancestors = []

    current_ppid = process.get("ppid")

    depth = 0

    while current_ppid and depth < max_depth:

        parent = process_map.get(current_ppid)

        if parent is None:
            break

        ancestors.append(parent["pid"])

        current_ppid = parent.get("ppid")

        depth += 1

    return ancestors

六、get_process_lineage() 在做什麼?

假設現在 Process Tree 是:

bash
PID 7000
   ↓
python3
PID 7010
   ↓
nc
PID 7020

現在要分析:

PID 7020

首先:

7020 的 PPID = 7010

所以:

ancestors = [7010]

再找:

7010 的 PPID = 7000

變成:

ancestors = [7010, 7000]

因此最後:

get_process_lineage(7020)

概念上會得到:

[7010, 7000]

這就代表:

7020
↑
7010
↑
7000

七、為什麼設定 max_depth?

我的 function 裡還有:

max_depth=4

也就是最多往上找四層。

這個限制很重要。

如果完全沒有限制,一個 Process 可以一直:

Child
↑
Parent
↑
Grandparent
↑
...
↑
systemd
PID 1

最後很多 Process 都可能一路追到:

PID 1

如果把太遠的 Process Relationship 全部視為強關係,很容易造成:

Over-Correlation

也就是:

把其實沒什麼關係的 Process 硬串成同一條事件。

所以第一版先限制 Process Lineage 深度,避免關係範圍無限制擴大。


八、實際取得 Process Lineage

今天實際執行:

PYTHONPATH=. python agent/process_monitor.py

接著產生:

bash
↓
python3
↓
sleep

BehaviorGuard 成功抓到:

[ALERT] BG-CMD-002
Rule      : Python Inline Code Execution
Severity  : MEDIUM

PID       : 2306118
PPID      : 2306074
Process   : python3
Parent    : bash
Ancestors : [2306074, 2306000, 2305992, 1]

Command   : python3 -c import subprocess, time; subprocess.Popen(["sleep","20"]); time.sleep(20)

代表 BehaviorGuard 現在不只知道:

這是 python3

還知道:

PID
PPID
Parent
Ancestors

Process Context 已經比之前完整很多。


九、建立 Process Relationship Helper

接著建立:

correlation/process_tree.py

其中最重要的 function 是:

def are_processes_related(alert_a, alert_b):

    pid_a = alert_a.get("pid")
    pid_b = alert_b.get("pid")

    if pid_a is None or pid_b is None:
        return False

    if pid_a == pid_b:
        return True

    ancestors_a = alert_a.get("ancestors", [])
    ancestors_b = alert_b.get("ancestors", [])

    if pid_a in ancestors_b:
        return True

    if pid_b in ancestors_a:
        return True

    return False

這個 function 就是在回答:

Alert A 和 Alert B 的 Process 到底有沒有血緣關係?


十、目前認定 Related 的三種情況

目前 BehaviorGuard 會認為以下三種情況存在 Process Relationship。

情況 結果
Same PID Related
A 是 B 的 Ancestor Related
B 是 A 的 Ancestor Related
只有共同 Ancestor NOT Related

第一種最簡單:

A PID 7000
B PID 7000

結果:

True

也就是保留 Day14 原本的 Same PID Correlation。


第二種:

Alert A
PID 7000

另一個:

Alert B
PID 7010
Ancestors [7000]

因為:

7000 in [7000]

所以:

PID 7000
是 PID 7010 的 Ancestor

結果:

True

第三種可以跨更多層。

例如:

Alert A
PID 7000

以及:

Alert B
PID 7020
Ancestors [7010, 7000]

雖然:

7000 != 7020

但是:

7000 in [7010, 7000]

所以依然可以知道:

7000
 ↓
7010
 ↓
7020

屬於同一條 Process Lineage。


十一、Correlation Engine 的核心改變

昨天 Day14:

Same PID
↓
Correlation

今天改成:

Same PID
        OR
Parent / Child
        OR
Ancestor / Descendant
        ↓
Correlation

Correlation Engine 不再先用:

alerts_by_pid = {}

把所有不同 PID 分開。

而是改成:

if not are_processes_related(
    previous_alert,
    candidate
):
    continue

意思就是:

下一個 Alert 除了 Rule 順序正確以外,它的 Process 還必須跟上一階段 Process 有 lineage 關係。


十二、Rule Sequence 還是存在

Day15 並沒有把昨天的 Correlation 邏輯全部推翻。

昨天建立的:

Time Window
Rule Sequence
Duplicate Suppression

全部保留。

因此現在完整條件變成:

Time Window
+
Rule Sequence
+
Process Relationship
+
Duplicate Suppression

例如:

BG-CMD-002
PID 7000
        ↓

BG-NET-005
PID 7010
PPID 7000
        ↓

BG-NET-003
PID 7020
PPID 7010

Rule 順序符合:

BG-CMD-002
↓
BG-NET-005
↓
BG-NET-003

Process Tree 也符合:

7000
↓
7010
↓
7020

因此:

BG-CORR-005

成立。


十三、Day15 正向測試

為了確認不同 PID 真的可以 Correlation,我建立三個測試 Alert。

第一個:

alert1 = {
    "rule": "BG-CMD-002",
    "name": "Python Inline Code Execution",
    "severity": "MEDIUM",
    "pid": 7000,
    "ppid": 6500,
    "ancestors": [
        6500
    ]
}

第二個:

alert2 = {
    "rule": "BG-NET-005",
    "name": "Shell or Interpreter Network Activity",
    "severity": "HIGH",
    "pid": 7010,
    "ppid": 7000,
    "ancestors": [
        7000,
        6500
    ]
}

第三個:

alert3 = {
    "rule": "BG-NET-003",
    "name": "Unexpected External Connection",
    "severity": "MEDIUM",
    "pid": 7020,
    "ppid": 7010,
    "ancestors": [
        7010,
        7000,
        6500
    ]
}

可以畫成:

PID 6500
   ↓
PID 7000
BG-CMD-002
   ↓
PID 7010
BG-NET-005
   ↓
PID 7020
BG-NET-003

這次三個 PID:

7000
7010
7020

完全不同。


十四、正向測試結果

執行:

PYTHONPATH=. python test_process_tree_correlation.py

成功出現:

========== BehaviorGuard Correlated Alert ==========
Rule        : BG-CORR-005
Name        : Suspicious Execution and Network Activity
Severity    : CRITICAL

Process Lineage:
  PID 7000 PPID 6500 Ancestors [6500]
  PID 7010 PPID 7000 Ancestors [7000, 6500]
  PID 7020 PPID 7010 Ancestors [7010, 7000, 6500]

Attack Chain:
  -> BG-CMD-002 (Python Inline Code Execution) [PID 7000]
  -> BG-NET-005 (Shell or Interpreter Network Activity) [PID 7010]
  -> BG-NET-003 (Unexpected External Connection) [PID 7020]
=====================================================

這代表:

7000 != 7010 != 7020

但是 BehaviorGuard 已經知道:

7000
 ↓
7010
 ↓
7020

是一條 Process Tree。

因此仍然成功產生:

BG-CORR-005
CRITICAL

https://ithelp.ithome.com.tw/upload/images/20261007/20179429YiTpjYz4j0.png

十五、為什麼同時出現 BG-CORR-002?

這次測試還同時出現:

BG-CORR-002
Python Execution with External Connection
Severity: HIGH

它使用:

BG-CMD-002
PID 7000

以及:

BG-NET-003
PID 7020

乍看之下:

7000 != 7020

但是 PID 7020 的 Ancestors:

[7010, 7000, 6500]

包含:

7000

所以系統知道:

PID 7000
↓
...
↓
PID 7020

其實存在祖先與後代關係。

因此:

BG-CORR-002

也可以成立。

這證明 Process Tree Correlation 不只支援直接 Parent / Child,也可以支援限定深度內的 Ancestor / Descendant。


十六、但是這裡又出現一個新問題

如果只要:

「有共同 Ancestor」

就算 Related,會發生什麼事情?

假設:

        PID 5000
        /      \
     6000      7000
       ↓         ↓
     8000      9000

PID 8000 的 Ancestors:

[6000, 5000]

PID 9000 的 Ancestors:

[7000, 5000]

兩個 Process 都有:

5000

這個共同祖先。

但:

8000

並不是:

9000

的 Parent。

9000 也不是 8000 的 Ancestor。

它們只是:

兩條不同 Branch

而已。

如果只因為:

都有 5000

就把兩個 Alert 串起來,會造成:

Over-Correlation


十七、什麼是 Over-Correlation?

Over-Correlation 可以理解成:

系統把其實沒有直接關係的事件關聯在一起。

Linux 裡這個問題特別重要。

因為很多 Process 最後都可能追到:

systemd
PID 1

如果 BehaviorGuard 的規則是:

只要有共同 ancestor 就 Related

那可能發生:

apache2

和:

NetworkManager

因為最後都有:

PID 1

就被錯誤串成同一次攻擊。

這樣 Correlation 反而會產生大量 False Positive。

因此我的 are_processes_related() 特別沒有寫成:

如果 ancestors 有交集:
    return True

而是只接受:

Same PID

或:

A 是 B 的 ancestor

或:

B 是 A 的 ancestor

十八、Negative Test

要確認系統真的沒有 Over-Correlation,我另外建立:

test_false_correlation.py

測試兩個 Process:

        PID 5000
        /      \
     6000      7000
      ↓          ↓
   PID 8000   PID 9000

第一個 Alert:

alert1 = {
    "rule": "BG-CMD-002",
    "name": "Python Inline Code Execution",
    "severity": "MEDIUM",
    "pid": 8000,
    "ppid": 6000,
    "ancestors": [
        6000,
        5000
    ]
}

第二個 Alert:

alert2 = {
    "rule": "BG-NET-003",
    "name": "Unexpected External Connection",
    "severity": "MEDIUM",
    "pid": 9000,
    "ppid": 7000,
    "ancestors": [
        7000,
        5000
    ]
}

兩邊都有:

5000

但是:

8000 不是 9000 的 ancestor

9000 也不是 8000 的 ancestor

所以:

are_processes_related()

應該回傳:

False

十九、Negative Test 結果

執行:

PYTHONPATH=. python test_false_correlation.py

結果:

Sending unrelated Command Alert...
Sending unrelated Network Alert...

If no BG-CORR-002 appears, the negative test passed.

而且畫面中:

沒有出現 BG-CORR-002

代表:

Negative Test ✅

成功。


【圖 2:Negative Test / Over-Correlation 測試】

這裡放今天 test_false_correlation.py 的截圖。
畫面中沒有出現 BG-CORR-002,證明兩個 Process 即使擁有共同 Ancestor,也不會直接被視為同一條 Process Lineage。

https://ithelp.ithome.com.tw/upload/images/20261007/20179429cIeqMhhQmv.png

二十、Positive Test 和 Negative Test 的差別

今天我覺得這兩個測試非常重要。

測試 Process 關係 結果
Positive Test 7000 → 7010 → 7020 Correlation ✅
Negative Test 8000 與 9000 只有共同 Ancestor Correlation ❌

也就是:

有真正 Parent / Child / Ancestor 關係
↓
應該關聯

但是:

只是剛好有共同 Ancestor
↓
不應該關聯

這讓 Process Tree Correlation 不只是:

「抓得到」

還開始處理另一個資安產品非常重要的問題:

「不要抓錯」

二十一、Day14 與 Day15 的差別

昨天 Day14:

BG-CMD-002
PID 7000
        ↓
BG-NET-005
PID 7000
        ↓
BG-NET-003
PID 7000

必須全部:

Same PID

才能 Correlation。

Day15:

BG-CMD-002
PID 7000
        ↓
BG-NET-005
PID 7010
PPID 7000
        ↓
BG-NET-003
PID 7020
PPID 7010

即使:

7000 != 7010 != 7020

BehaviorGuard 還是能透過:

Parent
Ancestor
Process Lineage

判斷:

它們其實是同一條 Process Tree。

所以整個 Correlation 能力從:

Same PID Correlation

升級成:

Process Tree Correlation

二十二、目前 BehaviorGuard 的 Correlation 條件

經過 Day14 和 Day15,目前一條 Attack Chain 要成立,可以同時考慮:

Context 用途
Time Window 確認事件是否發生在接近時間
Rule Sequence 確認事件發生順序
PID 判斷是否同一 Process
PPID 找 Parent Process
Ancestors 找 Process Lineage
Process Relationship 判斷 Parent / Child / Ancestor
Duplicate Suppression 避免相同 Alert 一直重複
Correlation Rule 定義哪些行為組合有安全意義

所以現在已經不是:

if suspicious:
    alert

這麼簡單。

而是:

Alert
↓
Time Context
↓
Process Context
↓
Behavior Sequence
↓
Correlation
↓
Attack Chain

二十三、今天學到的新資安概念

1. PID 不等於 Process Identity 的全部

Day14 很容易誤以為:

PID 不同
=
事件不同

但實際上:

bash PID 7000
↓
python3 PID 7010
↓
nc PID 7020

雖然三個 PID 完全不同,仍然可能屬於同一次行為。

因此 EDR 不能只看:

PID

還必須看:

PPID
Parent
Ancestor
Process Tree

2. Parent Process 是非常重要的 Context

同一個程式,由不同 Parent 啟動,安全意義可能完全不同。

例如:

Terminal
↓
bash

很正常。

但是:

apache2
↓
bash

就可能值得調查。

所以:

Who spawned this process?

是 Endpoint Detection 很重要的問題。


3. Ancestor 可以幫助還原更長的 Attack Chain

只看 PPID:

7020
↓
7010

只能知道一層。

加入 Ancestor:

7020
↓
7010
↓
7000
↓
6500

就能知道更完整的 Process Lineage。

這對多階段攻擊特別重要。


4. Correlation 不只要防 False Negative,也要防 False Positive

如果規則太嚴:

只能 Same PID

可能漏掉真正的攻擊。

這比較接近:

False Negative

但是如果規則太寬:

只要共同 Ancestor 就算 Related

又會把很多正常行為串在一起。

這會增加:

False Positive

因此 Detection Engineering 很重要的一件事情就是:

找到中間的平衡。

5. Negative Test 很重要

以前做專題時,我比較常測:

「功能有沒有成功觸發?」

今天開始發現還有另一種測試同樣重要:

「不應該觸發的情況,有沒有真的不觸發?」

也就是:

Negative Test

Positive Test:

有攻擊鏈
↓
有 Alert

Negative Test:

沒有真正關係
↓
不能 Alert

兩個都通過,才能比較有信心說規則設計是合理的。


二十四、今天遇到的限制

雖然 Process Tree Correlation 已經成功,但目前仍然不是完整 EDR。

目前主要還有幾個限制。

第一個:

Process Lineage 最大深度目前有限制

目前:

max_depth = 4

這是為了避免 Over-Correlation,但是也可能造成太深的 Process Tree 無法完整追蹤。


第二個:

目前測試 Correlation 時使用的 Alert,仍然有部分是:

test_process_tree_correlation.py

手動建立的測試資料。

真正理想的架構應該是:

Process Monitor
↓
Detection Engine
↓
Real Alert
↓
加入 PID / PPID / Ancestors
↓
Correlation Engine

也就是讓真實 Detection Pipeline 自動送進 Correlation,而不是靠測試檔建立 Alert。

這會是後續需要整合的方向。


第三個:

Process Tree 只解決:

Process ↔ Process

的關係。

但我們未來還要處理:

Process
↓
Network
↓
File
↓
Persistence

這些不同 Telemetry 之間的關係。

也就是之後的:

Cross-Telemetry Correlation


二十五、Day15 完成項目

功能 狀態
PID 蒐集 ✅
PPID 蒐集 ✅
Parent Process ✅
Ancestor List ✅
Process Lineage ✅
Process Tree Helper ✅
Same PID Correlation 保留 ✅
Parent / Child Correlation ✅
Ancestor / Descendant Correlation ✅
Different PID Correlation ✅
Rule Sequence 保留 ✅
Time Window 保留 ✅
Duplicate Suppression 保留 ✅
BG-CORR-005 跨 PID Attack Chain ✅
Positive Test ✅
Negative Test ✅
Over-Correlation Prevention ✅

Day15 小結

Day14 的 BehaviorGuard 已經可以把多個 Alert 串成 Attack Chain。

但是當時最大的限制是:

所有 Alert 必須使用同一個 PID。

Day15 加入 Process Tree 之後,BehaviorGuard 開始可以理解:

bash
PID 7000
   ↓
python3
PID 7010
   ↓
nc
PID 7020

雖然:

PID 不同

但是透過:

PPID
Parent
Ancestor
Process Lineage

仍然可以判斷它們屬於同一條 Process Tree。

最後成功完成:

BG-CMD-002
PID 7000
        ↓
BG-NET-005
PID 7010
        ↓
BG-NET-003
PID 7020
        ↓
BG-CORR-005
CRITICAL

另外,我也特別加入 Negative Test。

確認:

兩個 Process 即使擁有共同 Ancestor

只要彼此不存在真正的:

Parent / Child
或
Ancestor / Descendant

關係,就不會被 BehaviorGuard 錯誤關聯。

今天最大的收穫是:

Correlation 不只是把越多 Alert 串在一起越好,而是要找到真正有意義的關係。

BehaviorGuard 從昨天的:

Same PID Correlation

正式進入:

Process Tree Correlation

下一步就可以繼續思考:

Process
+
Command
+
Network
+
File
+
Persistence

要怎麼真正串成一個跨 Telemetry 的 Incident。

也就是讓 BehaviorGuard 從:

「知道哪些 Process 有關」

繼續往:

「還原整段攻擊行為」

前進。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言