前幾天的 BehaviorGuard 已經可以透過 Process 與 Command Line 偵測一些可疑行為。
例如目前已經有:
但只觀察 Process 與 Command 還不夠。
假設今天有人執行:
nc -l -p 9999
除了知道「Shell 啟動了 nc」之外,我還希望 BehaviorGuard 可以進一步知道:
nc 現在是不是正在開啟一個 Port 等待其他人連線?
所以 Day 7 開始加入第三個偵測面向:
Network Behavior Detection
首先使用 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。
接著建立:
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 的核心概念。
接下來修改:
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。
前面的 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。
啟動:
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 判斷。
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
已經警告過,就暫時不重複顯示。
最後我想測試一件很重要的事情:
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
Socket 可以理解成程式進行網路通訊時使用的一個端點。
一個 Process 如果要提供網路服務,就可能建立 Socket 並綁定 IP 與 Port。
LISTEN 代表程式目前正在等待其他連線進來。
例如:
0.0.0.0:9999 LISTEN
代表有程式正在 TCP 9999 Port 等待連線。
但要注意:
LISTEN 本身不是攻擊。
Apache、SSH、Database 等正常服務也都會有 Listening Socket。
今天收集的:
Process
PID
State
Port
Local Address
就是一種 Endpoint Network Telemetry。
未來可以將這些資料與 Process、Command 等資訊結合。
今天另一個重要觀念是:
Detection 不是 Alert 越多越好。
如果規則寫成:
只要 LISTEN → HIGH
那麼:
Apache
SSH
Database
可能全部都會一直發出警告。
這就是 False Positive(誤報)。
如果企業每天出現大量誤報,分析人員就必須花大量時間檢查,真正重要的 Alert 也可能被淹沒。
所以 Detection Rule 除了要考慮:
能不能抓到攻擊?
也必須考慮:
正常行為會不會被我誤判?
今天 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。