@panguard-ai/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/adapter-registry.d.ts +150 -0
- package/dist/adapters/adapter-registry.d.ts.map +1 -0
- package/dist/adapters/adapter-registry.js +271 -0
- package/dist/adapters/adapter-registry.js.map +1 -0
- package/dist/adapters/base-adapter.d.ts +101 -0
- package/dist/adapters/base-adapter.d.ts.map +1 -0
- package/dist/adapters/base-adapter.js +160 -0
- package/dist/adapters/base-adapter.js.map +1 -0
- package/dist/adapters/defender-adapter.d.ts +90 -0
- package/dist/adapters/defender-adapter.d.ts.map +1 -0
- package/dist/adapters/defender-adapter.js +227 -0
- package/dist/adapters/defender-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +22 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +23 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/syslog-adapter.d.ts +207 -0
- package/dist/adapters/syslog-adapter.d.ts.map +1 -0
- package/dist/adapters/syslog-adapter.js +432 -0
- package/dist/adapters/syslog-adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +135 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +13 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/wazuh-adapter.d.ts +120 -0
- package/dist/adapters/wazuh-adapter.d.ts.map +1 -0
- package/dist/adapters/wazuh-adapter.js +266 -0
- package/dist/adapters/wazuh-adapter.js.map +1 -0
- package/dist/ai/claude-provider.d.ts +66 -0
- package/dist/ai/claude-provider.d.ts.map +1 -0
- package/dist/ai/claude-provider.js +166 -0
- package/dist/ai/claude-provider.js.map +1 -0
- package/dist/ai/funnel-router.d.ts +75 -0
- package/dist/ai/funnel-router.d.ts.map +1 -0
- package/dist/ai/funnel-router.js +173 -0
- package/dist/ai/funnel-router.js.map +1 -0
- package/dist/ai/index.d.ts +77 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +95 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/ollama-provider.d.ts +73 -0
- package/dist/ai/ollama-provider.d.ts.map +1 -0
- package/dist/ai/ollama-provider.js +200 -0
- package/dist/ai/ollama-provider.js.map +1 -0
- package/dist/ai/openai-provider.d.ts +70 -0
- package/dist/ai/openai-provider.d.ts.map +1 -0
- package/dist/ai/openai-provider.js +175 -0
- package/dist/ai/openai-provider.js.map +1 -0
- package/dist/ai/prompts/event-classifier.d.ts +25 -0
- package/dist/ai/prompts/event-classifier.d.ts.map +1 -0
- package/dist/ai/prompts/event-classifier.js +94 -0
- package/dist/ai/prompts/event-classifier.js.map +1 -0
- package/dist/ai/prompts/index.d.ts +13 -0
- package/dist/ai/prompts/index.d.ts.map +1 -0
- package/dist/ai/prompts/index.js +13 -0
- package/dist/ai/prompts/index.js.map +1 -0
- package/dist/ai/prompts/report-generator.d.ts +25 -0
- package/dist/ai/prompts/report-generator.d.ts.map +1 -0
- package/dist/ai/prompts/report-generator.js +131 -0
- package/dist/ai/prompts/report-generator.js.map +1 -0
- package/dist/ai/prompts/threat-analyzer.d.ts +26 -0
- package/dist/ai/prompts/threat-analyzer.d.ts.map +1 -0
- package/dist/ai/prompts/threat-analyzer.js +75 -0
- package/dist/ai/prompts/threat-analyzer.js.map +1 -0
- package/dist/ai/provider-base.d.ts +100 -0
- package/dist/ai/provider-base.d.ts.map +1 -0
- package/dist/ai/provider-base.js +166 -0
- package/dist/ai/provider-base.js.map +1 -0
- package/dist/ai/response-parser.d.ts +36 -0
- package/dist/ai/response-parser.d.ts.map +1 -0
- package/dist/ai/response-parser.js +195 -0
- package/dist/ai/response-parser.js.map +1 -0
- package/dist/ai/token-tracker.d.ts +72 -0
- package/dist/ai/token-tracker.d.ts.map +1 -0
- package/dist/ai/token-tracker.js +145 -0
- package/dist/ai/token-tracker.js.map +1 -0
- package/dist/ai/types.d.ts +138 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +12 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/cli/index.d.ts +146 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +515 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +58 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +327 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/cli/wizard.d.ts +58 -0
- package/dist/cli/wizard.d.ts.map +1 -0
- package/dist/cli/wizard.js +200 -0
- package/dist/cli/wizard.js.map +1 -0
- package/dist/discovery/firewall-checker.d.ts +28 -0
- package/dist/discovery/firewall-checker.d.ts.map +1 -0
- package/dist/discovery/firewall-checker.js +379 -0
- package/dist/discovery/firewall-checker.js.map +1 -0
- package/dist/discovery/index.d.ts +23 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +29 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/network-scanner.d.ts +60 -0
- package/dist/discovery/network-scanner.d.ts.map +1 -0
- package/dist/discovery/network-scanner.js +640 -0
- package/dist/discovery/network-scanner.js.map +1 -0
- package/dist/discovery/os-detector.d.ts +24 -0
- package/dist/discovery/os-detector.d.ts.map +1 -0
- package/dist/discovery/os-detector.js +253 -0
- package/dist/discovery/os-detector.js.map +1 -0
- package/dist/discovery/osquery-provider.d.ts +127 -0
- package/dist/discovery/osquery-provider.d.ts.map +1 -0
- package/dist/discovery/osquery-provider.js +214 -0
- package/dist/discovery/osquery-provider.js.map +1 -0
- package/dist/discovery/risk-scorer.d.ts +66 -0
- package/dist/discovery/risk-scorer.d.ts.map +1 -0
- package/dist/discovery/risk-scorer.js +294 -0
- package/dist/discovery/risk-scorer.js.map +1 -0
- package/dist/discovery/security-tools.d.ts +31 -0
- package/dist/discovery/security-tools.d.ts.map +1 -0
- package/dist/discovery/security-tools.js +346 -0
- package/dist/discovery/security-tools.js.map +1 -0
- package/dist/discovery/service-detector.d.ts +28 -0
- package/dist/discovery/service-detector.d.ts.map +1 -0
- package/dist/discovery/service-detector.js +300 -0
- package/dist/discovery/service-detector.js.map +1 -0
- package/dist/discovery/types.d.ts +502 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +12 -0
- package/dist/discovery/types.js.map +1 -0
- package/dist/discovery/user-auditor.d.ts +28 -0
- package/dist/discovery/user-auditor.d.ts.map +1 -0
- package/dist/discovery/user-auditor.js +385 -0
- package/dist/discovery/user-auditor.js.map +1 -0
- package/dist/i18n/config.d.ts +45 -0
- package/dist/i18n/config.d.ts.map +1 -0
- package/dist/i18n/config.js +135 -0
- package/dist/i18n/config.js.map +1 -0
- package/dist/i18n/index.d.ts +8 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +8 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/monitor/event-normalizer.d.ts +102 -0
- package/dist/monitor/event-normalizer.d.ts.map +1 -0
- package/dist/monitor/event-normalizer.js +195 -0
- package/dist/monitor/event-normalizer.js.map +1 -0
- package/dist/monitor/file-monitor.d.ts +90 -0
- package/dist/monitor/file-monitor.d.ts.map +1 -0
- package/dist/monitor/file-monitor.js +222 -0
- package/dist/monitor/file-monitor.js.map +1 -0
- package/dist/monitor/index.d.ts +147 -0
- package/dist/monitor/index.d.ts.map +1 -0
- package/dist/monitor/index.js +293 -0
- package/dist/monitor/index.js.map +1 -0
- package/dist/monitor/log-monitor.d.ts +102 -0
- package/dist/monitor/log-monitor.d.ts.map +1 -0
- package/dist/monitor/log-monitor.js +245 -0
- package/dist/monitor/log-monitor.js.map +1 -0
- package/dist/monitor/network-monitor.d.ts +103 -0
- package/dist/monitor/network-monitor.d.ts.map +1 -0
- package/dist/monitor/network-monitor.js +336 -0
- package/dist/monitor/network-monitor.js.map +1 -0
- package/dist/monitor/process-monitor.d.ts +108 -0
- package/dist/monitor/process-monitor.d.ts.map +1 -0
- package/dist/monitor/process-monitor.js +245 -0
- package/dist/monitor/process-monitor.js.map +1 -0
- package/dist/monitor/threat-intel-feeds.d.ts +141 -0
- package/dist/monitor/threat-intel-feeds.d.ts.map +1 -0
- package/dist/monitor/threat-intel-feeds.js +430 -0
- package/dist/monitor/threat-intel-feeds.js.map +1 -0
- package/dist/monitor/threat-intel.d.ts +83 -0
- package/dist/monitor/threat-intel.d.ts.map +1 -0
- package/dist/monitor/threat-intel.js +215 -0
- package/dist/monitor/threat-intel.js.map +1 -0
- package/dist/monitor/types.d.ts +65 -0
- package/dist/monitor/types.d.ts.map +1 -0
- package/dist/monitor/types.js +20 -0
- package/dist/monitor/types.js.map +1 -0
- package/dist/rules/index.d.ts +115 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +244 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/rule-loader.d.ts +54 -0
- package/dist/rules/rule-loader.d.ts.map +1 -0
- package/dist/rules/rule-loader.js +167 -0
- package/dist/rules/rule-loader.js.map +1 -0
- package/dist/rules/sigma-matcher.d.ts +40 -0
- package/dist/rules/sigma-matcher.d.ts.map +1 -0
- package/dist/rules/sigma-matcher.js +447 -0
- package/dist/rules/sigma-matcher.js.map +1 -0
- package/dist/rules/sigma-parser.d.ts +36 -0
- package/dist/rules/sigma-parser.d.ts.map +1 -0
- package/dist/rules/sigma-parser.js +180 -0
- package/dist/rules/sigma-parser.js.map +1 -0
- package/dist/rules/types.d.ts +112 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +11 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/yara-scanner.d.ts +103 -0
- package/dist/rules/yara-scanner.d.ts.map +1 -0
- package/dist/rules/yara-scanner.js +421 -0
- package/dist/rules/yara-scanner.js.map +1 -0
- package/dist/scoring/achievements.d.ts +76 -0
- package/dist/scoring/achievements.d.ts.map +1 -0
- package/dist/scoring/achievements.js +211 -0
- package/dist/scoring/achievements.js.map +1 -0
- package/dist/scoring/index.d.ts +3 -0
- package/dist/scoring/index.d.ts.map +1 -0
- package/dist/scoring/index.js +3 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/scoring/security-score.d.ts +60 -0
- package/dist/scoring/security-score.d.ts.map +1 -0
- package/dist/scoring/security-score.js +211 -0
- package/dist/scoring/security-score.js.map +1 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +38 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +71 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validation.d.ts +35 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +56 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sigma rule event matcher
|
|
3
|
+
* Sigma 規則事件比對器
|
|
4
|
+
*
|
|
5
|
+
* Matches SecurityEvent instances against Sigma rules by evaluating
|
|
6
|
+
* detection selections and condition expressions.
|
|
7
|
+
* Supports wildcards (*), the |contains modifier, and simple AND/OR/NOT logic.
|
|
8
|
+
* 將 SecurityEvent 實例與 Sigma 規則比對,透過評估偵測選擇項和條件表達式。
|
|
9
|
+
* 支援萬用字元(*)、|contains 修飾符,以及簡單的 AND/OR/NOT 邏輯。
|
|
10
|
+
*
|
|
11
|
+
* @module @panguard-ai/core/rules/sigma-matcher
|
|
12
|
+
*/
|
|
13
|
+
import { createLogger } from '../utils/logger.js';
|
|
14
|
+
const logger = createLogger('sigma-matcher');
|
|
15
|
+
/**
|
|
16
|
+
* Convert a Sigma wildcard pattern to a RegExp
|
|
17
|
+
* 將 Sigma 萬用字元模式轉換為正規表達式
|
|
18
|
+
*
|
|
19
|
+
* Sigma uses `*` as a wildcard matching zero or more characters.
|
|
20
|
+
* Sigma 使用 `*` 作為比對零個或多個字元的萬用字元。
|
|
21
|
+
*
|
|
22
|
+
* @param pattern - Sigma pattern string possibly containing `*` wildcards / 可能包含 `*` 萬用字元的 Sigma 模式字串
|
|
23
|
+
* @returns Compiled RegExp for the pattern / 模式的編譯正規表達式
|
|
24
|
+
*/
|
|
25
|
+
function wildcardToRegex(pattern) {
|
|
26
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
27
|
+
const withWildcards = escaped.replace(/\*/g, '.*');
|
|
28
|
+
return new RegExp(`^${withWildcards}$`, 'i');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Retrieve a field value from a SecurityEvent by name
|
|
32
|
+
* 依名稱從 SecurityEvent 取得欄位值
|
|
33
|
+
*
|
|
34
|
+
* Looks in the event's top-level properties first, then in metadata.
|
|
35
|
+
* 先在事件的頂層屬性中查找,然後在 metadata 中查找。
|
|
36
|
+
*
|
|
37
|
+
* @param event - The security event / 安全事件
|
|
38
|
+
* @param fieldName - Field name to look up / 要查找的欄位名稱
|
|
39
|
+
* @returns The field value as a string, or undefined if not found / 欄位值的字串,找不到則回傳 undefined
|
|
40
|
+
*/
|
|
41
|
+
function getEventFieldValue(event, fieldName) {
|
|
42
|
+
// Check top-level event properties first / 先檢查事件頂層屬性
|
|
43
|
+
const topLevelKeys = [
|
|
44
|
+
'id',
|
|
45
|
+
'source',
|
|
46
|
+
'severity',
|
|
47
|
+
'category',
|
|
48
|
+
'description',
|
|
49
|
+
'host',
|
|
50
|
+
];
|
|
51
|
+
for (const key of topLevelKeys) {
|
|
52
|
+
if (key === fieldName) {
|
|
53
|
+
const val = event[key];
|
|
54
|
+
if (typeof val === 'string')
|
|
55
|
+
return val;
|
|
56
|
+
if (val instanceof Date)
|
|
57
|
+
return val.toISOString();
|
|
58
|
+
return String(val);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Then check metadata / 然後檢查 metadata
|
|
62
|
+
const metaValue = event.metadata[fieldName];
|
|
63
|
+
if (metaValue === undefined || metaValue === null)
|
|
64
|
+
return undefined;
|
|
65
|
+
return String(metaValue);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse a field name and extract the base name and modifier
|
|
69
|
+
* 解析欄位名稱並擷取基礎名稱和修飾符
|
|
70
|
+
*
|
|
71
|
+
* Sigma field names can include modifiers like `|contains`, `|endswith`, `|startswith`.
|
|
72
|
+
* Sigma 欄位名稱可包含修飾符如 `|contains`、`|endswith`、`|startswith`。
|
|
73
|
+
*
|
|
74
|
+
* @param fieldName - Full field name possibly with modifier / 可能帶有修飾符的完整欄位名稱
|
|
75
|
+
* @returns Tuple of [baseName, modifier] / [基礎名稱, 修飾符] 的元組
|
|
76
|
+
*/
|
|
77
|
+
function parseFieldModifier(fieldName) {
|
|
78
|
+
const pipeIndex = fieldName.indexOf('|');
|
|
79
|
+
if (pipeIndex === -1)
|
|
80
|
+
return [fieldName, null];
|
|
81
|
+
return [fieldName.substring(0, pipeIndex), fieldName.substring(pipeIndex + 1)];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check whether a single field value matches an expected value with modifier support
|
|
85
|
+
* 檢查單一欄位值是否與預期值比對(支援修飾符)
|
|
86
|
+
*
|
|
87
|
+
* @param actual - The actual event field value / 事件的實際欄位值
|
|
88
|
+
* @param expected - The expected value from the rule / 規則中的預期值
|
|
89
|
+
* @param modifier - Optional modifier (contains, endswith, startswith) / 可選修飾符
|
|
90
|
+
* @returns True if the value matches / 值比對時回傳 true
|
|
91
|
+
*/
|
|
92
|
+
function matchValue(actual, expected, modifier) {
|
|
93
|
+
const actualLower = actual.toLowerCase();
|
|
94
|
+
const expectedLower = expected.toLowerCase();
|
|
95
|
+
// Handle chained modifiers (e.g., "contains|all") — use first modifier
|
|
96
|
+
const primaryModifier = modifier?.split('|')[0] ?? null;
|
|
97
|
+
switch (primaryModifier) {
|
|
98
|
+
case 'contains':
|
|
99
|
+
return actualLower.includes(expectedLower);
|
|
100
|
+
case 'endswith':
|
|
101
|
+
return actualLower.endsWith(expectedLower);
|
|
102
|
+
case 'startswith':
|
|
103
|
+
return actualLower.startsWith(expectedLower);
|
|
104
|
+
case 're':
|
|
105
|
+
try {
|
|
106
|
+
return new RegExp(expected, 'i').test(actual);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
logger.warn(`Invalid regex pattern: "${expected}" / 無效的正規表達式: "${expected}"`);
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
case 'base64':
|
|
113
|
+
case 'base64offset': {
|
|
114
|
+
// Check if the actual value contains the expected value in base64 form
|
|
115
|
+
try {
|
|
116
|
+
const decoded = Buffer.from(actual, 'base64').toString('utf-8');
|
|
117
|
+
return decoded.toLowerCase().includes(expectedLower);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
case 'cidr': {
|
|
124
|
+
// Basic CIDR matching for IP addresses
|
|
125
|
+
return matchCIDR(actual, expected);
|
|
126
|
+
}
|
|
127
|
+
case 'gt':
|
|
128
|
+
return Number(actual) > Number(expected);
|
|
129
|
+
case 'gte':
|
|
130
|
+
return Number(actual) >= Number(expected);
|
|
131
|
+
case 'lt':
|
|
132
|
+
return Number(actual) < Number(expected);
|
|
133
|
+
case 'lte':
|
|
134
|
+
return Number(actual) <= Number(expected);
|
|
135
|
+
case 'utf8':
|
|
136
|
+
case 'wide':
|
|
137
|
+
// Encoding modifiers — perform basic string matching
|
|
138
|
+
return actualLower.includes(expectedLower);
|
|
139
|
+
default: {
|
|
140
|
+
// Default: exact match or wildcard match / 預設:精確比對或萬用字元比對
|
|
141
|
+
if (expected.includes('*')) {
|
|
142
|
+
return wildcardToRegex(expected).test(actual);
|
|
143
|
+
}
|
|
144
|
+
return actualLower === expectedLower;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Basic CIDR matching for IP addresses
|
|
150
|
+
* 基本的 CIDR IP 位址比對
|
|
151
|
+
*/
|
|
152
|
+
function matchCIDR(ip, cidr) {
|
|
153
|
+
const parts = cidr.split('/');
|
|
154
|
+
if (parts.length !== 2)
|
|
155
|
+
return ip === cidr;
|
|
156
|
+
const cidrIP = parts[0];
|
|
157
|
+
const prefixLen = parseInt(parts[1], 10);
|
|
158
|
+
if (isNaN(prefixLen))
|
|
159
|
+
return false;
|
|
160
|
+
const ipNum = ipToNumber(ip);
|
|
161
|
+
const cidrNum = ipToNumber(cidrIP);
|
|
162
|
+
if (ipNum === null || cidrNum === null)
|
|
163
|
+
return false;
|
|
164
|
+
const mask = prefixLen === 0 ? 0 : (~0 << (32 - prefixLen)) >>> 0;
|
|
165
|
+
return (ipNum & mask) === (cidrNum & mask);
|
|
166
|
+
}
|
|
167
|
+
function ipToNumber(ip) {
|
|
168
|
+
const parts = ip.split('.');
|
|
169
|
+
if (parts.length !== 4)
|
|
170
|
+
return null;
|
|
171
|
+
let num = 0;
|
|
172
|
+
for (const part of parts) {
|
|
173
|
+
const val = parseInt(part, 10);
|
|
174
|
+
if (isNaN(val) || val < 0 || val > 255)
|
|
175
|
+
return null;
|
|
176
|
+
num = (num << 8) | val;
|
|
177
|
+
}
|
|
178
|
+
return num >>> 0;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Evaluate a single detection selection against an event
|
|
182
|
+
* 評估單一偵測選擇項與事件的比對
|
|
183
|
+
*
|
|
184
|
+
* All fields in the selection must match (AND logic within a selection).
|
|
185
|
+
* For array values, any value matching counts as a match (OR logic for arrays).
|
|
186
|
+
* 選擇項中的所有欄位都必須比對(選擇項內為 AND 邏輯)。
|
|
187
|
+
* 對於陣列值,任一值比對即算比對成功(陣列為 OR 邏輯)。
|
|
188
|
+
*
|
|
189
|
+
* @param event - The security event to test / 要測試的安全事件
|
|
190
|
+
* @param selection - The selection fields and values / 選擇項欄位和值
|
|
191
|
+
* @returns Object with match result and list of matched field names / 比對結果和比對到的欄位名稱列表
|
|
192
|
+
*/
|
|
193
|
+
function evaluateSelection(event, selection) {
|
|
194
|
+
const matchedFields = [];
|
|
195
|
+
for (const [rawFieldName, expectedValues] of Object.entries(selection)) {
|
|
196
|
+
const [baseName, modifier] = parseFieldModifier(rawFieldName);
|
|
197
|
+
const actual = getEventFieldValue(event, baseName);
|
|
198
|
+
if (actual === undefined) {
|
|
199
|
+
return { matched: false, fields: [] };
|
|
200
|
+
}
|
|
201
|
+
const values = Array.isArray(expectedValues) ? expectedValues : [expectedValues];
|
|
202
|
+
const fieldMatched = values.some((expected) => matchValue(actual, expected, modifier));
|
|
203
|
+
if (!fieldMatched) {
|
|
204
|
+
return { matched: false, fields: [] };
|
|
205
|
+
}
|
|
206
|
+
matchedFields.push(baseName);
|
|
207
|
+
}
|
|
208
|
+
return { matched: true, fields: matchedFields };
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Tokenize a condition expression into tokens
|
|
212
|
+
* 將條件表達式分詞為 token
|
|
213
|
+
*
|
|
214
|
+
* Splits the condition string into identifiers, operators (AND, OR, NOT),
|
|
215
|
+
* and parentheses.
|
|
216
|
+
* 將條件字串拆分為識別碼、運算子(AND、OR、NOT)和括號。
|
|
217
|
+
*
|
|
218
|
+
* @param condition - The condition string / 條件字串
|
|
219
|
+
* @returns Array of token strings / token 字串陣列
|
|
220
|
+
*/
|
|
221
|
+
function tokenize(condition) {
|
|
222
|
+
const tokens = [];
|
|
223
|
+
let current = '';
|
|
224
|
+
for (let i = 0; i < condition.length; i++) {
|
|
225
|
+
const ch = condition[i];
|
|
226
|
+
if (ch === '(' || ch === ')') {
|
|
227
|
+
if (current.trim())
|
|
228
|
+
tokens.push(current.trim());
|
|
229
|
+
tokens.push(ch);
|
|
230
|
+
current = '';
|
|
231
|
+
}
|
|
232
|
+
else if (ch === ' ' || ch === '\t') {
|
|
233
|
+
if (current.trim())
|
|
234
|
+
tokens.push(current.trim());
|
|
235
|
+
current = '';
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
current += ch;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (current.trim())
|
|
242
|
+
tokens.push(current.trim());
|
|
243
|
+
return tokens;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Resolve aggregation expressions like "1 of them", "all of them", "1 of selection*"
|
|
247
|
+
* 解析聚合表達式如 "1 of them"、"all of them"、"1 of selection*"
|
|
248
|
+
*
|
|
249
|
+
* Pre-processes the condition string to expand these into explicit OR/AND expressions.
|
|
250
|
+
*
|
|
251
|
+
* @param condition - The condition string / 條件字串
|
|
252
|
+
* @param selectionNames - Available selection names / 可用的選擇項名稱
|
|
253
|
+
* @returns Expanded condition string / 展開的條件字串
|
|
254
|
+
*/
|
|
255
|
+
function expandAggregations(condition, selectionNames) {
|
|
256
|
+
let result = condition;
|
|
257
|
+
// "all of them" → (sel1 AND sel2 AND ...)
|
|
258
|
+
result = result.replace(/\ball\s+of\s+them\b/gi, () => {
|
|
259
|
+
if (selectionNames.length === 0)
|
|
260
|
+
return 'false';
|
|
261
|
+
return '(' + selectionNames.join(' AND ') + ')';
|
|
262
|
+
});
|
|
263
|
+
// "1 of them" → (sel1 OR sel2 OR ...)
|
|
264
|
+
result = result.replace(/\b1\s+of\s+them\b/gi, () => {
|
|
265
|
+
if (selectionNames.length === 0)
|
|
266
|
+
return 'false';
|
|
267
|
+
return '(' + selectionNames.join(' OR ') + ')';
|
|
268
|
+
});
|
|
269
|
+
// "<N> of them" → at least N selections match (expand as OR of AND combos is complex,
|
|
270
|
+
// so we treat as "1 of them" for simplicity — covers most real-world rules)
|
|
271
|
+
result = result.replace(/\b\d+\s+of\s+them\b/gi, () => {
|
|
272
|
+
if (selectionNames.length === 0)
|
|
273
|
+
return 'false';
|
|
274
|
+
return '(' + selectionNames.join(' OR ') + ')';
|
|
275
|
+
});
|
|
276
|
+
// "all of <pattern>*" → AND of matching selections
|
|
277
|
+
result = result.replace(/\ball\s+of\s+(\w+)\*/gi, (_match, prefix) => {
|
|
278
|
+
const matching = selectionNames.filter((n) => n.startsWith(prefix));
|
|
279
|
+
if (matching.length === 0)
|
|
280
|
+
return 'false';
|
|
281
|
+
return '(' + matching.join(' AND ') + ')';
|
|
282
|
+
});
|
|
283
|
+
// "1 of <pattern>*" → OR of matching selections
|
|
284
|
+
result = result.replace(/\b1\s+of\s+(\w+)\*/gi, (_match, prefix) => {
|
|
285
|
+
const matching = selectionNames.filter((n) => n.startsWith(prefix));
|
|
286
|
+
if (matching.length === 0)
|
|
287
|
+
return 'false';
|
|
288
|
+
return '(' + matching.join(' OR ') + ')';
|
|
289
|
+
});
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Evaluate a condition expression given selection results
|
|
294
|
+
* 根據選擇項結果評估條件表達式
|
|
295
|
+
*
|
|
296
|
+
* Supports AND/OR/NOT with parentheses, plus Sigma aggregation expressions:
|
|
297
|
+
* "1 of them", "all of them", "1 of selection*", "all of filter*"
|
|
298
|
+
* 支援 AND/OR/NOT 搭配括號,以及 Sigma 聚合表達式。
|
|
299
|
+
*
|
|
300
|
+
* @param condition - The condition expression / 條件表達式
|
|
301
|
+
* @param selectionResults - Map of selection name to match result / 選擇項名稱到比對結果的映射
|
|
302
|
+
* @returns True if the condition is satisfied / 條件滿足時回傳 true
|
|
303
|
+
*/
|
|
304
|
+
function evaluateCondition(condition, selectionResults) {
|
|
305
|
+
// Expand aggregation expressions / 展開聚合表達式
|
|
306
|
+
const selectionNames = Array.from(selectionResults.keys());
|
|
307
|
+
const expanded = expandAggregations(condition, selectionNames);
|
|
308
|
+
const tokens = tokenize(expanded);
|
|
309
|
+
// Simple case: single selection name / 簡單情況:單一選擇項名稱
|
|
310
|
+
if (tokens.length === 1) {
|
|
311
|
+
const name = tokens[0];
|
|
312
|
+
if (name === 'false')
|
|
313
|
+
return false;
|
|
314
|
+
if (name === 'true')
|
|
315
|
+
return true;
|
|
316
|
+
return selectionResults.get(name) ?? false;
|
|
317
|
+
}
|
|
318
|
+
// Recursive descent parser for AND/OR/NOT with parentheses
|
|
319
|
+
// 遞迴下降解析器,處理 AND/OR/NOT 和括號
|
|
320
|
+
let pos = 0;
|
|
321
|
+
function peek() {
|
|
322
|
+
return tokens[pos];
|
|
323
|
+
}
|
|
324
|
+
function consume() {
|
|
325
|
+
const tok = tokens[pos];
|
|
326
|
+
pos++;
|
|
327
|
+
return tok;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Parse primary: NOT, parenthesized expression, or selection name
|
|
331
|
+
* 解析主要項:NOT、括號表達式或選擇項名稱
|
|
332
|
+
*/
|
|
333
|
+
function parsePrimary() {
|
|
334
|
+
const tok = peek();
|
|
335
|
+
if (tok === undefined)
|
|
336
|
+
return false;
|
|
337
|
+
if (tok.toUpperCase() === 'NOT') {
|
|
338
|
+
consume();
|
|
339
|
+
return !parsePrimary();
|
|
340
|
+
}
|
|
341
|
+
if (tok === '(') {
|
|
342
|
+
consume(); // consume '('
|
|
343
|
+
const result = parseOr();
|
|
344
|
+
if (peek() === ')')
|
|
345
|
+
consume(); // consume ')'
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
// It is a selection name / 是選擇項名稱
|
|
349
|
+
consume();
|
|
350
|
+
if (tok === 'false')
|
|
351
|
+
return false;
|
|
352
|
+
if (tok === 'true')
|
|
353
|
+
return true;
|
|
354
|
+
return selectionResults.get(tok) ?? false;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Parse AND expressions / 解析 AND 表達式
|
|
358
|
+
*/
|
|
359
|
+
function parseAnd() {
|
|
360
|
+
let result = parsePrimary();
|
|
361
|
+
while (peek()?.toUpperCase() === 'AND') {
|
|
362
|
+
consume();
|
|
363
|
+
const right = parsePrimary();
|
|
364
|
+
result = result && right;
|
|
365
|
+
}
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Parse OR expressions (lowest precedence) / 解析 OR 表達式(最低優先權)
|
|
370
|
+
*/
|
|
371
|
+
function parseOr() {
|
|
372
|
+
let result = parseAnd();
|
|
373
|
+
while (peek()?.toUpperCase() === 'OR') {
|
|
374
|
+
consume();
|
|
375
|
+
const right = parseAnd();
|
|
376
|
+
result = result || right;
|
|
377
|
+
}
|
|
378
|
+
return result;
|
|
379
|
+
}
|
|
380
|
+
return parseOr();
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Match a single security event against a single Sigma rule
|
|
384
|
+
* 比對單一安全事件與單一 Sigma 規則
|
|
385
|
+
*
|
|
386
|
+
* Evaluates all selections in the rule's detection block, then checks
|
|
387
|
+
* whether the condition expression is satisfied.
|
|
388
|
+
* 評估規則偵測區塊中的所有選擇項,然後檢查條件表達式是否滿足。
|
|
389
|
+
*
|
|
390
|
+
* @param event - The security event to test / 要測試的安全事件
|
|
391
|
+
* @param rule - The Sigma rule to match against / 要比對的 Sigma 規則
|
|
392
|
+
* @returns A RuleMatch if the event matches, or null / 事件比對時回傳 RuleMatch,否則回傳 null
|
|
393
|
+
*/
|
|
394
|
+
export function matchEvent(event, rule) {
|
|
395
|
+
const detection = rule.detection;
|
|
396
|
+
const selectionResults = new Map();
|
|
397
|
+
const allMatchedFields = [];
|
|
398
|
+
// Evaluate each selection in the detection block / 評估偵測區塊中的每個選擇項
|
|
399
|
+
for (const [key, value] of Object.entries(detection)) {
|
|
400
|
+
if (key === 'condition')
|
|
401
|
+
continue;
|
|
402
|
+
if (typeof value === 'string')
|
|
403
|
+
continue; // skip condition-like entries / 跳過條件類條目
|
|
404
|
+
const result = evaluateSelection(event, value);
|
|
405
|
+
selectionResults.set(key, result.matched);
|
|
406
|
+
if (result.matched) {
|
|
407
|
+
allMatchedFields.push(...result.fields);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
// Evaluate the condition expression / 評估條件表達式
|
|
411
|
+
const conditionMet = evaluateCondition(detection.condition, selectionResults);
|
|
412
|
+
if (!conditionMet) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
// Deduplicate matched fields / 去重比對到的欄位
|
|
416
|
+
const uniqueFields = [...new Set(allMatchedFields)];
|
|
417
|
+
const match = {
|
|
418
|
+
rule,
|
|
419
|
+
event,
|
|
420
|
+
matchedFields: uniqueFields,
|
|
421
|
+
timestamp: new Date().toISOString(),
|
|
422
|
+
};
|
|
423
|
+
logger.info(`Event matched rule "${rule.title}" (${rule.id}) / 事件比對到規則 "${rule.title}" (${rule.id})`, { eventId: event.id, matchedFields: uniqueFields });
|
|
424
|
+
return match;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Match a single security event against multiple Sigma rules
|
|
428
|
+
* 比對單一安全事件與多個 Sigma 規則
|
|
429
|
+
*
|
|
430
|
+
* Tests the event against every rule and returns all matches.
|
|
431
|
+
* 將事件與每個規則測試並回傳所有比對結果。
|
|
432
|
+
*
|
|
433
|
+
* @param event - The security event to test / 要測試的安全事件
|
|
434
|
+
* @param rules - Array of Sigma rules to match against / 要比對的 Sigma 規則陣列
|
|
435
|
+
* @returns Array of RuleMatch for all matching rules / 所有比對規則的 RuleMatch 陣列
|
|
436
|
+
*/
|
|
437
|
+
export function matchEventAgainstRules(event, rules) {
|
|
438
|
+
const matches = [];
|
|
439
|
+
for (const rule of rules) {
|
|
440
|
+
const result = matchEvent(event, rule);
|
|
441
|
+
if (result !== null) {
|
|
442
|
+
matches.push(result);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return matches;
|
|
446
|
+
}
|
|
447
|
+
//# sourceMappingURL=sigma-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigma-matcher.js","sourceRoot":"","sources":["../../src/rules/sigma-matcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sigma YAML rule parser
|
|
3
|
+
* Sigma YAML 規則解析器
|
|
4
|
+
*
|
|
5
|
+
* Parses Sigma rules from YAML format into typed SigmaRule objects.
|
|
6
|
+
* Validates required fields and logs warnings for missing optional fields.
|
|
7
|
+
* 將 Sigma 規則從 YAML 格式解析為型別化的 SigmaRule 物件。
|
|
8
|
+
* 驗證必要欄位並對缺少的可選欄位記錄警告。
|
|
9
|
+
*
|
|
10
|
+
* @module @panguard-ai/core/rules/sigma-parser
|
|
11
|
+
*/
|
|
12
|
+
import type { SigmaRule } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Parse a Sigma rule from a YAML string
|
|
15
|
+
* 從 YAML 字串解析 Sigma 規則
|
|
16
|
+
*
|
|
17
|
+
* Validates required fields (title, detection, level) and normalizes
|
|
18
|
+
* optional fields with sensible defaults.
|
|
19
|
+
* 驗證必要欄位(title、detection、level)並以合理預設值標準化可選欄位。
|
|
20
|
+
*
|
|
21
|
+
* @param yamlContent - Raw YAML string content / 原始 YAML 字串內容
|
|
22
|
+
* @returns Parsed SigmaRule or null if validation fails / 解析後的 SigmaRule,驗證失敗則回傳 null
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseSigmaYaml(yamlContent: string): SigmaRule | null;
|
|
25
|
+
/**
|
|
26
|
+
* Parse a Sigma rule from a YAML file on disk
|
|
27
|
+
* 從磁碟上的 YAML 檔案解析 Sigma 規則
|
|
28
|
+
*
|
|
29
|
+
* Reads the file contents and delegates to parseSigmaYaml.
|
|
30
|
+
* 讀取檔案內容並委派給 parseSigmaYaml。
|
|
31
|
+
*
|
|
32
|
+
* @param filePath - Absolute or relative path to the YAML file / YAML 檔案的絕對或相對路徑
|
|
33
|
+
* @returns Parsed SigmaRule or null if file read or parsing fails / 解析後的 SigmaRule,讀取或解析失敗則回傳 null
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseSigmaFile(filePath: string): SigmaRule | null;
|
|
36
|
+
//# sourceMappingURL=sigma-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigma-parser.d.ts","sourceRoot":"","sources":["../../src/rules/sigma-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAkC,MAAM,YAAY,CAAC;AAU5E;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CA8JpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAejE"}
|