defense-mcp-server 0.6.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/CHANGELOG.md +471 -0
- package/LICENSE +21 -0
- package/README.md +242 -0
- package/build/core/auto-installer.d.ts +102 -0
- package/build/core/auto-installer.d.ts.map +1 -0
- package/build/core/auto-installer.js +833 -0
- package/build/core/backup-manager.d.ts +63 -0
- package/build/core/backup-manager.d.ts.map +1 -0
- package/build/core/backup-manager.js +189 -0
- package/build/core/changelog.d.ts +75 -0
- package/build/core/changelog.d.ts.map +1 -0
- package/build/core/changelog.js +123 -0
- package/build/core/command-allowlist.d.ts +129 -0
- package/build/core/command-allowlist.d.ts.map +1 -0
- package/build/core/command-allowlist.js +849 -0
- package/build/core/config.d.ts +79 -0
- package/build/core/config.d.ts.map +1 -0
- package/build/core/config.js +193 -0
- package/build/core/dependency-validator.d.ts +106 -0
- package/build/core/dependency-validator.d.ts.map +1 -0
- package/build/core/dependency-validator.js +405 -0
- package/build/core/distro-adapter.d.ts +177 -0
- package/build/core/distro-adapter.d.ts.map +1 -0
- package/build/core/distro-adapter.js +481 -0
- package/build/core/distro.d.ts +68 -0
- package/build/core/distro.d.ts.map +1 -0
- package/build/core/distro.js +457 -0
- package/build/core/encrypted-state.d.ts +76 -0
- package/build/core/encrypted-state.d.ts.map +1 -0
- package/build/core/encrypted-state.js +209 -0
- package/build/core/executor.d.ts +56 -0
- package/build/core/executor.d.ts.map +1 -0
- package/build/core/executor.js +350 -0
- package/build/core/installer.d.ts +92 -0
- package/build/core/installer.d.ts.map +1 -0
- package/build/core/installer.js +1072 -0
- package/build/core/logger.d.ts +102 -0
- package/build/core/logger.d.ts.map +1 -0
- package/build/core/logger.js +132 -0
- package/build/core/parsers.d.ts +151 -0
- package/build/core/parsers.d.ts.map +1 -0
- package/build/core/parsers.js +479 -0
- package/build/core/policy-engine.d.ts +170 -0
- package/build/core/policy-engine.d.ts.map +1 -0
- package/build/core/policy-engine.js +656 -0
- package/build/core/preflight.d.ts +157 -0
- package/build/core/preflight.d.ts.map +1 -0
- package/build/core/preflight.js +638 -0
- package/build/core/privilege-manager.d.ts +108 -0
- package/build/core/privilege-manager.d.ts.map +1 -0
- package/build/core/privilege-manager.js +363 -0
- package/build/core/rate-limiter.d.ts +67 -0
- package/build/core/rate-limiter.d.ts.map +1 -0
- package/build/core/rate-limiter.js +129 -0
- package/build/core/rollback.d.ts +73 -0
- package/build/core/rollback.d.ts.map +1 -0
- package/build/core/rollback.js +278 -0
- package/build/core/safeguards.d.ts +58 -0
- package/build/core/safeguards.d.ts.map +1 -0
- package/build/core/safeguards.js +448 -0
- package/build/core/sanitizer.d.ts +118 -0
- package/build/core/sanitizer.d.ts.map +1 -0
- package/build/core/sanitizer.js +459 -0
- package/build/core/secure-fs.d.ts +67 -0
- package/build/core/secure-fs.d.ts.map +1 -0
- package/build/core/secure-fs.js +143 -0
- package/build/core/spawn-safe.d.ts +55 -0
- package/build/core/spawn-safe.d.ts.map +1 -0
- package/build/core/spawn-safe.js +146 -0
- package/build/core/sudo-guard.d.ts +145 -0
- package/build/core/sudo-guard.d.ts.map +1 -0
- package/build/core/sudo-guard.js +349 -0
- package/build/core/sudo-session.d.ts +100 -0
- package/build/core/sudo-session.d.ts.map +1 -0
- package/build/core/sudo-session.js +319 -0
- package/build/core/tool-dependencies.d.ts +61 -0
- package/build/core/tool-dependencies.d.ts.map +1 -0
- package/build/core/tool-dependencies.js +571 -0
- package/build/core/tool-registry.d.ts +111 -0
- package/build/core/tool-registry.d.ts.map +1 -0
- package/build/core/tool-registry.js +656 -0
- package/build/core/tool-wrapper.d.ts +73 -0
- package/build/core/tool-wrapper.d.ts.map +1 -0
- package/build/core/tool-wrapper.js +296 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +247 -0
- package/build/tools/access-control.d.ts +9 -0
- package/build/tools/access-control.d.ts.map +1 -0
- package/build/tools/access-control.js +1818 -0
- package/build/tools/api-security.d.ts +12 -0
- package/build/tools/api-security.d.ts.map +1 -0
- package/build/tools/api-security.js +901 -0
- package/build/tools/app-hardening.d.ts +11 -0
- package/build/tools/app-hardening.d.ts.map +1 -0
- package/build/tools/app-hardening.js +768 -0
- package/build/tools/backup.d.ts +8 -0
- package/build/tools/backup.d.ts.map +1 -0
- package/build/tools/backup.js +381 -0
- package/build/tools/cloud-security.d.ts +17 -0
- package/build/tools/cloud-security.d.ts.map +1 -0
- package/build/tools/cloud-security.js +739 -0
- package/build/tools/compliance.d.ts +10 -0
- package/build/tools/compliance.d.ts.map +1 -0
- package/build/tools/compliance.js +1225 -0
- package/build/tools/container-security.d.ts +14 -0
- package/build/tools/container-security.d.ts.map +1 -0
- package/build/tools/container-security.js +788 -0
- package/build/tools/deception.d.ts +13 -0
- package/build/tools/deception.d.ts.map +1 -0
- package/build/tools/deception.js +763 -0
- package/build/tools/dns-security.d.ts +93 -0
- package/build/tools/dns-security.d.ts.map +1 -0
- package/build/tools/dns-security.js +745 -0
- package/build/tools/drift-detection.d.ts +8 -0
- package/build/tools/drift-detection.d.ts.map +1 -0
- package/build/tools/drift-detection.js +326 -0
- package/build/tools/ebpf-security.d.ts +15 -0
- package/build/tools/ebpf-security.d.ts.map +1 -0
- package/build/tools/ebpf-security.js +294 -0
- package/build/tools/encryption.d.ts +9 -0
- package/build/tools/encryption.d.ts.map +1 -0
- package/build/tools/encryption.js +1667 -0
- package/build/tools/firewall.d.ts +9 -0
- package/build/tools/firewall.d.ts.map +1 -0
- package/build/tools/firewall.js +1398 -0
- package/build/tools/hardening.d.ts +10 -0
- package/build/tools/hardening.d.ts.map +1 -0
- package/build/tools/hardening.js +2654 -0
- package/build/tools/ids.d.ts +9 -0
- package/build/tools/ids.d.ts.map +1 -0
- package/build/tools/ids.js +624 -0
- package/build/tools/incident-response.d.ts +10 -0
- package/build/tools/incident-response.d.ts.map +1 -0
- package/build/tools/incident-response.js +1180 -0
- package/build/tools/logging.d.ts +12 -0
- package/build/tools/logging.d.ts.map +1 -0
- package/build/tools/logging.js +454 -0
- package/build/tools/malware.d.ts +10 -0
- package/build/tools/malware.d.ts.map +1 -0
- package/build/tools/malware.js +532 -0
- package/build/tools/meta.d.ts +11 -0
- package/build/tools/meta.d.ts.map +1 -0
- package/build/tools/meta.js +2278 -0
- package/build/tools/network-defense.d.ts +12 -0
- package/build/tools/network-defense.d.ts.map +1 -0
- package/build/tools/network-defense.js +760 -0
- package/build/tools/patch-management.d.ts +3 -0
- package/build/tools/patch-management.d.ts.map +1 -0
- package/build/tools/patch-management.js +708 -0
- package/build/tools/process-security.d.ts +12 -0
- package/build/tools/process-security.d.ts.map +1 -0
- package/build/tools/process-security.js +784 -0
- package/build/tools/reporting.d.ts +11 -0
- package/build/tools/reporting.d.ts.map +1 -0
- package/build/tools/reporting.js +559 -0
- package/build/tools/secrets.d.ts +9 -0
- package/build/tools/secrets.d.ts.map +1 -0
- package/build/tools/secrets.js +596 -0
- package/build/tools/siem-integration.d.ts +18 -0
- package/build/tools/siem-integration.d.ts.map +1 -0
- package/build/tools/siem-integration.js +754 -0
- package/build/tools/sudo-management.d.ts +18 -0
- package/build/tools/sudo-management.d.ts.map +1 -0
- package/build/tools/sudo-management.js +737 -0
- package/build/tools/supply-chain-security.d.ts +8 -0
- package/build/tools/supply-chain-security.d.ts.map +1 -0
- package/build/tools/supply-chain-security.js +256 -0
- package/build/tools/threat-intel.d.ts +22 -0
- package/build/tools/threat-intel.d.ts.map +1 -0
- package/build/tools/threat-intel.js +749 -0
- package/build/tools/vulnerability-management.d.ts +11 -0
- package/build/tools/vulnerability-management.d.ts.map +1 -0
- package/build/tools/vulnerability-management.js +667 -0
- package/build/tools/waf.d.ts +12 -0
- package/build/tools/waf.d.ts.map +1 -0
- package/build/tools/waf.js +843 -0
- package/build/tools/wireless-security.d.ts +19 -0
- package/build/tools/wireless-security.d.ts.map +1 -0
- package/build/tools/wireless-security.js +826 -0
- package/build/tools/zero-trust-network.d.ts +8 -0
- package/build/tools/zero-trust-network.d.ts.map +1 -0
- package/build/tools/zero-trust-network.js +367 -0
- package/docs/SAFEGUARDS.md +518 -0
- package/docs/TOOLS-REFERENCE.md +665 -0
- package/package.json +87 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging and audit tools for Kali Defense MCP Server.
|
|
3
|
+
*
|
|
4
|
+
* Registers 4 tools:
|
|
5
|
+
* log_auditd (actions: rules, search, report, cis_rules)
|
|
6
|
+
* log_journalctl_query (kept as-is)
|
|
7
|
+
* log_fail2ban (actions: status, ban, unban, reload, audit)
|
|
8
|
+
* log_system (actions: analyze, rotation_audit)
|
|
9
|
+
*/
|
|
10
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
+
export declare function registerLoggingTools(server: McpServer): void;
|
|
12
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/tools/logging.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAepE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsc5D"}
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging and audit tools for Kali Defense MCP Server.
|
|
3
|
+
*
|
|
4
|
+
* Registers 4 tools:
|
|
5
|
+
* log_auditd (actions: rules, search, report, cis_rules)
|
|
6
|
+
* log_journalctl_query (kept as-is)
|
|
7
|
+
* log_fail2ban (actions: status, ban, unban, reload, audit)
|
|
8
|
+
* log_system (actions: analyze, rotation_audit)
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { executeCommand } from "../core/executor.js";
|
|
12
|
+
import { getConfig, getToolTimeout } from "../core/config.js";
|
|
13
|
+
import { createTextContent, createErrorContent, parseAuditdOutput, parseFail2banOutput, formatToolOutput } from "../core/parsers.js";
|
|
14
|
+
import { logChange, createChangeEntry } from "../core/changelog.js";
|
|
15
|
+
import { sanitizeArgs, validateAuditdKey, validateTarget, validateToolPath } from "../core/sanitizer.js";
|
|
16
|
+
import { getDistroAdapter } from "../core/distro-adapter.js";
|
|
17
|
+
import { existsSync } from "node:fs";
|
|
18
|
+
// ── TOOL-015 remediation: allowed directories for log file paths ────────────
|
|
19
|
+
const ALLOWED_LOG_DIRS = ["/var/log", "/var/spool", "/tmp", "/var/lib", "/run/log"];
|
|
20
|
+
// ── Registration entry point ───────────────────────────────────────────────
|
|
21
|
+
export function registerLoggingTools(server) {
|
|
22
|
+
// ── 1. log_auditd (merged: rules, search, report, cis_rules) ─────────
|
|
23
|
+
server.tool("log_auditd", "Auditd management: manage rules, search logs, generate reports, or check CIS benchmark audit rules.", {
|
|
24
|
+
action: z.enum(["rules", "search", "report", "cis_rules"]).describe("Action: rules=manage auditd rules, search=search audit logs, report=generate audit report, cis_rules=check/generate CIS rules"),
|
|
25
|
+
// rules params
|
|
26
|
+
rules_action: z.enum(["list", "add", "delete"]).optional().describe("Rule action (rules action)"),
|
|
27
|
+
rule: z.string().min(1).optional().describe("Audit rule string (rules add/delete)"),
|
|
28
|
+
// search params
|
|
29
|
+
key: z.string().min(1).regex(/^[a-zA-Z0-9._-]+$/).optional().describe("Audit key to search for (search action)"),
|
|
30
|
+
syscall: z.string().min(1).regex(/^[a-zA-Z0-9_]+$/).optional().describe("System call name to filter (search action)"),
|
|
31
|
+
uid: z.string().min(1).regex(/^[0-9]+$/).optional().describe("User ID to filter (search action)"),
|
|
32
|
+
start: z.string().min(1).optional().describe("Start time e.g. 'today', '1 hour ago' (search/report action)"),
|
|
33
|
+
end: z.string().min(1).optional().describe("End time (search action)"),
|
|
34
|
+
success: z.enum(["yes", "no"]).optional().describe("Filter by success/failure (search action)"),
|
|
35
|
+
limit: z.number().optional().default(50).describe("Maximum number of lines to return (search action)"),
|
|
36
|
+
// report params
|
|
37
|
+
report_type: z.enum(["summary", "auth", "login", "account", "event", "file", "exec"]).optional().default("summary").describe("Type of audit report (report action)"),
|
|
38
|
+
// cis_rules params
|
|
39
|
+
cis_action: z.enum(["check", "generate"]).optional().default("check").describe("check or generate CIS rules (cis_rules action)"),
|
|
40
|
+
// shared
|
|
41
|
+
dry_run: z.boolean().optional().describe("Preview the command without executing"),
|
|
42
|
+
}, async (params) => {
|
|
43
|
+
const { action } = params;
|
|
44
|
+
switch (action) {
|
|
45
|
+
case "rules": {
|
|
46
|
+
const { rules_action, rule, dry_run } = params;
|
|
47
|
+
try {
|
|
48
|
+
if (!rules_action) {
|
|
49
|
+
return { content: [createErrorContent("rules_action is required for rules action (list/add/delete)")], isError: true };
|
|
50
|
+
}
|
|
51
|
+
if (rules_action === "list") {
|
|
52
|
+
const result = await executeCommand({ command: "sudo", args: ["auditctl", "-l"], toolName: "log_auditd", timeout: getToolTimeout("auditd") });
|
|
53
|
+
if (result.exitCode !== 0)
|
|
54
|
+
return { content: [createErrorContent(`auditctl list failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
55
|
+
return { content: [createTextContent(`Current auditd rules:\n${result.stdout}`)] };
|
|
56
|
+
}
|
|
57
|
+
if (!rule)
|
|
58
|
+
return { content: [createErrorContent(`A rule string is required for '${rules_action}' action`)], isError: true };
|
|
59
|
+
const ruleTokens = rule.trim().split(/\s+/);
|
|
60
|
+
sanitizeArgs(ruleTokens);
|
|
61
|
+
let args;
|
|
62
|
+
if (rules_action === "add") {
|
|
63
|
+
if (ruleTokens[0] === "-w")
|
|
64
|
+
args = ["auditctl", ...ruleTokens];
|
|
65
|
+
else if (ruleTokens[0] === "-a")
|
|
66
|
+
args = ["auditctl", ...ruleTokens];
|
|
67
|
+
else
|
|
68
|
+
args = ["auditctl", "-a", ...ruleTokens];
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
if (ruleTokens[0] === "-w")
|
|
72
|
+
args = ["auditctl", "-W", ...ruleTokens.slice(1)];
|
|
73
|
+
else if (ruleTokens[0] === "-a")
|
|
74
|
+
args = ["auditctl", "-d", ...ruleTokens.slice(1)];
|
|
75
|
+
else
|
|
76
|
+
args = ["auditctl", "-d", ...ruleTokens];
|
|
77
|
+
}
|
|
78
|
+
const fullCmd = `sudo ${args.join(" ")}`;
|
|
79
|
+
if (dry_run ?? getConfig().dryRun) {
|
|
80
|
+
logChange(createChangeEntry({ tool: "log_auditd", action: `[DRY-RUN] ${rules_action} auditd rule`, target: rule, after: fullCmd, dryRun: true, success: true }));
|
|
81
|
+
return { content: [createTextContent(`[DRY-RUN] Would execute:\n ${fullCmd}`)] };
|
|
82
|
+
}
|
|
83
|
+
const result = await executeCommand({ command: "sudo", args, toolName: "log_auditd", timeout: getToolTimeout("auditd") });
|
|
84
|
+
const ok = result.exitCode === 0;
|
|
85
|
+
logChange(createChangeEntry({ tool: "log_auditd", action: `${rules_action} auditd rule`, target: rule, after: fullCmd, dryRun: false, success: ok, error: ok ? undefined : result.stderr }));
|
|
86
|
+
if (!ok)
|
|
87
|
+
return { content: [createErrorContent(`auditctl ${rules_action} failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
88
|
+
return { content: [createTextContent(`Auditd rule ${rules_action === "add" ? "added" : "deleted"} successfully.\nCommand: ${fullCmd}`)] };
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
return { content: [createErrorContent(err instanceof Error ? err.message : String(err))], isError: true };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
case "search": {
|
|
95
|
+
const { key, syscall, uid, start, end, success, limit: maxLines } = params;
|
|
96
|
+
try {
|
|
97
|
+
const args = ["ausearch"];
|
|
98
|
+
if (key) {
|
|
99
|
+
validateAuditdKey(key);
|
|
100
|
+
args.push("-k", key);
|
|
101
|
+
}
|
|
102
|
+
if (syscall) {
|
|
103
|
+
sanitizeArgs([syscall]);
|
|
104
|
+
args.push("-sc", syscall);
|
|
105
|
+
}
|
|
106
|
+
if (uid) {
|
|
107
|
+
sanitizeArgs([uid]);
|
|
108
|
+
args.push("-ui", uid);
|
|
109
|
+
}
|
|
110
|
+
if (start) {
|
|
111
|
+
sanitizeArgs([start]);
|
|
112
|
+
args.push("--start", start);
|
|
113
|
+
}
|
|
114
|
+
if (end) {
|
|
115
|
+
sanitizeArgs([end]);
|
|
116
|
+
args.push("--end", end);
|
|
117
|
+
}
|
|
118
|
+
if (success)
|
|
119
|
+
args.push("--success", success);
|
|
120
|
+
args.push("--interpret");
|
|
121
|
+
sanitizeArgs(args);
|
|
122
|
+
const result = await executeCommand({ command: "sudo", args, toolName: "log_auditd", timeout: getToolTimeout("auditd") });
|
|
123
|
+
if (result.exitCode !== 0 && !result.stderr.includes("no matches")) {
|
|
124
|
+
return { content: [createErrorContent(`ausearch failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
125
|
+
}
|
|
126
|
+
if (result.exitCode !== 0 && result.stderr.includes("no matches")) {
|
|
127
|
+
return { content: [createTextContent("No matching audit records found.")] };
|
|
128
|
+
}
|
|
129
|
+
const lines = result.stdout.split("\n");
|
|
130
|
+
const truncated = lines.slice(-maxLines).join("\n");
|
|
131
|
+
const parsed = parseAuditdOutput(result.stdout);
|
|
132
|
+
return { content: [formatToolOutput({ totalEntries: parsed.length, displayedLines: Math.min(lines.length, maxLines), entries: parsed.slice(-maxLines), raw: truncated })] };
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
return { content: [createErrorContent(err instanceof Error ? err.message : String(err))], isError: true };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
case "report": {
|
|
139
|
+
const { report_type, start } = params;
|
|
140
|
+
try {
|
|
141
|
+
const args = ["aureport"];
|
|
142
|
+
const reportFlags = { summary: "--summary", auth: "--auth", login: "--login", account: "--account-modifications", event: "--event", file: "--file", exec: "--executable" };
|
|
143
|
+
args.push(reportFlags[report_type] ?? "--summary");
|
|
144
|
+
if (start) {
|
|
145
|
+
sanitizeArgs([start]);
|
|
146
|
+
args.push("--start", start);
|
|
147
|
+
}
|
|
148
|
+
sanitizeArgs(args);
|
|
149
|
+
const result = await executeCommand({ command: "sudo", args, toolName: "log_auditd", timeout: getToolTimeout("auditd") });
|
|
150
|
+
if (result.exitCode !== 0)
|
|
151
|
+
return { content: [createErrorContent(`aureport failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
152
|
+
return { content: [createTextContent(`Audit Report (${report_type}):\n${"=".repeat(50)}\n${result.stdout}`)] };
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
return { content: [createErrorContent(err instanceof Error ? err.message : String(err))], isError: true };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
case "cis_rules": {
|
|
159
|
+
const { cis_action } = params;
|
|
160
|
+
try {
|
|
161
|
+
const CIS_RULES = [
|
|
162
|
+
{ rule: "-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change", description: "Record time changes (64-bit)" },
|
|
163
|
+
{ rule: "-a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -k time-change", description: "Record time changes (32-bit)" },
|
|
164
|
+
{ rule: "-w /etc/localtime -p wa -k time-change", description: "Record timezone changes" },
|
|
165
|
+
{ rule: "-w /etc/group -p wa -k identity", description: "Record group modifications" },
|
|
166
|
+
{ rule: "-w /etc/passwd -p wa -k identity", description: "Record user modifications" },
|
|
167
|
+
{ rule: "-w /etc/gshadow -p wa -k identity", description: "Record gshadow changes" },
|
|
168
|
+
{ rule: "-w /etc/shadow -p wa -k identity", description: "Record shadow changes" },
|
|
169
|
+
{ rule: "-w /etc/security/opasswd -p wa -k identity", description: "Record opasswd changes" },
|
|
170
|
+
{ rule: "-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale", description: "Record hostname changes" },
|
|
171
|
+
{ rule: "-w /etc/issue -p wa -k system-locale", description: "Record issue changes" },
|
|
172
|
+
{ rule: "-w /etc/issue.net -p wa -k system-locale", description: "Record issue.net changes" },
|
|
173
|
+
{ rule: "-w /etc/hosts -p wa -k system-locale", description: "Record hosts changes" },
|
|
174
|
+
{ rule: "-w /etc/apparmor/ -p wa -k MAC-policy", description: "Record AppArmor changes" },
|
|
175
|
+
{ rule: "-w /etc/apparmor.d/ -p wa -k MAC-policy", description: "Record AppArmor profile changes" },
|
|
176
|
+
{ rule: "-w /var/log/faillog -p wa -k logins", description: "Record failed logins" },
|
|
177
|
+
{ rule: "-w /var/log/lastlog -p wa -k logins", description: "Record last logins" },
|
|
178
|
+
{ rule: "-w /var/log/tallylog -p wa -k logins", description: "Record tally logins" },
|
|
179
|
+
{ rule: "-w /var/run/utmp -p wa -k session", description: "Record utmp session changes" },
|
|
180
|
+
{ rule: "-w /var/log/wtmp -p wa -k logins", description: "Record wtmp login changes" },
|
|
181
|
+
{ rule: "-w /var/log/btmp -p wa -k logins", description: "Record btmp failed logins" },
|
|
182
|
+
{ rule: "-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod", description: "Record permission changes" },
|
|
183
|
+
{ rule: "-a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts", description: "Record mount operations" },
|
|
184
|
+
{ rule: "-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete", description: "Record file deletions" },
|
|
185
|
+
{ rule: "-w /etc/sudoers -p wa -k scope", description: "Record sudoers changes" },
|
|
186
|
+
{ rule: "-w /etc/sudoers.d/ -p wa -k scope", description: "Record sudoers.d changes" },
|
|
187
|
+
{ rule: "-w /var/log/sudo.log -p wa -k actions", description: "Record sudo log changes" },
|
|
188
|
+
{ rule: "-a always,exit -F arch=b64 -S init_module -S delete_module -k modules", description: "Record kernel module operations" },
|
|
189
|
+
];
|
|
190
|
+
if (cis_action === "generate") {
|
|
191
|
+
const rulesText = CIS_RULES.map(r => `# ${r.description}\n${r.rule}`).join("\n\n");
|
|
192
|
+
return { content: [createTextContent(`# CIS Benchmark Required Audit Rules\n# Save to /etc/audit/rules.d/99-cis.rules\n# Then run: sudo augenrules --load\n\n${rulesText}\n\n# Make immutable (must be last rule)\n-e 2\n`)] };
|
|
193
|
+
}
|
|
194
|
+
const currentRules = await executeCommand({ command: "sudo", args: ["auditctl", "-l"], timeout: 10000, toolName: "log_auditd" });
|
|
195
|
+
const existing = currentRules.stdout || "";
|
|
196
|
+
const results = CIS_RULES.map(r => {
|
|
197
|
+
const keyMatch = r.rule.match(/-k\s+(\S+)/);
|
|
198
|
+
const key = keyMatch ? keyMatch[1] : "";
|
|
199
|
+
const found = existing.includes(key) || r.rule.split(" ").every(part => part.startsWith("-") ? existing.includes(part) : true);
|
|
200
|
+
return { description: r.description, rule: r.rule, present: found };
|
|
201
|
+
});
|
|
202
|
+
const present = results.filter(r => r.present).length;
|
|
203
|
+
return { content: [createTextContent(JSON.stringify({ summary: { totalRequired: CIS_RULES.length, present, missing: CIS_RULES.length - present, compliancePercent: Math.round((present / CIS_RULES.length) * 100) }, results }, null, 2))] };
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
return { content: [createErrorContent(error instanceof Error ? error.message : String(error))], isError: true };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
default:
|
|
210
|
+
return { content: [createErrorContent(`Unknown action: ${action}`)], isError: true };
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
// ── 2. log_journalctl_query (kept as-is) ──────────────────────────────
|
|
214
|
+
server.tool("log_journalctl_query", "Query systemd journal for log entries with flexible filtering", {
|
|
215
|
+
unit: z.string().optional().describe("Systemd unit name to filter"),
|
|
216
|
+
priority: z.enum(["emerg", "alert", "crit", "err", "warning", "notice", "info", "debug"]).optional().describe("Minimum priority level"),
|
|
217
|
+
since: z.string().optional().describe("Start time, e.g. '1 hour ago', 'today', '2024-01-01'"),
|
|
218
|
+
until: z.string().optional().describe("End time"),
|
|
219
|
+
grep: z.string().optional().describe("Pattern to search for in log messages"),
|
|
220
|
+
lines: z.number().optional().default(100).describe("Number of log lines to return"),
|
|
221
|
+
output_format: z.enum(["short", "json", "cat", "verbose"]).optional().default("short").describe("Output format for journal entries"),
|
|
222
|
+
}, async ({ unit, priority, since, until, grep, lines, output_format }) => {
|
|
223
|
+
try {
|
|
224
|
+
const args = ["journalctl"];
|
|
225
|
+
if (unit) {
|
|
226
|
+
sanitizeArgs([unit]);
|
|
227
|
+
args.push("--unit", unit);
|
|
228
|
+
}
|
|
229
|
+
if (priority)
|
|
230
|
+
args.push("-p", priority);
|
|
231
|
+
if (since) {
|
|
232
|
+
sanitizeArgs([since]);
|
|
233
|
+
args.push("--since", since);
|
|
234
|
+
}
|
|
235
|
+
if (until) {
|
|
236
|
+
sanitizeArgs([until]);
|
|
237
|
+
args.push("--until", until);
|
|
238
|
+
}
|
|
239
|
+
if (grep) {
|
|
240
|
+
sanitizeArgs([grep]);
|
|
241
|
+
args.push("-g", grep);
|
|
242
|
+
}
|
|
243
|
+
args.push("-n", String(lines));
|
|
244
|
+
args.push("-o", output_format);
|
|
245
|
+
args.push("--no-pager");
|
|
246
|
+
sanitizeArgs(args);
|
|
247
|
+
const result = await executeCommand({ command: "journalctl", args: args.slice(1), toolName: "log_journalctl_query", timeout: getToolTimeout("auditd") });
|
|
248
|
+
if (result.exitCode !== 0)
|
|
249
|
+
return { content: [createErrorContent(`journalctl query failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
250
|
+
return { content: [createTextContent(result.stdout)] };
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
return { content: [createErrorContent(err instanceof Error ? err.message : String(err))], isError: true };
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
// ── 3. log_fail2ban (merged: status, ban, unban, reload, audit) ───────
|
|
257
|
+
server.tool("log_fail2ban", "Fail2ban management: check status, ban/unban IPs, reload config, or audit jail configurations.", {
|
|
258
|
+
action: z.enum(["status", "ban", "unban", "reload", "audit"]).describe("Action: status, ban, unban, reload, audit"),
|
|
259
|
+
// status/ban/unban params
|
|
260
|
+
jail: z.string().min(1).regex(/^[a-zA-Z0-9._-]+$/).optional().describe("Jail name (status: optional, ban/unban: required)"),
|
|
261
|
+
ip: z.string().min(1).optional().describe("IP address to ban or unban (ban/unban action)"),
|
|
262
|
+
// shared
|
|
263
|
+
dry_run: z.boolean().optional().describe("Preview without executing"),
|
|
264
|
+
}, async (params) => {
|
|
265
|
+
const { action } = params;
|
|
266
|
+
switch (action) {
|
|
267
|
+
case "status": {
|
|
268
|
+
const { jail } = params;
|
|
269
|
+
try {
|
|
270
|
+
const args = ["fail2ban-client", "status"];
|
|
271
|
+
if (jail) {
|
|
272
|
+
sanitizeArgs([jail]);
|
|
273
|
+
args.push(jail);
|
|
274
|
+
}
|
|
275
|
+
const result = await executeCommand({ command: "sudo", args, toolName: "log_fail2ban", timeout: getToolTimeout("auditd") });
|
|
276
|
+
if (result.exitCode !== 0)
|
|
277
|
+
return { content: [createErrorContent(`fail2ban status failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
278
|
+
if (jail) {
|
|
279
|
+
const parsed = parseFail2banOutput(result.stdout);
|
|
280
|
+
return { content: [formatToolOutput({ jail, parsed, raw: result.stdout })] };
|
|
281
|
+
}
|
|
282
|
+
return { content: [createTextContent(result.stdout)] };
|
|
283
|
+
}
|
|
284
|
+
catch (err) {
|
|
285
|
+
return { content: [createErrorContent(err instanceof Error ? err.message : String(err))], isError: true };
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
case "ban":
|
|
289
|
+
case "unban": {
|
|
290
|
+
const { jail, ip, dry_run } = params;
|
|
291
|
+
try {
|
|
292
|
+
if (!jail)
|
|
293
|
+
return { content: [createErrorContent(`Jail name is required for '${action}' action`)], isError: true };
|
|
294
|
+
if (!ip)
|
|
295
|
+
return { content: [createErrorContent(`IP address is required for '${action}' action`)], isError: true };
|
|
296
|
+
sanitizeArgs([jail]);
|
|
297
|
+
validateTarget(ip);
|
|
298
|
+
const subcommand = action === "ban" ? "banip" : "unbanip";
|
|
299
|
+
const args = ["fail2ban-client", "set", jail, subcommand, ip];
|
|
300
|
+
const fullCmd = `sudo ${args.join(" ")}`;
|
|
301
|
+
const rollbackCmd = action === "ban" ? `sudo fail2ban-client set ${jail} unbanip ${ip}` : `sudo fail2ban-client set ${jail} banip ${ip}`;
|
|
302
|
+
if (dry_run ?? getConfig().dryRun) {
|
|
303
|
+
logChange(createChangeEntry({ tool: "log_fail2ban", action: `[DRY-RUN] ${action} IP in fail2ban`, target: `${jail}/${ip}`, after: fullCmd, dryRun: true, success: true, rollbackCommand: rollbackCmd }));
|
|
304
|
+
return { content: [createTextContent(`[DRY-RUN] Would execute:\n ${fullCmd}\n\nRollback command:\n ${rollbackCmd}`)] };
|
|
305
|
+
}
|
|
306
|
+
const result = await executeCommand({ command: "sudo", args, toolName: "log_fail2ban", timeout: getToolTimeout("auditd") });
|
|
307
|
+
const ok = result.exitCode === 0;
|
|
308
|
+
logChange(createChangeEntry({ tool: "log_fail2ban", action: `${action} IP in fail2ban`, target: `${jail}/${ip}`, after: fullCmd, dryRun: false, success: ok, error: ok ? undefined : result.stderr, rollbackCommand: rollbackCmd }));
|
|
309
|
+
if (!ok)
|
|
310
|
+
return { content: [createErrorContent(`fail2ban ${action} failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
311
|
+
return { content: [createTextContent(`IP ${ip} ${action === "ban" ? "banned" : "unbanned"} in jail ${jail}.\nRollback: ${rollbackCmd}`)] };
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
return { content: [createErrorContent(err instanceof Error ? err.message : String(err))], isError: true };
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
case "reload": {
|
|
318
|
+
const { dry_run } = params;
|
|
319
|
+
try {
|
|
320
|
+
const fullCmd = "sudo fail2ban-client reload";
|
|
321
|
+
if (dry_run ?? getConfig().dryRun) {
|
|
322
|
+
logChange(createChangeEntry({ tool: "log_fail2ban", action: "[DRY-RUN] Reload fail2ban", target: "fail2ban", after: fullCmd, dryRun: true, success: true }));
|
|
323
|
+
return { content: [createTextContent(`[DRY-RUN] Would execute:\n ${fullCmd}`)] };
|
|
324
|
+
}
|
|
325
|
+
const result = await executeCommand({ command: "sudo", args: ["fail2ban-client", "reload"], toolName: "log_fail2ban", timeout: getToolTimeout("auditd") });
|
|
326
|
+
const ok = result.exitCode === 0;
|
|
327
|
+
logChange(createChangeEntry({ tool: "log_fail2ban", action: "Reload fail2ban", target: "fail2ban", after: fullCmd, dryRun: false, success: ok, error: ok ? undefined : result.stderr }));
|
|
328
|
+
if (!ok)
|
|
329
|
+
return { content: [createErrorContent(`fail2ban reload failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
330
|
+
return { content: [createTextContent("fail2ban reloaded successfully.")] };
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
return { content: [createErrorContent(err instanceof Error ? err.message : String(err))], isError: true };
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
case "audit": {
|
|
337
|
+
try {
|
|
338
|
+
const statusResult = await executeCommand({ command: "sudo", args: ["fail2ban-client", "status"], timeout: 10000, toolName: "log_fail2ban" });
|
|
339
|
+
if (statusResult.exitCode !== 0) {
|
|
340
|
+
return { content: [createTextContent(JSON.stringify({ installed: false, recommendation: "Install fail2ban: sudo apt install fail2ban && sudo systemctl enable fail2ban" }, null, 2))] };
|
|
341
|
+
}
|
|
342
|
+
const jailLine = statusResult.stdout.match(/Jail list:\s*(.*)/);
|
|
343
|
+
const jails = jailLine ? jailLine[1].split(",").map(j => j.trim()).filter(Boolean) : [];
|
|
344
|
+
const findings = [];
|
|
345
|
+
for (const jail of jails) {
|
|
346
|
+
const jailResult = await executeCommand({ command: "sudo", args: ["fail2ban-client", "get", jail, "bantime"], timeout: 5000, toolName: "log_fail2ban" });
|
|
347
|
+
const bantime = parseInt(jailResult.stdout.trim()) || 0;
|
|
348
|
+
findings.push({ jail, setting: "bantime", value: `${bantime}s`, status: bantime >= 600 ? "PASS" : "WARN", recommendation: bantime < 600 ? "Increase bantime to at least 600s (10 min)" : "OK" });
|
|
349
|
+
const maxRetryResult = await executeCommand({ command: "sudo", args: ["fail2ban-client", "get", jail, "maxretry"], timeout: 5000, toolName: "log_fail2ban" });
|
|
350
|
+
const maxRetry = parseInt(maxRetryResult.stdout.trim()) || 0;
|
|
351
|
+
findings.push({ jail, setting: "maxretry", value: String(maxRetry), status: maxRetry <= 5 ? "PASS" : "WARN", recommendation: maxRetry > 5 ? "Reduce maxretry to 5 or less" : "OK" });
|
|
352
|
+
const findtimeResult = await executeCommand({ command: "sudo", args: ["fail2ban-client", "get", jail, "findtime"], timeout: 5000, toolName: "log_fail2ban" });
|
|
353
|
+
const findtime = parseInt(findtimeResult.stdout.trim()) || 0;
|
|
354
|
+
findings.push({ jail, setting: "findtime", value: `${findtime}s`, status: findtime >= 300 ? "PASS" : "WARN", recommendation: findtime < 300 ? "Increase findtime to at least 300s" : "OK" });
|
|
355
|
+
}
|
|
356
|
+
const recommendedJails = ["sshd", "apache-auth", "nginx-http-auth", "postfix"];
|
|
357
|
+
const missingJails = recommendedJails.filter(j => !jails.includes(j));
|
|
358
|
+
return { content: [createTextContent(JSON.stringify({ installed: true, activeJails: jails.length, jails, missingRecommended: missingJails, findings, summary: { pass: findings.filter(f => f.status === "PASS").length, warn: findings.filter(f => f.status === "WARN").length } }, null, 2))] };
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
return { content: [createErrorContent(error instanceof Error ? error.message : String(error))], isError: true };
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
default:
|
|
365
|
+
return { content: [createErrorContent(`Unknown action: ${action}`)], isError: true };
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
// ── 4. log_system (merged: syslog_analyze + rotation_audit) ───────────
|
|
369
|
+
server.tool("log_system", "System log analysis: analyze syslog for security events or audit log rotation configuration.", {
|
|
370
|
+
action: z.enum(["analyze", "rotation_audit"]).describe("Action: analyze=analyze syslog, rotation_audit=audit logrotate/journald"),
|
|
371
|
+
// analyze params
|
|
372
|
+
log_file: z.string().optional().describe("Path to the log file (analyze action)"),
|
|
373
|
+
pattern: z.enum(["auth_failures", "ssh_brute", "privilege_escalation", "service_changes", "all"]).optional().default("all").describe("Security event pattern (analyze action)"),
|
|
374
|
+
lines: z.number().optional().default(500).describe("Maximum number of matching lines (analyze action)"),
|
|
375
|
+
}, async (params) => {
|
|
376
|
+
const { action } = params;
|
|
377
|
+
switch (action) {
|
|
378
|
+
case "analyze": {
|
|
379
|
+
const { log_file, pattern, lines: maxLines } = params;
|
|
380
|
+
try {
|
|
381
|
+
let effectiveLogFile;
|
|
382
|
+
if (log_file) {
|
|
383
|
+
// TOOL-015: Validate user-supplied log file path against traversal
|
|
384
|
+
effectiveLogFile = validateToolPath(log_file, ALLOWED_LOG_DIRS, "Log file path");
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
const adapterPath = (await getDistroAdapter()).paths.syslog;
|
|
388
|
+
const candidates = [adapterPath];
|
|
389
|
+
if (adapterPath !== "/var/log/messages")
|
|
390
|
+
candidates.push("/var/log/messages");
|
|
391
|
+
if (adapterPath !== "/var/log/syslog")
|
|
392
|
+
candidates.push("/var/log/syslog");
|
|
393
|
+
const found = candidates.find((p) => existsSync(p));
|
|
394
|
+
if (!found) {
|
|
395
|
+
return { content: [createErrorContent(`No syslog file found (tried: ${candidates.join(", ")}). This system may use journald exclusively — use log_journalctl_query instead.`)], isError: true };
|
|
396
|
+
}
|
|
397
|
+
effectiveLogFile = found;
|
|
398
|
+
}
|
|
399
|
+
const patterns = {
|
|
400
|
+
auth_failures: "authentication failure|Failed password|pam_unix.*failed",
|
|
401
|
+
ssh_brute: "Failed password for|Invalid user|Connection closed by.*\\[preauth\\]",
|
|
402
|
+
privilege_escalation: "sudo:|su\\[|su:|pkexec",
|
|
403
|
+
service_changes: "systemd\\[.*Started|systemd\\[.*Stopped|systemd\\[.*Reloading",
|
|
404
|
+
};
|
|
405
|
+
const grepPattern = pattern === "all" ? Object.values(patterns).join("|") : (patterns[pattern] ?? patterns.auth_failures);
|
|
406
|
+
const args = ["-E", grepPattern, effectiveLogFile, "-m", String(maxLines)];
|
|
407
|
+
const result = await executeCommand({ command: "grep", args, toolName: "log_system", timeout: getToolTimeout("auditd") });
|
|
408
|
+
if (result.exitCode === 1 && result.stdout.trim() === "") {
|
|
409
|
+
return { content: [createTextContent(`No matching security events found in ${effectiveLogFile} for pattern '${pattern}'.`)] };
|
|
410
|
+
}
|
|
411
|
+
if (result.exitCode !== 0 && result.exitCode !== 1) {
|
|
412
|
+
return { content: [createErrorContent(`Log analysis failed (exit ${result.exitCode}): ${result.stderr}`)], isError: true };
|
|
413
|
+
}
|
|
414
|
+
const matchedLines = result.stdout.trim().split("\n").filter((l) => l.length > 0);
|
|
415
|
+
return { content: [formatToolOutput({ logFile: log_file, pattern, matchCount: matchedLines.length, maxLines, matches: result.stdout })] };
|
|
416
|
+
}
|
|
417
|
+
catch (err) {
|
|
418
|
+
return { content: [createErrorContent(err instanceof Error ? err.message : String(err))], isError: true };
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
case "rotation_audit": {
|
|
422
|
+
try {
|
|
423
|
+
const findings = [];
|
|
424
|
+
const lrResult = await executeCommand({ command: "cat", args: ["/etc/logrotate.conf"], timeout: 5000, toolName: "log_system" });
|
|
425
|
+
findings.push({ check: "logrotate_config", status: lrResult.exitCode === 0 ? "PASS" : "FAIL", value: lrResult.exitCode === 0 ? "present" : "missing", description: "logrotate main configuration" });
|
|
426
|
+
if (lrResult.exitCode === 0) {
|
|
427
|
+
const hasCompress = lrResult.stdout.includes("compress");
|
|
428
|
+
findings.push({ check: "logrotate_compress", status: hasCompress ? "PASS" : "WARN", value: hasCompress ? "enabled" : "not set", description: "Log compression enabled" });
|
|
429
|
+
const rotateMatch = lrResult.stdout.match(/rotate\s+(\d+)/);
|
|
430
|
+
if (rotateMatch) {
|
|
431
|
+
findings.push({ check: "logrotate_retention", status: parseInt(rotateMatch[1]) >= 4 ? "PASS" : "WARN", value: `${rotateMatch[1]} rotations`, description: "Log retention count" });
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
const journaldResult = await executeCommand({ command: "cat", args: ["/etc/systemd/journald.conf"], timeout: 5000, toolName: "log_system" });
|
|
435
|
+
if (journaldResult.exitCode === 0) {
|
|
436
|
+
const hasPersistent = journaldResult.stdout.includes("Storage=persistent");
|
|
437
|
+
findings.push({ check: "journald_persistent", status: hasPersistent ? "PASS" : "WARN", value: hasPersistent ? "persistent" : "auto/volatile", description: "journald persistent storage (CIS recommends Storage=persistent)" });
|
|
438
|
+
const compressMatch = journaldResult.stdout.match(/Compress=(yes|no)/i);
|
|
439
|
+
findings.push({ check: "journald_compress", status: !compressMatch || compressMatch[1] === "yes" ? "PASS" : "WARN", value: compressMatch ? compressMatch[1] : "default (yes)", description: "journald compression" });
|
|
440
|
+
}
|
|
441
|
+
const logPerms = await executeCommand({ command: "stat", args: ["-c", "%a %U:%G", "/var/log"], timeout: 5000, toolName: "log_system" });
|
|
442
|
+
findings.push({ check: "var_log_permissions", status: logPerms.stdout.trim().startsWith("755") || logPerms.stdout.trim().startsWith("750") ? "PASS" : "WARN", value: logPerms.stdout.trim(), description: "/var/log directory permissions" });
|
|
443
|
+
const passCount = findings.filter(f => f.status === "PASS").length;
|
|
444
|
+
return { content: [createTextContent(JSON.stringify({ summary: { total: findings.length, pass: passCount, fail: findings.filter(f => f.status === "FAIL").length, warn: findings.filter(f => f.status === "WARN").length }, findings }, null, 2))] };
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
return { content: [createErrorContent(error instanceof Error ? error.message : String(error))], isError: true };
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
default:
|
|
451
|
+
return { content: [createErrorContent(`Unknown action: ${action}`)], isError: true };
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Malware detection and quarantine tools for Kali Defense MCP Server.
|
|
3
|
+
*
|
|
4
|
+
* Registers 4 tools: malware_clamav (actions: scan, update),
|
|
5
|
+
* malware_yara_scan, malware_file_scan (actions: suspicious, webshell),
|
|
6
|
+
* malware_quarantine_manage.
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
export declare function registerMalwareTools(server: McpServer): void;
|
|
10
|
+
//# sourceMappingURL=malware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"malware.d.ts","sourceRoot":"","sources":["../../src/tools/malware.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmDpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0lB5D"}
|