iT邦幫忙

0

Day 7 BehaviorGuard 加入 Network Detection,開始監控網路行為

  • 分享至 

  • xImage
  •  

前幾天的 BehaviorGuard 已經可以透過 Process 與 Command Line 偵測一些可疑行為。

例如目前已經有:

  • BG-PROC-001:Web Server Spawned Shell
  • BG-PROC-002:Shell Spawned Network Tool
  • BG-CMD-001:Download Piped to Shell
  • BG-CMD-002:Python Inline Code Execution

但只觀察 Process 與 Command 還不夠。

假設今天有人執行:

nc -l -p 9999

除了知道「Shell 啟動了 nc」之外,我還希望 BehaviorGuard 可以進一步知道:

nc 現在是不是正在開啟一個 Port 等待其他人連線?

所以 Day 7 開始加入第三個偵測面向:

Network Behavior Detection


一、什麼是 Network Telemetry?

首先使用 Linux 的 ss 指令觀察目前的 Network Socket:

ss -lntp

參數分別代表:

  • -l:顯示 Listening Socket
  • -n:直接顯示 IP 與 Port
  • -t:顯示 TCP
  • -p:顯示對應的 Process

接著開啟一個測試用的 Netcat Listener:

nc -l -p 9999

再次執行:

ss -lntp

可以看到:

LISTEN 0 1 0.0.0.0:9999 0.0.0.0:* users:(("nc",pid=1446473,fd=3))

這代表:

Process = nc
PID     = 1446473
State   = LISTEN
Port    = 9999
Address = 0.0.0.0:9999

也就是 nc 正在 TCP Port 9999 上等待連線。

這些資訊就是今天 BehaviorGuard 要開始收集的 Network Telemetry。


二、新增 Network Detection Rule

接著建立:

detection/network_rules.py

加入第一條 Network Rule:

# BehaviorGuard - Network Detection Rules


def detect_suspicious_listener(event):
    """
    BG-NET-001
    Detect suspicious network tools opening a listening port.
    """

    process = event.get("process", "").lower()
    state = event.get("state", "").upper()
    port = event.get("port", 0)

    suspicious_tools = ["nc", "ncat", "socat"]

    if process in suspicious_tools and state == "LISTEN":
        return {
            "rule_id": "BG-NET-001",
            "rule_name": "Suspicious Network Listener",
            "severity": "HIGH",
            "description": f"{process} opened a listening socket on port {port}."
        }

    return None

目前這條規則的邏輯是:

Process = nc / ncat / socat
             +
State = LISTEN
             ↓
         BG-NET-001
             ↓
          HIGH Alert

這裡要注意:

不是 Port 9999 本身有問題。

Port 9999 可以被正常程式使用,nc 本身也不是病毒。

我們真正觀察的是:

特定網路工具正在建立 Listening Socket 這個「行為」。

這也是 Behavior-Based Detection 的核心概念。


三、把 Network Rule 接進 Detection Engine

接下來修改:

detection/engine.py

加入:

from detection.network_rules import (
    detect_suspicious_listener
)

建立 Network Rules:

NETWORK_RULES = [
    detect_suspicious_listener
]

再加入:

def analyze_network_event(event):
    """
    Send one network event through all network detection rules.
    """

    alerts = []

    for rule in NETWORK_RULES:
        result = rule(event)

        if result is not None:
            alerts.append(result)

    return alerts

這樣 Detection Engine 現在就有三種規則:

Detection Engine
      │
      ├── PROCESS_RULES
      │
      ├── COMMAND_RULES
      │
      └── NETWORK_RULES

先用測試 Event:

event = {
    "process": "nc",
    "state": "LISTEN",
    "port": 9999
}

送進:

analyze_network_event(event)

成功得到:

[{
    'rule_id': 'BG-NET-001',
    'rule_name': 'Suspicious Network Listener',
    'severity': 'HIGH',
    'description': 'nc opened a listening socket on port 9999.'
}]

