@panguard-ai/panguard-guard 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/agent/analyze-agent.d.ts +62 -0
- package/dist/agent/analyze-agent.d.ts.map +1 -0
- package/dist/agent/analyze-agent.js +327 -0
- package/dist/agent/analyze-agent.js.map +1 -0
- package/dist/agent/detect-agent.d.ts +59 -0
- package/dist/agent/detect-agent.d.ts.map +1 -0
- package/dist/agent/detect-agent.js +214 -0
- package/dist/agent/detect-agent.js.map +1 -0
- package/dist/agent/index.d.ts +15 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +14 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/report-agent.d.ts +122 -0
- package/dist/agent/report-agent.d.ts.map +1 -0
- package/dist/agent/report-agent.js +468 -0
- package/dist/agent/report-agent.js.map +1 -0
- package/dist/agent/respond-agent.d.ts +113 -0
- package/dist/agent/respond-agent.d.ts.map +1 -0
- package/dist/agent/respond-agent.js +749 -0
- package/dist/agent/respond-agent.js.map +1 -0
- package/dist/agent-client/index.d.ts +81 -0
- package/dist/agent-client/index.d.ts.map +1 -0
- package/dist/agent-client/index.js +170 -0
- package/dist/agent-client/index.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +295 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +108 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/index.d.ts +66 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +284 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/dashboard/index.d.ts +78 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +455 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/guard-engine.d.ts +108 -0
- package/dist/guard-engine.d.ts.map +1 -0
- package/dist/guard-engine.js +740 -0
- package/dist/guard-engine.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/install/index.d.ts +23 -0
- package/dist/install/index.d.ts.map +1 -0
- package/dist/install/index.js +216 -0
- package/dist/install/index.js.map +1 -0
- package/dist/investigation/index.d.ts +80 -0
- package/dist/investigation/index.d.ts.map +1 -0
- package/dist/investigation/index.js +570 -0
- package/dist/investigation/index.js.map +1 -0
- package/dist/license/index.d.ts +46 -0
- package/dist/license/index.d.ts.map +1 -0
- package/dist/license/index.js +145 -0
- package/dist/license/index.js.map +1 -0
- package/dist/memory/baseline.d.ts +34 -0
- package/dist/memory/baseline.d.ts.map +1 -0
- package/dist/memory/baseline.js +224 -0
- package/dist/memory/baseline.js.map +1 -0
- package/dist/memory/index.d.ts +32 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +58 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/learning.d.ts +35 -0
- package/dist/memory/learning.d.ts.map +1 -0
- package/dist/memory/learning.js +60 -0
- package/dist/memory/learning.js.map +1 -0
- package/dist/monitors/falco-monitor.d.ts +62 -0
- package/dist/monitors/falco-monitor.d.ts.map +1 -0
- package/dist/monitors/falco-monitor.js +226 -0
- package/dist/monitors/falco-monitor.js.map +1 -0
- package/dist/monitors/suricata-monitor.d.ts +80 -0
- package/dist/monitors/suricata-monitor.d.ts.map +1 -0
- package/dist/monitors/suricata-monitor.js +227 -0
- package/dist/monitors/suricata-monitor.js.map +1 -0
- package/dist/notify/email.d.ts +23 -0
- package/dist/notify/email.d.ts.map +1 -0
- package/dist/notify/email.js +124 -0
- package/dist/notify/email.js.map +1 -0
- package/dist/notify/index.d.ts +31 -0
- package/dist/notify/index.d.ts.map +1 -0
- package/dist/notify/index.js +70 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/line-notify.d.ts.map +1 -0
- package/dist/notify/slack.d.ts +21 -0
- package/dist/notify/slack.d.ts.map +1 -0
- package/dist/notify/slack.js +92 -0
- package/dist/notify/slack.js.map +1 -0
- package/dist/notify/telegram.d.ts +21 -0
- package/dist/notify/telegram.d.ts.map +1 -0
- package/dist/notify/telegram.js +89 -0
- package/dist/notify/telegram.js.map +1 -0
- package/dist/response/file-quarantine.d.ts +63 -0
- package/dist/response/file-quarantine.d.ts.map +1 -0
- package/dist/response/file-quarantine.js +137 -0
- package/dist/response/file-quarantine.js.map +1 -0
- package/dist/response/index.d.ts +4 -0
- package/dist/response/index.d.ts.map +1 -0
- package/dist/response/index.js +4 -0
- package/dist/response/index.js.map +1 -0
- package/dist/response/ip-blocker.d.ts +69 -0
- package/dist/response/ip-blocker.d.ts.map +1 -0
- package/dist/response/ip-blocker.js +191 -0
- package/dist/response/ip-blocker.js.map +1 -0
- package/dist/response/process-killer.d.ts +49 -0
- package/dist/response/process-killer.d.ts.map +1 -0
- package/dist/response/process-killer.js +230 -0
- package/dist/response/process-killer.js.map +1 -0
- package/dist/rules/builtin-rules.d.ts +12 -0
- package/dist/rules/builtin-rules.d.ts.map +1 -0
- package/dist/rules/builtin-rules.js +471 -0
- package/dist/rules/builtin-rules.js.map +1 -0
- package/dist/threat-cloud/client-id.d.ts +13 -0
- package/dist/threat-cloud/client-id.d.ts.map +1 -0
- package/dist/threat-cloud/client-id.js +38 -0
- package/dist/threat-cloud/client-id.js.map +1 -0
- package/dist/threat-cloud/index.d.ts +103 -0
- package/dist/threat-cloud/index.d.ts.map +1 -0
- package/dist/threat-cloud/index.js +386 -0
- package/dist/threat-cloud/index.js.map +1 -0
- package/dist/types.d.ts +336 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +42 -0
- package/dist/types.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic Reasoning Investigation Engine
|
|
3
|
+
* 動態推理調查引擎
|
|
4
|
+
*
|
|
5
|
+
* Performs multi-step investigation on suspicious events using a variety
|
|
6
|
+
* of inspection tools. Each tool contributes risk data and may trigger
|
|
7
|
+
* additional investigation steps based on findings.
|
|
8
|
+
* 使用多種檢查工具對可疑事件進行多步驟調查。每個工具貢獻風險數據,
|
|
9
|
+
* 並可能根據發現觸發額外的調查步驟。
|
|
10
|
+
*
|
|
11
|
+
* @module @panguard-ai/panguard-guard/investigation
|
|
12
|
+
*/
|
|
13
|
+
import { createLogger, checkThreatIntel } from '@panguard-ai/core';
|
|
14
|
+
const logger = createLogger('panguard-guard:investigation');
|
|
15
|
+
/** Maximum investigation steps to prevent infinite loops / 最大調查步驟數以防止無限循環 */
|
|
16
|
+
const MAX_STEPS = 8;
|
|
17
|
+
/** Max events to keep in the sliding window / 滑動視窗保留的最大事件數 */
|
|
18
|
+
const EVENT_BUFFER_SIZE = 500;
|
|
19
|
+
/** Correlation time window in ms (10 minutes) / 關聯時間視窗(10 分鐘) */
|
|
20
|
+
const CORRELATION_WINDOW_MS = 10 * 60 * 1000;
|
|
21
|
+
/**
|
|
22
|
+
* Investigation Engine performs dynamic, multi-step reasoning about security events
|
|
23
|
+
* 調查引擎對安全事件進行動態多步驟推理
|
|
24
|
+
*/
|
|
25
|
+
export class InvestigationEngine {
|
|
26
|
+
baseline;
|
|
27
|
+
/** Sliding window of recent events for correlation / 近期事件滑動視窗 */
|
|
28
|
+
eventBuffer = [];
|
|
29
|
+
constructor(baseline) {
|
|
30
|
+
this.baseline = baseline;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Feed an event into the correlation buffer.
|
|
34
|
+
* Call this for every event processed by the guard engine.
|
|
35
|
+
*/
|
|
36
|
+
recordEvent(event) {
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
this.eventBuffer.push({ event, receivedAt: now });
|
|
39
|
+
// Trim old events beyond buffer size
|
|
40
|
+
while (this.eventBuffer.length > EVENT_BUFFER_SIZE) {
|
|
41
|
+
this.eventBuffer.shift();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Investigate a security event using dynamic reasoning
|
|
46
|
+
* 使用動態推理調查安全事件
|
|
47
|
+
*
|
|
48
|
+
* Creates an investigation plan based on event characteristics,
|
|
49
|
+
* executes each tool step, and collects findings. Steps may trigger
|
|
50
|
+
* additional investigation based on intermediate results.
|
|
51
|
+
* 根據事件特徵建立調查計畫,執行每個工具步驟並收集發現。
|
|
52
|
+
* 步驟可能根據中間結果觸發額外調查。
|
|
53
|
+
*
|
|
54
|
+
* @param event - The security event to investigate / 要調查的安全事件
|
|
55
|
+
* @returns Completed investigation plan with all results / 包含所有結果的已完成調查計畫
|
|
56
|
+
*/
|
|
57
|
+
async investigate(event) {
|
|
58
|
+
logger.info(`Starting investigation for event ${event.id} / 開始調查事件 ${event.id}`);
|
|
59
|
+
const plan = this.createPlan(event);
|
|
60
|
+
const completedSteps = [];
|
|
61
|
+
for (const step of plan.steps) {
|
|
62
|
+
if (completedSteps.length >= MAX_STEPS) {
|
|
63
|
+
logger.info(`Max investigation steps (${MAX_STEPS}) reached / 已達最大調查步驟數`);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
const startTime = Date.now();
|
|
67
|
+
const result = await this.executeStep(step.tool, event);
|
|
68
|
+
const durationMs = Date.now() - startTime;
|
|
69
|
+
const completedStep = {
|
|
70
|
+
...step,
|
|
71
|
+
result,
|
|
72
|
+
durationMs,
|
|
73
|
+
};
|
|
74
|
+
completedSteps.push(completedStep);
|
|
75
|
+
logger.info(`Step ${step.tool}: risk=${result.riskContribution}, ` +
|
|
76
|
+
`needs_more=${result.needsAdditionalInvestigation} / ` +
|
|
77
|
+
`步驟 ${step.tool}: 風險=${result.riskContribution}`);
|
|
78
|
+
// Dynamic reasoning: add follow-up steps if needed
|
|
79
|
+
// 動態推理:如需要則添加後續步驟
|
|
80
|
+
if (result.needsAdditionalInvestigation) {
|
|
81
|
+
const followUpTools = this.getFollowUpTools(step.tool, result);
|
|
82
|
+
for (const followUp of followUpTools) {
|
|
83
|
+
if (completedSteps.length < MAX_STEPS &&
|
|
84
|
+
!completedSteps.some((s) => s.tool === followUp) &&
|
|
85
|
+
!plan.steps.some((s) => s.tool === followUp)) {
|
|
86
|
+
const fStart = Date.now();
|
|
87
|
+
const fResult = await this.executeStep(followUp, event);
|
|
88
|
+
const fDuration = Date.now() - fStart;
|
|
89
|
+
completedSteps.push({
|
|
90
|
+
tool: followUp,
|
|
91
|
+
reason: `Follow-up from ${step.tool}: ${result.finding} / 來自 ${step.tool} 的後續調查`,
|
|
92
|
+
result: fResult,
|
|
93
|
+
durationMs: fDuration,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
steps: completedSteps,
|
|
101
|
+
reasoning: this.buildReasoning(completedSteps),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create an initial investigation plan based on event characteristics
|
|
106
|
+
* 根據事件特徵建立初始調查計畫
|
|
107
|
+
*/
|
|
108
|
+
createPlan(event) {
|
|
109
|
+
const steps = [];
|
|
110
|
+
// Always check time anomaly / 總是檢查時間異常
|
|
111
|
+
steps.push({
|
|
112
|
+
tool: 'checkTimeAnomaly',
|
|
113
|
+
reason: 'Check if event occurred during unusual hours / 檢查事件是否發生在異常時間',
|
|
114
|
+
});
|
|
115
|
+
// Network events: check IP and geo / 網路事件:檢查 IP 和地理位置
|
|
116
|
+
if (event.source === 'network') {
|
|
117
|
+
steps.push({
|
|
118
|
+
tool: 'checkIPHistory',
|
|
119
|
+
reason: 'Check IP reputation and history / 檢查 IP 信譽和歷史',
|
|
120
|
+
});
|
|
121
|
+
steps.push({
|
|
122
|
+
tool: 'checkGeoLocation',
|
|
123
|
+
reason: 'Verify geographic origin of connection / 驗證連線的地理來源',
|
|
124
|
+
});
|
|
125
|
+
steps.push({
|
|
126
|
+
tool: 'checkNetworkPattern',
|
|
127
|
+
reason: 'Analyze network communication patterns / 分析網路通訊模式',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// Process events: check process tree and file reputation
|
|
131
|
+
// 程序事件:檢查程序樹和檔案信譽
|
|
132
|
+
if (event.source === 'process') {
|
|
133
|
+
steps.push({
|
|
134
|
+
tool: 'checkProcessTree',
|
|
135
|
+
reason: 'Examine parent-child process relationships / 檢查父子程序關係',
|
|
136
|
+
});
|
|
137
|
+
steps.push({
|
|
138
|
+
tool: 'checkFileReputation',
|
|
139
|
+
reason: 'Check executable file reputation / 檢查可執行檔信譽',
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Auth events: check user privilege and related events
|
|
143
|
+
// 認證事件:檢查使用者權限和相關事件
|
|
144
|
+
if (event.category === 'authentication' || event.category === 'authorization') {
|
|
145
|
+
steps.push({
|
|
146
|
+
tool: 'checkUserPrivilege',
|
|
147
|
+
reason: 'Verify user privilege level / 驗證使用者權限等級',
|
|
148
|
+
});
|
|
149
|
+
steps.push({
|
|
150
|
+
tool: 'checkRelatedEvents',
|
|
151
|
+
reason: 'Look for related suspicious activity / 查找相關可疑活動',
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
// File events: check file reputation / 檔案事件:檢查檔案信譽
|
|
155
|
+
if (event.source === 'file') {
|
|
156
|
+
steps.push({
|
|
157
|
+
tool: 'checkFileReputation',
|
|
158
|
+
reason: 'Analyze file reputation and hash / 分析檔案信譽和雜湊',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
steps,
|
|
163
|
+
reasoning: `Investigation plan for ${event.source}/${event.category} event / ` +
|
|
164
|
+
`${event.source}/${event.category} 事件的調查計畫`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Execute a single investigation step
|
|
169
|
+
* 執行單一調查步驟
|
|
170
|
+
*/
|
|
171
|
+
async executeStep(tool, event) {
|
|
172
|
+
switch (tool) {
|
|
173
|
+
case 'checkIPHistory':
|
|
174
|
+
return this.checkIPHistory(event);
|
|
175
|
+
case 'checkUserPrivilege':
|
|
176
|
+
return this.checkUserPrivilege(event);
|
|
177
|
+
case 'checkTimeAnomaly':
|
|
178
|
+
return this.checkTimeAnomaly(event);
|
|
179
|
+
case 'checkGeoLocation':
|
|
180
|
+
return this.checkGeoLocation(event);
|
|
181
|
+
case 'checkRelatedEvents':
|
|
182
|
+
return this.checkRelatedEvents(event);
|
|
183
|
+
case 'checkProcessTree':
|
|
184
|
+
return this.checkProcessTree(event);
|
|
185
|
+
case 'checkFileReputation':
|
|
186
|
+
return this.checkFileReputation(event);
|
|
187
|
+
case 'checkNetworkPattern':
|
|
188
|
+
return this.checkNetworkPattern(event);
|
|
189
|
+
default:
|
|
190
|
+
return {
|
|
191
|
+
finding: `Unknown tool: ${tool} / 未知工具`,
|
|
192
|
+
riskContribution: 0,
|
|
193
|
+
needsAdditionalInvestigation: false,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Determine follow-up investigation tools based on a step's results
|
|
199
|
+
* 根據步驟結果決定後續調查工具
|
|
200
|
+
*/
|
|
201
|
+
getFollowUpTools(tool, result) {
|
|
202
|
+
const followUps = [];
|
|
203
|
+
if (tool === 'checkIPHistory' && result.riskContribution > 50) {
|
|
204
|
+
followUps.push('checkGeoLocation', 'checkRelatedEvents');
|
|
205
|
+
}
|
|
206
|
+
if (tool === 'checkProcessTree' && result.riskContribution > 40) {
|
|
207
|
+
followUps.push('checkFileReputation');
|
|
208
|
+
}
|
|
209
|
+
if (tool === 'checkTimeAnomaly' && result.riskContribution > 60) {
|
|
210
|
+
followUps.push('checkUserPrivilege', 'checkRelatedEvents');
|
|
211
|
+
}
|
|
212
|
+
if (tool === 'checkUserPrivilege' && result.riskContribution > 50) {
|
|
213
|
+
followUps.push('checkRelatedEvents');
|
|
214
|
+
}
|
|
215
|
+
return followUps;
|
|
216
|
+
}
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// Investigation tool implementations / 調查工具實作
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
/** Check IP history against threat intelligence / 檢查 IP 歷史(威脅情報) */
|
|
221
|
+
checkIPHistory(event) {
|
|
222
|
+
const ip = event.metadata?.['sourceIP'] ?? event.metadata?.['remoteAddress'];
|
|
223
|
+
if (!ip) {
|
|
224
|
+
return {
|
|
225
|
+
finding: 'No IP address available for lookup / 無可查詢的 IP 地址',
|
|
226
|
+
riskContribution: 0,
|
|
227
|
+
needsAdditionalInvestigation: false,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const threatEntry = checkThreatIntel(ip);
|
|
231
|
+
if (threatEntry) {
|
|
232
|
+
return {
|
|
233
|
+
finding: `IP ${ip} found in threat intel: ${threatEntry.type} (${threatEntry.source}) / ` +
|
|
234
|
+
`IP ${ip} 在威脅情報中: ${threatEntry.type} (${threatEntry.source})`,
|
|
235
|
+
riskContribution: 80,
|
|
236
|
+
needsAdditionalInvestigation: true,
|
|
237
|
+
data: { ip, threat: `${threatEntry.type} (${threatEntry.source})`, type: threatEntry.type },
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
finding: `IP ${ip} not found in threat intel / IP ${ip} 未在威脅情報中`,
|
|
242
|
+
riskContribution: 0,
|
|
243
|
+
needsAdditionalInvestigation: false,
|
|
244
|
+
data: { ip },
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/** Check user privilege level / 檢查使用者權限等級 */
|
|
248
|
+
checkUserPrivilege(event) {
|
|
249
|
+
const user = event.metadata?.['user'] ?? event.metadata?.['username'];
|
|
250
|
+
if (!user) {
|
|
251
|
+
return {
|
|
252
|
+
finding: 'No user information available / 無可用的使用者資訊',
|
|
253
|
+
riskContribution: 0,
|
|
254
|
+
needsAdditionalInvestigation: false,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
// Check if root/admin / 檢查是否為 root/admin
|
|
258
|
+
const isPrivileged = [
|
|
259
|
+
'root',
|
|
260
|
+
'admin',
|
|
261
|
+
'administrator',
|
|
262
|
+
'system',
|
|
263
|
+
'nt authority\\system',
|
|
264
|
+
].includes(user.toLowerCase());
|
|
265
|
+
if (isPrivileged) {
|
|
266
|
+
return {
|
|
267
|
+
finding: `Privileged user activity: ${user} / 特權使用者活動: ${user}`,
|
|
268
|
+
riskContribution: 60,
|
|
269
|
+
needsAdditionalInvestigation: true,
|
|
270
|
+
data: { user, privileged: true },
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// Check if user is in baseline / 檢查使用者是否在基線中
|
|
274
|
+
const knownUser = this.baseline.normalLoginPatterns.some((l) => l.username === user);
|
|
275
|
+
if (!knownUser) {
|
|
276
|
+
return {
|
|
277
|
+
finding: `Unknown user: ${user} (not in baseline) / 未知使用者: ${user}`,
|
|
278
|
+
riskContribution: 45,
|
|
279
|
+
needsAdditionalInvestigation: true,
|
|
280
|
+
data: { user, known: false },
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
finding: `Known user: ${user} / 已知使用者: ${user}`,
|
|
285
|
+
riskContribution: 0,
|
|
286
|
+
needsAdditionalInvestigation: false,
|
|
287
|
+
data: { user, known: true },
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
/** Check time anomaly / 檢查時間異常 */
|
|
291
|
+
checkTimeAnomaly(event) {
|
|
292
|
+
const eventTime = event.timestamp instanceof Date ? event.timestamp : new Date(event.timestamp);
|
|
293
|
+
const hour = eventTime.getHours();
|
|
294
|
+
// Business hours: 6-22 / 營業時間: 6-22
|
|
295
|
+
const outsideBusinessHours = hour < 6 || hour > 22;
|
|
296
|
+
if (outsideBusinessHours) {
|
|
297
|
+
// Check if this user normally operates at this hour
|
|
298
|
+
// 檢查該使用者是否通常在此時間操作
|
|
299
|
+
const user = event.metadata?.['user'] ?? event.metadata?.['username'];
|
|
300
|
+
const hasNightPattern = user
|
|
301
|
+
? this.baseline.normalLoginPatterns.some((l) => l.username === user && (l.hourOfDay < 6 || l.hourOfDay > 22))
|
|
302
|
+
: false;
|
|
303
|
+
if (hasNightPattern) {
|
|
304
|
+
return {
|
|
305
|
+
finding: `Off-hours activity (${hour}:00) but user has night pattern / ` +
|
|
306
|
+
`非工作時間活動但使用者有夜間模式`,
|
|
307
|
+
riskContribution: 15,
|
|
308
|
+
needsAdditionalInvestigation: false,
|
|
309
|
+
data: { hour, outsideBusinessHours: true, hasNightPattern: true },
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
finding: `Activity at unusual hour (${hour}:00) / 在異常時間活動 (${hour}:00)`,
|
|
314
|
+
riskContribution: 40,
|
|
315
|
+
needsAdditionalInvestigation: true,
|
|
316
|
+
data: { hour, outsideBusinessHours: true, hasNightPattern: false },
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
finding: `Activity during normal hours (${hour}:00) / 正常時間活動`,
|
|
321
|
+
riskContribution: 0,
|
|
322
|
+
needsAdditionalInvestigation: false,
|
|
323
|
+
data: { hour, outsideBusinessHours: false },
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
/** Check geographic location / 檢查地理位置 */
|
|
327
|
+
checkGeoLocation(event) {
|
|
328
|
+
const ip = event.metadata?.['sourceIP'] ?? event.metadata?.['remoteAddress'];
|
|
329
|
+
if (!ip) {
|
|
330
|
+
return {
|
|
331
|
+
finding: 'No IP for geolocation / 無可查詢的 IP',
|
|
332
|
+
riskContribution: 0,
|
|
333
|
+
needsAdditionalInvestigation: false,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
// Check if from known baseline connections / 檢查是否來自已知基線連線
|
|
337
|
+
const knownConnection = this.baseline.normalConnections.some((c) => c.remoteAddress === ip);
|
|
338
|
+
if (!knownConnection) {
|
|
339
|
+
return {
|
|
340
|
+
finding: `Connection from new IP: ${ip} (not in baseline) / ` +
|
|
341
|
+
`來自新 IP 的連線: ${ip} (不在基線中)`,
|
|
342
|
+
riskContribution: 35,
|
|
343
|
+
needsAdditionalInvestigation: true,
|
|
344
|
+
data: { ip, known: false },
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
finding: `Connection from known IP: ${ip} / 來自已知 IP 的連線`,
|
|
349
|
+
riskContribution: 0,
|
|
350
|
+
needsAdditionalInvestigation: false,
|
|
351
|
+
data: { ip, known: true },
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/** Check related events using the sliding window buffer / 使用滑動視窗緩衝區檢查相關事件 */
|
|
355
|
+
checkRelatedEvents(event) {
|
|
356
|
+
const now = Date.now();
|
|
357
|
+
const cutoff = now - CORRELATION_WINDOW_MS;
|
|
358
|
+
// Extract correlation keys from the current event
|
|
359
|
+
const eventIP = event.metadata?.['sourceIP'] ?? event.metadata?.['remoteAddress'];
|
|
360
|
+
const eventUser = event.metadata?.['user'] ?? event.metadata?.['username'];
|
|
361
|
+
const eventProcess = event.metadata?.['processName'];
|
|
362
|
+
// Find related events in the time window (excluding the event itself)
|
|
363
|
+
const related = [];
|
|
364
|
+
for (const stored of this.eventBuffer) {
|
|
365
|
+
if (stored.receivedAt < cutoff)
|
|
366
|
+
continue;
|
|
367
|
+
if (stored.event.id === event.id)
|
|
368
|
+
continue;
|
|
369
|
+
const storedIP = stored.event.metadata?.['sourceIP'] ??
|
|
370
|
+
stored.event.metadata?.['remoteAddress'];
|
|
371
|
+
const storedUser = stored.event.metadata?.['user'] ??
|
|
372
|
+
stored.event.metadata?.['username'];
|
|
373
|
+
const storedProcess = stored.event.metadata?.['processName'];
|
|
374
|
+
// Same source IP
|
|
375
|
+
if (eventIP && storedIP && eventIP === storedIP) {
|
|
376
|
+
related.push({ event: stored.event, reason: `same_ip:${eventIP}` });
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
// Same user
|
|
380
|
+
if (eventUser && storedUser && eventUser === storedUser) {
|
|
381
|
+
related.push({ event: stored.event, reason: `same_user:${eventUser}` });
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
// Same process
|
|
385
|
+
if (eventProcess && storedProcess && eventProcess === storedProcess) {
|
|
386
|
+
related.push({ event: stored.event, reason: `same_process:${eventProcess}` });
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
// Same category (e.g. multiple auth failures)
|
|
390
|
+
if (event.category === stored.event.category && event.severity !== 'info') {
|
|
391
|
+
related.push({ event: stored.event, reason: `same_category:${event.category}` });
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (related.length === 0) {
|
|
395
|
+
return {
|
|
396
|
+
finding: 'No related events found in the last 10 minutes / 最近 10 分鐘內無相關事件',
|
|
397
|
+
riskContribution: 0,
|
|
398
|
+
needsAdditionalInvestigation: false,
|
|
399
|
+
data: { relatedCount: 0 },
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
// Count unique correlation reasons
|
|
403
|
+
const reasons = new Map();
|
|
404
|
+
for (const r of related) {
|
|
405
|
+
const key = r.reason.split(':')[0];
|
|
406
|
+
reasons.set(key, (reasons.get(key) ?? 0) + 1);
|
|
407
|
+
}
|
|
408
|
+
// Risk scoring: more related events = higher risk
|
|
409
|
+
const count = related.length;
|
|
410
|
+
let risk;
|
|
411
|
+
if (count >= 10)
|
|
412
|
+
risk = 80;
|
|
413
|
+
else if (count >= 5)
|
|
414
|
+
risk = 60;
|
|
415
|
+
else if (count >= 3)
|
|
416
|
+
risk = 40;
|
|
417
|
+
else
|
|
418
|
+
risk = 20;
|
|
419
|
+
// Boost risk if multiple correlation types (e.g. same IP AND same user)
|
|
420
|
+
if (reasons.size >= 2) {
|
|
421
|
+
risk = Math.min(95, risk + 15);
|
|
422
|
+
}
|
|
423
|
+
const reasonSummary = Array.from(reasons.entries())
|
|
424
|
+
.map(([key, cnt]) => `${key}(${cnt})`)
|
|
425
|
+
.join(', ');
|
|
426
|
+
return {
|
|
427
|
+
finding: `Found ${count} related event(s) within 10 min: ${reasonSummary} / ` +
|
|
428
|
+
`在 10 分鐘內找到 ${count} 個相關事件: ${reasonSummary}`,
|
|
429
|
+
riskContribution: risk,
|
|
430
|
+
needsAdditionalInvestigation: count >= 5,
|
|
431
|
+
data: {
|
|
432
|
+
relatedCount: count,
|
|
433
|
+
correlationTypes: Object.fromEntries(reasons),
|
|
434
|
+
sampleEventIds: related.slice(0, 5).map((r) => r.event.id),
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
/** Check process tree / 檢查程序樹 */
|
|
439
|
+
checkProcessTree(event) {
|
|
440
|
+
const processName = event.metadata?.['processName'];
|
|
441
|
+
const parentProcess = event.metadata?.['parentProcess'];
|
|
442
|
+
if (!processName) {
|
|
443
|
+
return {
|
|
444
|
+
finding: 'No process information available / 無可用的程序資訊',
|
|
445
|
+
riskContribution: 0,
|
|
446
|
+
needsAdditionalInvestigation: false,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
// Check if process is in baseline / 檢查程序是否在基線中
|
|
450
|
+
const knownProcess = this.baseline.normalProcesses.some((p) => p.name === processName);
|
|
451
|
+
if (!knownProcess) {
|
|
452
|
+
// Suspicious parent processes / 可疑的父程序
|
|
453
|
+
const suspiciousParents = [
|
|
454
|
+
'cmd.exe',
|
|
455
|
+
'powershell.exe',
|
|
456
|
+
'bash',
|
|
457
|
+
'sh',
|
|
458
|
+
'python',
|
|
459
|
+
'python3',
|
|
460
|
+
'perl',
|
|
461
|
+
'ruby',
|
|
462
|
+
];
|
|
463
|
+
const hasSuspiciousParent = parentProcess
|
|
464
|
+
? suspiciousParents.some((sp) => parentProcess.toLowerCase().includes(sp))
|
|
465
|
+
: false;
|
|
466
|
+
return {
|
|
467
|
+
finding: `New process: ${processName}${hasSuspiciousParent ? ` (suspicious parent: ${parentProcess})` : ''} / ` +
|
|
468
|
+
`新程序: ${processName}`,
|
|
469
|
+
riskContribution: hasSuspiciousParent ? 65 : 40,
|
|
470
|
+
needsAdditionalInvestigation: hasSuspiciousParent,
|
|
471
|
+
data: { processName, parentProcess, known: false, suspiciousParent: hasSuspiciousParent },
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
finding: `Known process: ${processName} / 已知程序: ${processName}`,
|
|
476
|
+
riskContribution: 0,
|
|
477
|
+
needsAdditionalInvestigation: false,
|
|
478
|
+
data: { processName, known: true },
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
/** Check file reputation / 檢查檔案信譽 */
|
|
482
|
+
checkFileReputation(event) {
|
|
483
|
+
const filePath = event.metadata?.['filePath'] ?? event.metadata?.['processPath'];
|
|
484
|
+
if (!filePath) {
|
|
485
|
+
return {
|
|
486
|
+
finding: 'No file path available for reputation check / 無可用的檔案路徑',
|
|
487
|
+
riskContribution: 0,
|
|
488
|
+
needsAdditionalInvestigation: false,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
// Check for suspicious file locations / 檢查可疑檔案位置
|
|
492
|
+
const suspiciousLocations = ['/tmp/', '/dev/shm/', '\\Temp\\', '\\AppData\\Local\\Temp\\'];
|
|
493
|
+
const inSuspiciousLocation = suspiciousLocations.some((loc) => filePath.includes(loc));
|
|
494
|
+
// Check for suspicious extensions / 檢查可疑副檔名
|
|
495
|
+
const suspiciousExtensions = ['.ps1', '.vbs', '.bat', '.cmd', '.scr', '.pif', '.hta'];
|
|
496
|
+
const hasSuspiciousExt = suspiciousExtensions.some((ext) => filePath.toLowerCase().endsWith(ext));
|
|
497
|
+
if (inSuspiciousLocation || hasSuspiciousExt) {
|
|
498
|
+
return {
|
|
499
|
+
finding: `Suspicious file: ${filePath}` +
|
|
500
|
+
`${inSuspiciousLocation ? ' (temp directory)' : ''}` +
|
|
501
|
+
`${hasSuspiciousExt ? ' (suspicious extension)' : ''} / ` +
|
|
502
|
+
`可疑檔案: ${filePath}`,
|
|
503
|
+
riskContribution: inSuspiciousLocation && hasSuspiciousExt ? 70 : 45,
|
|
504
|
+
needsAdditionalInvestigation: true,
|
|
505
|
+
data: {
|
|
506
|
+
filePath,
|
|
507
|
+
suspiciousLocation: inSuspiciousLocation,
|
|
508
|
+
suspiciousExtension: hasSuspiciousExt,
|
|
509
|
+
},
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
finding: `File appears normal: ${filePath} / 檔案看起來正常`,
|
|
514
|
+
riskContribution: 0,
|
|
515
|
+
needsAdditionalInvestigation: false,
|
|
516
|
+
data: { filePath },
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
/** Check network communication pattern / 檢查網路通訊模式 */
|
|
520
|
+
checkNetworkPattern(event) {
|
|
521
|
+
const remoteAddr = event.metadata?.['remoteAddress'] ??
|
|
522
|
+
event.metadata?.['destinationIP'];
|
|
523
|
+
const remotePort = event.metadata?.['remotePort'];
|
|
524
|
+
if (!remoteAddr) {
|
|
525
|
+
return {
|
|
526
|
+
finding: 'No network destination available / 無可用的網路目的地',
|
|
527
|
+
riskContribution: 0,
|
|
528
|
+
needsAdditionalInvestigation: false,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
// Check against baseline connections / 與基線連線比較
|
|
532
|
+
const knownConnection = this.baseline.normalConnections.some((c) => c.remoteAddress === remoteAddr && (!remotePort || c.remotePort === remotePort));
|
|
533
|
+
// Check for suspicious ports / 檢查可疑埠
|
|
534
|
+
const suspiciousPorts = [4444, 5555, 8888, 1337, 31337, 6666, 6667, 9001];
|
|
535
|
+
const isSuspiciousPort = remotePort ? suspiciousPorts.includes(remotePort) : false;
|
|
536
|
+
if (!knownConnection) {
|
|
537
|
+
return {
|
|
538
|
+
finding: `New network connection: ${remoteAddr}:${remotePort ?? 'unknown'}` +
|
|
539
|
+
`${isSuspiciousPort ? ' (suspicious port)' : ''} / ` +
|
|
540
|
+
`新網路連線: ${remoteAddr}:${remotePort ?? 'unknown'}`,
|
|
541
|
+
riskContribution: isSuspiciousPort ? 75 : 30,
|
|
542
|
+
needsAdditionalInvestigation: isSuspiciousPort,
|
|
543
|
+
data: { remoteAddr, remotePort, known: false, suspiciousPort: isSuspiciousPort },
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
return {
|
|
547
|
+
finding: `Known network pattern: ${remoteAddr}:${remotePort ?? 'unknown'} / 已知網路模式`,
|
|
548
|
+
riskContribution: 0,
|
|
549
|
+
needsAdditionalInvestigation: false,
|
|
550
|
+
data: { remoteAddr, remotePort, known: true },
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Build human-readable reasoning from investigation steps
|
|
555
|
+
* 從調查步驟建立人類可讀的推理
|
|
556
|
+
*/
|
|
557
|
+
buildReasoning(steps) {
|
|
558
|
+
const parts = ['Investigation Summary / 調查摘要:'];
|
|
559
|
+
for (const step of steps) {
|
|
560
|
+
if (step.result) {
|
|
561
|
+
parts.push(` [${step.tool}] ${step.result.finding} (risk: ${step.result.riskContribution}%)`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
const totalRisk = steps.reduce((sum, s) => sum + (s.result?.riskContribution ?? 0), 0);
|
|
565
|
+
const avgRisk = steps.length > 0 ? Math.round(totalRisk / steps.length) : 0;
|
|
566
|
+
parts.push(`Average risk contribution: ${avgRisk}% / 平均風險貢獻: ${avgRisk}%`);
|
|
567
|
+
return parts.join('\n');
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/investigation/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License Key Validation and Feature Gating
|
|
3
|
+
* 授權金鑰驗證與功能閘
|
|
4
|
+
*
|
|
5
|
+
* Validates license keys in the format CLAW-TIER-XXXX-XXXX-XXXX,
|
|
6
|
+
* determines tier (Free/Pro/Enterprise), and gates features accordingly.
|
|
7
|
+
* 驗證格式為 CLAW-TIER-XXXX-XXXX-XXXX 的授權金鑰,
|
|
8
|
+
* 判定等級(Free/Pro/Enterprise),並據此控制功能閘。
|
|
9
|
+
*
|
|
10
|
+
* @module @panguard-ai/panguard-guard/license
|
|
11
|
+
*/
|
|
12
|
+
import type { LicenseTier, LicenseInfo } from '../types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Validate a license key and return license information
|
|
15
|
+
* 驗證授權金鑰並回傳授權資訊
|
|
16
|
+
*
|
|
17
|
+
* Key format: CLAW-{TIER}-{XXXX}-{XXXX}-{XXXX}
|
|
18
|
+
* - TIER: FREE, PRO, or ENT
|
|
19
|
+
* - X: Alphanumeric characters
|
|
20
|
+
* - Last 4 characters contain a checksum
|
|
21
|
+
*
|
|
22
|
+
* @param key - The license key to validate / 要驗證的授權金鑰
|
|
23
|
+
* @returns License information / 授權資訊
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateLicense(key: string | undefined): LicenseInfo;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a feature is available for the given license
|
|
28
|
+
* 檢查功能是否適用於給定的授權
|
|
29
|
+
*
|
|
30
|
+
* @param license - License information / 授權資訊
|
|
31
|
+
* @param feature - Feature name to check / 要檢查的功能名稱
|
|
32
|
+
* @returns True if feature is available / 功能可用時回傳 true
|
|
33
|
+
*/
|
|
34
|
+
export declare function hasFeature(license: LicenseInfo, feature: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Get all features for a tier / 取得等級的所有功能
|
|
37
|
+
*/
|
|
38
|
+
export declare function getTierFeatures(tier: LicenseTier): string[];
|
|
39
|
+
/**
|
|
40
|
+
* Generate a license key for testing / 產生測試用授權金鑰
|
|
41
|
+
*
|
|
42
|
+
* @param tier - The tier to generate for / 要產生的等級
|
|
43
|
+
* @returns A valid license key / 有效的授權金鑰
|
|
44
|
+
*/
|
|
45
|
+
export declare function generateTestLicenseKey(tier: LicenseTier): string;
|
|
46
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/license/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAe5D;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAyDpE;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAehE"}
|