Day 24 將 AI 分析結果整理成 AI Analysis Panel 之後,AI SOC Dashboard 從事件列表、搜尋、統計到 AI 分析都已經可以運作。
不過資料庫裡一直只有 Day 10 建立的幾筆 Mock Data。只有三筆事件時,搜尋與統計其實看不出效果,AI 也只分析過 Network Scan 與 Login Attempt 這兩種情況。
Day 1 曾經提到,最後希望可以使用 Brute Force、Port Scan、Web Attack 等不同案例來測試整個系統。所以今天先準備測試資料,讓 Dashboard 看起來更接近真實 SOC 每天會面對的事件。
我整理了 9 種事件類型,共 27 筆事件:
| Event Type | 內容 |
|---|---|
| Brute Force | SSH、RDP、FTP 的多次登入嘗試 |
| Web Attack | SQL Injection、XSS、Directory Traversal、Log4j、WebShell |
| Network Scan | Nmap、Nikto、SNMP 掃描 |
| Malware | C2 連線、可疑檔案下載 |
| DNS Anomaly | DNS Tunneling、DGA、可疑網域查詢 |
| Lateral Movement | PsExec、Kerberoasting、WinRM |
| Data Exfiltration | 大量對外上傳 |
| Policy Violation | Tor、BitTorrent、Telnet 明文登入 |
| DoS | SYN Flood、Slowloris |
Signature 採用 Suricata 規則常見的命名方式,例如 ET SCAN ...、ET WEB_SERVER ...。外部來源 IP 則使用 203.0.113.x 與 198.51.100.x,這兩個網段是保留給文件與範例使用的位址,不會對應到真實的主機。
Severity 沿用 Day 13 的規則:1 是 High、2 是 Medium、3 是 Low。
在 backend 資料夾新增 seed_demo.py
import sqlite3
from pathlib import Path
# 加入測試案例(重複執行不會重複新增)
DATABASE = Path(__file__).resolve().parent / "soc.db"
# (event_type, src_ip, dest_ip, dest_port, protocol, signature, severity)
DEMO_EVENTS = [
("Brute Force", "203.0.113.45", "192.168.3.141", 22, "TCP", "ET SCAN Potential SSH Scan / Brute Force Attempt", 1),
("Brute Force", "198.51.100.23", "192.168.3.150", 3389, "TCP", "ET SCAN RDP Brute Force Login Attempt", 1),
("Brute Force", "192.168.3.120", "192.168.3.160", 21, "TCP", "FTP Multiple Failed Login Attempts", 2),
("Web Attack", "203.0.113.77", "192.168.3.141", 80, "TCP", "ET WEB_SERVER SQL Injection Attempt UNION SELECT in URI", 1),
("Web Attack", "203.0.113.77", "192.168.3.141", 80, "TCP", "ET WEB_SERVER Possible XSS Attempt script tag in URI", 2),
("Web Attack", "198.51.100.88", "192.168.3.141", 443, "TCP", "ET WEB_SERVER Directory Traversal Attempt ../../etc/passwd", 1),
("Web Attack", "198.51.100.88", "192.168.3.141", 8080, "TCP", "ET EXPLOIT Apache Log4j RCE Attempt jndi:ldap in HTTP Header", 1),
("Web Attack", "203.0.113.12", "192.168.3.141", 80, "TCP", "ET WEB_SERVER WebShell Access cmd.php", 1),
("Network Scan", "192.168.3.100", "192.168.3.0", 445, "TCP", "ET SCAN Nmap SYN Scan Multiple Ports", 2),
("Network Scan", "203.0.113.200", "192.168.3.141", 443, "TCP", "ET SCAN Nikto Web Vulnerability Scanner User-Agent", 2),
("Network Scan", "192.168.3.100", "192.168.3.150", 161, "UDP", "ET SCAN SNMP Community String Sweep", 3),
("Malware", "192.168.3.133", "185.220.101.5", 443, "TCP", "ET MALWARE Cobalt Strike Beacon C2 Activity", 1),
("Malware", "192.168.3.133", "45.155.205.99", 8443, "TCP", "ET MALWARE Possible Ransomware C2 Check-in", 1),
("Malware", "192.168.3.118", "104.21.33.7", 80, "TCP", "ET MALWARE Suspicious EXE Download from Raw IP", 2),
("DNS Anomaly", "192.168.3.133", "8.8.8.8", 53, "UDP", "ET DNS Possible DNS Tunneling Long TXT Query", 1),
("DNS Anomaly", "192.168.3.118", "192.168.3.1", 53, "UDP", "ET DNS Query to Suspicious .top TLD Domain", 3),
("DNS Anomaly", "192.168.3.125", "192.168.3.1", 53, "UDP", "ET DNS Excessive NXDOMAIN Responses Possible DGA", 2),
("Lateral Movement", "192.168.3.133", "192.168.3.150", 445, "TCP", "ET EXPLOIT SMB PsExec Service Creation", 1),
("Lateral Movement", "192.168.3.133", "192.168.3.10", 88, "TCP", "ET POLICY Kerberoasting TGS Request RC4 Encryption", 1),
("Lateral Movement", "192.168.3.133", "192.168.3.160", 5985, "TCP", "ET POLICY WinRM Remote PowerShell Session", 2),
("Data Exfiltration", "192.168.3.150", "162.125.6.18", 443, "TCP", "ET POLICY Large Outbound Upload to Cloud Storage", 2),
("Data Exfiltration", "192.168.3.150", "203.0.113.90", 21, "TCP", "ET POLICY Outbound FTP File Upload of Archive", 1),
("Policy Violation", "192.168.3.125", "104.16.248.249", 443, "TCP", "ET POLICY Tor Exit Node Connection", 2),
("Policy Violation", "192.168.3.142", "151.101.1.140", 6881, "UDP", "ET P2P BitTorrent DHT Announce", 3),
("Policy Violation", "192.168.3.142", "192.168.3.1", 23, "TCP", "ET POLICY Cleartext Telnet Login", 3),
("DoS", "203.0.113.150", "192.168.3.141", 80, "TCP", "ET DOS Possible SYN Flood Inbound", 1),
("DoS", "198.51.100.200", "192.168.3.141", 443, "TCP", "ET DOS Slowloris HTTP Slow Header Attack", 2),
]
conn = sqlite3.connect(DATABASE)
added = 0
for event in DEMO_EVENTS:
exists = conn.execute(
"SELECT 1 FROM events WHERE src_ip = ? AND dest_ip = ? AND signature = ?",
(event[1], event[2], event[5])
).fetchone()
if exists:
continue
conn.execute("""
INSERT INTO events
(event_type, src_ip, dest_ip, dest_port,
protocol, signature, severity)
VALUES (?, ?, ?, ?, ?, ?, ?)
""", event)
added += 1
conn.commit()
total = conn.execute("SELECT COUNT(*) FROM events").fetchone()[0]
conn.close()
print("Added demo events:", added)
print("Total events:", total)
寫入之前會先檢查相同的 Source IP、Destination IP 與 Signature 是否已經存在,所以這支程式重複執行也不會產生重複的資料。
資料變多之後,我發現表格只顯示 Event Type 是不夠的。同樣是 Web Attack,SQL Injection 和 Log4j 的嚴重程度與處理方式完全不同,分析人員需要看到 Signature 才能分辨。
修改 App.jsx,在表格標題加入
<th>Event Type</th>
<th>Signature</th>
資料列加入
<td>{event.event_type}</td>
<td>{event.signature}</td>
分析完成後自動捲動到結果
事件增加到 30 筆之後,AI Analysis Panel 被推到頁面最下方。按下 Analyze with AI 之後畫面沒有變化,要自己往下捲才看得到結果。
修改 import:
import { useEffect, useRef, useState } from "react";
新增一個 ref
const aiPanelRef = useRef(null);
加入 useEffect,當分析完成時捲動到結果區塊
// AI 分析完成時,捲動到結果區塊
useEffect(() => {
if (aiAnalysis) {
aiPanelRef.current?.scrollIntoView({ behavior: "smooth" });
}
}, [aiAnalysis]);
在 AI Analysis Panel 的上方放一個定位點
<div ref={aiPanelRef}></div>
{aiAnalysis && aiAnalysis.ai_analysis && (
<div className="ai-panel">
重新整理 Dashboard,Total Events 變成 30,High、Medium、Low 分別是 15、11、4,Event Type Statistics 也從 3 種增加到 10 種類型。
搜尋 Log4j 會找到 1 筆事件,搜尋 192.168.3.133 則可以看到同一台主機同時出現 C2 連線、DNS Tunneling 與橫向移動的事件。
選一筆新的事件按下 Analyze with AI,畫面會自動捲動到 AI Analysis Panel。
小結
今天主要是替系統準備測試資料,並調整資料變多之後才出現的兩個使用問題。
只有三筆資料時,Dashboard 的每個功能看起來都沒有問題。但資料增加到 30 筆之後,我才發現表格缺少 Signature、分析結果會被推到看不見的位置。這些問題在資料很少的時候是不會被注意到的。
另外,在整理測試案例時也讓我重新複習了一次不同攻擊類型的差異。例如搜尋 192.168.3.133 所看到的幾筆事件,單獨看每一筆都只是一個告警,但放在一起就像是一台主機被入侵之後的完整過程。這也是 Day 2 提到 SIEM 關聯分析想要解決的問題。
這些測試案例讓 Dashboard 的每個功能都有足夠的資料可以驗證。接下來希望可以把分析結果保存下來,並把前面 Day 11 到 Day 13 寫好的 Suricata 解析流程真正接進資料庫。