代表 Network Rule 已經成功接進 Detection Engine。


四、建立 Network Monitor

前面的 Event 還是手動建立的。

真正想做到的是:

Linux Network
      ↓
Network Monitor
      ↓
Network Event
      ↓
Detection Engine
      ↓
Network Rules
      ↓
Alert

因此新增:

agent/network_monitor.py

主要程式如下:

import subprocess
import re
import time

from detection.engine import analyze_network_event


def get_listening_connections():
    """
    Read listening TCP sockets from Linux using ss -lntp.
    """

    events = []

    try:
        result = subprocess.run(
            ["ss", "-lntp"],
            capture_output=True,
            text=True
        )

        lines = result.stdout.splitlines()

        for line in lines[1:]:

            parts = line.split()

            if len(parts) < 6:
                continue

            state = parts[0]
            local_address = parts[3]
            process_info = " ".join(parts[5:])

            try:
                port = int(local_address.rsplit(":", 1)[1])
            except (ValueError, IndexError):
                continue

            process_match = re.search(
                r'\(\("([^"]+)"',
                process_info
            )

            pid_match = re.search(
                r'pid=(\d+)',
                process_info
            )

            if process_match:
                process = process_match.group(1)
            else:
                process = "unknown"

            if pid_match:
                pid = int(pid_match.group(1))
            else:
                pid = 0

            event = {
                "process": process,
                "pid": pid,
                "state": state,
                "port": port,
                "local_address": local_address
            }

            events.append(event)

    except Exception as e:
        print(
            f"[ERROR] Failed to collect network information: {e}"
        )

    return events


def print_alert(alert, event):

    print(
        "\n========== BehaviorGuard Network Alert =========="
    )

    print(f"Rule       : {alert['rule_id']}")
    print(f"Name       : {alert['rule_name']}")
    print(f"Severity   : {alert['severity']}")
    print(f"Process    : {event['process']}")
    print(f"PID        : {event['pid']}")
    print(f"Address    : {event['local_address']}")
    print(f"Description: {alert['description']}")

    print(
        "=================================================\n"
    )


def monitor_network():

    print(
        "[BehaviorGuard] Network Monitor started..."
    )

    seen_alerts = set()

    while True:

        events = get_listening_connections()

        for event in events:

            alerts = analyze_network_event(event)

            for alert in alerts:

                alert_key = (
                    alert["rule_id"],
                    event["pid"],
                    event["port"]
                )

                if alert_key not in seen_alerts:

                    print_alert(
                        alert,
                        event
                    )

                    seen_alerts.add(
                        alert_key
                    )

        time.sleep(2)


if __name__ == "__main__":
    monitor_network()

這個 Network Monitor 目前每隔約 2 秒取得一次 Listening Socket,再把資料整理成 Network Event。

例如:

{
    "process": "nc",
    "pid": 1458425,
    "state": "LISTEN",
    "port": 9999,
    "local_address": "0.0.0.0:9999"
}

接著交給 Detection Engine。


五、第一次真實 Network Detection

啟動:

PYTHONPATH=. python3 agent/network_monitor.py

接著另外開一個 Terminal:

nc -l -p 9999

BehaviorGuard 成功產生:

========== BehaviorGuard Network Alert ==========

Rule       : BG-NET-001
Name       : Suspicious Network Listener
Severity   : HIGH
Process    : nc
PID        : 1458425
Address    : 0.0.0.0:9999
Description: nc opened a listening socket on port 9999.

=================================================

這次不是手動建立 Event,而是 BehaviorGuard 自己從系統取得 Network Telemetry,再經過 Detection Engine 判斷。


六、為什麼要使用 seen_alerts?

Network Monitor 每隔 2 秒就會重新檢查一次。

如果 nc 一直存在,就可能變成:

HIGH Alert

2 秒後

HIGH Alert

2 秒後

HIGH Alert

因此目前使用:

seen_alerts = set()

並利用:

alert_key = (
    alert["rule_id"],
    event["pid"],
    event["port"]
)

判斷是不是同一個 Alert。

如果同一個:

Rule ID
+
PID
+
Port

已經警告過,就暫時不重複顯示。


七、測試 False Positive

最後我想測試一件很重要的事情:

BehaviorGuard 會不會看到任何 Listening Port 都發出警告?

因此啟動 Apache:

sudo systemctl start apache2

查看:

sudo ss -lntp | grep apache

可以看到 Apache 正常監聽:

*:80

接著再次啟動 BehaviorGuard。

結果:

[BehaviorGuard] Network Monitor started...

沒有產生 Alert。

因為:

apache2
   ↓
TCP 80 LISTEN
   ↓
不是 BG-NET-001 指定的可疑工具
   ↓
不產生 Alert

接著再執行:

nc -l -p 9999

BehaviorGuard 馬上產生:

BG-NET-001
Suspicious Network Listener
Severity: HIGH

因此目前可以做到:

Apache :80
    ↓
正常 Listening Behavior
    ↓
不 Alert


nc :9999
    ↓
Suspicious Listener
    ↓
HIGH Alert

八、今天學到的資安知識

1. Socket

Socket 可以理解成程式進行網路通訊時使用的一個端點。

一個 Process 如果要提供網路服務,就可能建立 Socket 並綁定 IP 與 Port。


2. LISTEN

LISTEN 代表程式目前正在等待其他連線進來。

例如:

0.0.0.0:9999 LISTEN

代表有程式正在 TCP 9999 Port 等待連線。

但要注意:

LISTEN 本身不是攻擊。

Apache、SSH、Database 等正常服務也都會有 Listening Socket。


3. Network Telemetry

今天收集的:

Process
PID
State
Port
Local Address

就是一種 Endpoint Network Telemetry。

未來可以將這些資料與 Process、Command 等資訊結合。


4. False Positive

今天另一個重要觀念是:

Detection 不是 Alert 越多越好。

如果規則寫成:

只要 LISTEN → HIGH

那麼:

Apache
SSH
Database

可能全部都會一直發出警告。

這就是 False Positive(誤報)。

如果企業每天出現大量誤報,分析人員就必須花大量時間檢查,真正重要的 Alert 也可能被淹沒。

所以 Detection Rule 除了要考慮:

能不能抓到攻擊?

也必須考慮:

正常行為會不會被我誤判?


Day 7 小結

今天 BehaviorGuard 正式加入 Network Detection。

目前整體架構開始變成:

                 Endpoint
                    │
        ┌───────────┴───────────┐
        ↓                       ↓
 Process Telemetry        Network Telemetry
        ↓                       ↓
 Process Monitor          Network Monitor
        │                       │
        └──────────┬────────────┘
                   ↓
            Detection Engine
                   │
        ┌──────────┼──────────┐
        ↓          ↓          ↓
   PROC Rules   CMD Rules   NET Rules
        │          │          │
        └──────────┴──────────┘
                   ↓
                 Alert

目前 BehaviorGuard 已經有:

BG-PROC-001
BG-PROC-002

BG-CMD-001
BG-CMD-002

BG-NET-001

總共 5 條 Detection Rules。

今天最大的進展不是單純「多寫了一條規則」,而是 BehaviorGuard 多了一種新的資料來源:

Network Telemetry。

目前 Network Detection 還只是第一版。

Day 8 會繼續擴充 Network Detection,讓 BehaviorGuard 不只是知道「有人開了一個 Listening Port」,還能觀察更多 Network Behavior。

等 Detection 的範圍逐漸完整之後,再把 Process、Command、Network、File 等不同事件串起來做 Behavior Correlation 與 Risk Scoring,最後才進入 Response。


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

尚未有邦友留言

立即登入留言