@poolzin/pool-bot 2026.3.15 → 2026.3.17
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 +20 -0
- package/dist/agents/checkpoint-manager.js +1 -2
- package/dist/build-info.json +3 -3
- package/docs/assets-evaluation.md +418 -0
- package/docs/branding-evaluation-2026-03-12.md +285 -0
- package/docs/commit-evaluation-42f463de4.md +362 -0
- package/docs/extensions-evaluation.md +696 -0
- package/docs/hexstrike-evaluation.md +514 -0
- package/docs/implementations-summary.md +300 -0
- package/docs/version-2026.3.16-evaluation.md +190 -0
- package/extensions/dexter/README.md +147 -0
- package/extensions/dexter/dist/agent.d.ts +44 -0
- package/extensions/dexter/dist/agent.js +265 -0
- package/extensions/dexter/dist/index.d.ts +12 -0
- package/extensions/dexter/dist/index.js +99 -0
- package/extensions/dexter/node_modules/.bin/tsc +21 -0
- package/extensions/dexter/node_modules/.bin/tsserver +21 -0
- package/extensions/dexter/package.json +33 -0
- package/extensions/dexter/poolbot.plugin.json +35 -0
- package/extensions/dexter/src/agent.ts +375 -0
- package/extensions/dexter/src/index.ts +129 -0
- package/extensions/dexter/tsconfig.json +20 -0
- package/extensions/hackingtool/README.md +75 -0
- package/extensions/hackingtool/dist/client.d.ts +34 -0
- package/extensions/hackingtool/dist/client.js +82 -0
- package/extensions/hackingtool/dist/index.d.ts +12 -0
- package/extensions/hackingtool/dist/index.js +163 -0
- package/extensions/hackingtool/dist/server-manager.d.ts +25 -0
- package/extensions/hackingtool/dist/server-manager.js +107 -0
- package/extensions/hackingtool/node_modules/.bin/tsc +21 -0
- package/extensions/hackingtool/node_modules/.bin/tsserver +21 -0
- package/extensions/hackingtool/package.json +36 -0
- package/extensions/hackingtool/poolbot.plugin.json +55 -0
- package/extensions/hackingtool/src/client.ts +120 -0
- package/extensions/hackingtool/src/index.ts +181 -0
- package/extensions/hackingtool/src/server/hackingtool_mcp.py +454 -0
- package/extensions/hackingtool/src/server/requirements.txt +2 -0
- package/extensions/hackingtool/src/server-manager.ts +128 -0
- package/extensions/hackingtool/tsconfig.json +20 -0
- package/extensions/hexstrike-ai/README.md +693 -44
- package/extensions/hexstrike-ai/src/client.test.ts +335 -0
- package/extensions/hexstrike-ai/src/server-manager.test.ts +286 -0
- package/package.json +1 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { HackingToolServerManager } from "./server-manager.js";
|
|
2
|
+
import { HackingToolClient } from "./client.js";
|
|
3
|
+
|
|
4
|
+
interface HackingToolConfig {
|
|
5
|
+
port?: number;
|
|
6
|
+
host?: string;
|
|
7
|
+
autoStart?: boolean;
|
|
8
|
+
token?: string;
|
|
9
|
+
pythonPath?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default async function createPlugin(
|
|
13
|
+
ctx: any
|
|
14
|
+
): Promise<any> {
|
|
15
|
+
const config = ctx.config as HackingToolConfig;
|
|
16
|
+
const serverManager = new HackingToolServerManager({
|
|
17
|
+
port: config.port,
|
|
18
|
+
host: config.host,
|
|
19
|
+
pythonPath: config.pythonPath,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const client = new HackingToolClient({
|
|
23
|
+
host: config.host,
|
|
24
|
+
port: config.port,
|
|
25
|
+
token: config.token,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (config.autoStart !== false) {
|
|
29
|
+
ctx.logger.info("Starting HackingTool MCP server...");
|
|
30
|
+
try {
|
|
31
|
+
await serverManager.start();
|
|
32
|
+
ctx.logger.info("HackingTool MCP server started successfully");
|
|
33
|
+
} catch (err) {
|
|
34
|
+
ctx.logger.error("Failed to start HackingTool MCP server:", err);
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
ctx.cli
|
|
40
|
+
.command("pentest.status")
|
|
41
|
+
.description("Check HackingTool server status")
|
|
42
|
+
.action(async () => {
|
|
43
|
+
try {
|
|
44
|
+
const health = await client.health();
|
|
45
|
+
console.log("✅ HackingTool is running");
|
|
46
|
+
console.log(" Status:", health.status);
|
|
47
|
+
console.log(" Version:", health.version ?? "unknown");
|
|
48
|
+
console.log(" Uptime:", health.uptime ? `${Math.floor(health.uptime / 60)}m` : "N/A");
|
|
49
|
+
console.log(" Tools Available:", health.toolsAvailable);
|
|
50
|
+
console.log(" Active Scans:", health.activeScans);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error("❌ HackingTool is not running");
|
|
53
|
+
console.error(" Error:", err instanceof Error ? err.message : String(err));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
ctx.cli
|
|
59
|
+
.command("pentest.tools")
|
|
60
|
+
.description("List available penetration testing tools")
|
|
61
|
+
.action(async () => {
|
|
62
|
+
try {
|
|
63
|
+
const tools = await client.getTools();
|
|
64
|
+
console.log("🔧 Available Penetration Testing Tools:\n");
|
|
65
|
+
|
|
66
|
+
for (const [category, toolList] of Object.entries(tools)) {
|
|
67
|
+
if (Array.isArray(toolList)) {
|
|
68
|
+
console.log(`📁 ${category.toUpperCase().replace("_", " ")}`);
|
|
69
|
+
for (const tool of toolList.slice(0, 10)) {
|
|
70
|
+
console.log(` • ${tool}`);
|
|
71
|
+
}
|
|
72
|
+
if (toolList.length > 10) {
|
|
73
|
+
console.log(` ... and ${toolList.length - 10} more`);
|
|
74
|
+
}
|
|
75
|
+
console.log();
|
|
76
|
+
} else {
|
|
77
|
+
console.log(`📁 ${category.toUpperCase().replace("_", " ")}`);
|
|
78
|
+
const subCategories = toolList as Record<string, string[]>;
|
|
79
|
+
for (const [subcat, subtools] of Object.entries(subCategories)) {
|
|
80
|
+
console.log(` ${subcat.replace("_", " ")}: ${subtools.slice(0, 5).join(", ")}`);
|
|
81
|
+
if (subtools.length > 5) {
|
|
82
|
+
console.log(` ... and ${subtools.length - 5} more`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
console.log();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error("❌ Failed to get tools:", err instanceof Error ? err.message : String(err));
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
ctx.cli
|
|
95
|
+
.command("pentest.scan")
|
|
96
|
+
.description("Run penetration testing tool")
|
|
97
|
+
.argument("<category>", "Tool category (e.g., information_gathering, sql_injection, web_attack)")
|
|
98
|
+
.argument("<tool>", "Tool name (e.g., nmap, sqlmap, dirb)")
|
|
99
|
+
.argument("[target]", "Target URL or IP (optional)")
|
|
100
|
+
.option("-o, --output <file>", "Save results to file")
|
|
101
|
+
.action(async (category: string, tool: string, target?: string, options?: { output?: string }) => {
|
|
102
|
+
try {
|
|
103
|
+
console.log(`🚀 Running ${tool} from ${category}...`);
|
|
104
|
+
if (target) {
|
|
105
|
+
console.log(` Target: ${target}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = await client.runTool(category, tool, target);
|
|
109
|
+
console.log(`✅ Tool execution ${result.status}`);
|
|
110
|
+
console.log(` Scan ID: ${result.scanId}`);
|
|
111
|
+
|
|
112
|
+
if (result.result) {
|
|
113
|
+
if (result.result.simulated) {
|
|
114
|
+
console.log(` ℹ️ ${result.result.message}`);
|
|
115
|
+
} else if (result.result.stdout) {
|
|
116
|
+
console.log("\n📊 Output:");
|
|
117
|
+
console.log(result.result.stdout);
|
|
118
|
+
} else if (result.result.error) {
|
|
119
|
+
console.log(` ❌ Error: ${result.result.error}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (options?.output && result.result) {
|
|
124
|
+
const fs = await import("fs");
|
|
125
|
+
fs.writeFileSync(options.output, JSON.stringify(result.result, null, 2));
|
|
126
|
+
console.log(`\n💾 Results saved to: ${options.output}`);
|
|
127
|
+
}
|
|
128
|
+
} catch (err) {
|
|
129
|
+
console.error("❌ Scan failed:", err instanceof Error ? err.message : String(err));
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
ctx.cli
|
|
135
|
+
.command("pentest.scans")
|
|
136
|
+
.description("List active scans")
|
|
137
|
+
.action(async () => {
|
|
138
|
+
try {
|
|
139
|
+
const scans = await client.listScans();
|
|
140
|
+
if (scans.length === 0) {
|
|
141
|
+
console.log("ℹ️ No active scans");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log("🔍 Active Scans:\n");
|
|
146
|
+
for (const scan of scans) {
|
|
147
|
+
const statusIcon = scan.status === "running" ? "🔄" : scan.status === "completed" ? "✅" : "❌";
|
|
148
|
+
console.log(`${statusIcon} ${scan.scanId} - ${scan.tool} (${scan.status})`);
|
|
149
|
+
if (scan.target) {
|
|
150
|
+
console.log(` Target: ${scan.target}`);
|
|
151
|
+
}
|
|
152
|
+
console.log(` Started: ${new Date((scan.startedAt || 0) * 1000).toLocaleString()}`);
|
|
153
|
+
console.log();
|
|
154
|
+
}
|
|
155
|
+
} catch (err) {
|
|
156
|
+
console.error("❌ Failed to list scans:", err instanceof Error ? err.message : String(err));
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
ctx.cli
|
|
162
|
+
.command("pentest.stop")
|
|
163
|
+
.description("Stop HackingTool server")
|
|
164
|
+
.action(async () => {
|
|
165
|
+
ctx.logger.info("Stopping HackingTool server...");
|
|
166
|
+
await serverManager.stop();
|
|
167
|
+
console.log("✅ HackingTool server stopped");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
name: "hackingtool",
|
|
172
|
+
version: "1.2.0",
|
|
173
|
+
async onShutdown() {
|
|
174
|
+
ctx.logger.info("Stopping HackingTool server...");
|
|
175
|
+
await serverManager.stop();
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export { HackingToolServerManager, HackingToolClient };
|
|
181
|
+
export type { HackingToolConfig };
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
HackingTool MCP Server - Security Testing Platform
|
|
4
|
+
Integrates 100+ security tools for penetration testing and security assessment.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import json
|
|
9
|
+
import subprocess
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Dict, List, Optional
|
|
13
|
+
import asyncio
|
|
14
|
+
import hashlib
|
|
15
|
+
import time
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class HackingToolServer:
|
|
19
|
+
"""MCP server for HackingTool security platform."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, port: int = 8889, host: str = "127.0.0.1"):
|
|
22
|
+
self.port = port
|
|
23
|
+
self.host = host
|
|
24
|
+
self.start_time = time.time()
|
|
25
|
+
self.active_scans: Dict[str, Dict[str, Any]] = {}
|
|
26
|
+
self.tool_categories = {
|
|
27
|
+
"anonymity": "Anonymously Hiding Tools",
|
|
28
|
+
"information_gathering": "Information Gathering Tools",
|
|
29
|
+
"wordlist": "Wordlist Generator",
|
|
30
|
+
"wireless": "Wireless Attack Tools",
|
|
31
|
+
"sql_injection": "SQL Injection Tools",
|
|
32
|
+
"phishing": "Phishing Attack Tools",
|
|
33
|
+
"web_attack": "Web Attack Tools",
|
|
34
|
+
"post_exploitation": "Post Exploitation Tools",
|
|
35
|
+
"forensic": "Forensic Tools",
|
|
36
|
+
"payload": "Payload Creation Tools",
|
|
37
|
+
"exploit": "Exploit Framework",
|
|
38
|
+
"reverse_engineering": "Reverse Engineering Tools",
|
|
39
|
+
"ddos": "DDOS Attack Tools",
|
|
40
|
+
"rat": "Remote Administrator Tools",
|
|
41
|
+
"xss": "XSS Attack Tools",
|
|
42
|
+
"steganography": "Steganography Tools",
|
|
43
|
+
"other": "Other Tools",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
def get_health(self) -> Dict[str, Any]:
|
|
47
|
+
"""Get server health status."""
|
|
48
|
+
return {
|
|
49
|
+
"status": "healthy",
|
|
50
|
+
"version": "1.2.0",
|
|
51
|
+
"uptime": time.time() - self.start_time,
|
|
52
|
+
"active_scans": len(self.active_scans),
|
|
53
|
+
"tools_available": sum(len(tools) for tools in self.get_tools().values()),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
def get_tools(self) -> Dict[str, List[str]]:
|
|
57
|
+
"""Get available tools by category."""
|
|
58
|
+
return {
|
|
59
|
+
"anonymity": ["Anonmously Surf", "Multitor"],
|
|
60
|
+
"information_gathering": [
|
|
61
|
+
"nmap",
|
|
62
|
+
"Dracnmap",
|
|
63
|
+
"Port Scan",
|
|
64
|
+
"Host2IP",
|
|
65
|
+
"Xerosploit",
|
|
66
|
+
"RED HAWK",
|
|
67
|
+
"ReconSpider",
|
|
68
|
+
"IsItDown",
|
|
69
|
+
"Infoga",
|
|
70
|
+
"ReconDog",
|
|
71
|
+
"Striker",
|
|
72
|
+
"SecretFinder",
|
|
73
|
+
"Shodanfy",
|
|
74
|
+
"rang3r",
|
|
75
|
+
"ranger-reloaded",
|
|
76
|
+
"Breacher",
|
|
77
|
+
],
|
|
78
|
+
"wordlist": [
|
|
79
|
+
"Cupp",
|
|
80
|
+
"WordlistCreator",
|
|
81
|
+
"Goblin WordGenerator",
|
|
82
|
+
"Password List",
|
|
83
|
+
],
|
|
84
|
+
"wireless": [
|
|
85
|
+
"WiFi-Pumpkin",
|
|
86
|
+
"pixiewps",
|
|
87
|
+
"Bluepot",
|
|
88
|
+
"Fluxion",
|
|
89
|
+
"Wifiphisher",
|
|
90
|
+
"Wifite",
|
|
91
|
+
"EvilTwin",
|
|
92
|
+
"Fastssh",
|
|
93
|
+
"Howmanypeople",
|
|
94
|
+
],
|
|
95
|
+
"sql_injection": [
|
|
96
|
+
"Sqlmap",
|
|
97
|
+
"NoSqlMap",
|
|
98
|
+
"DSSS",
|
|
99
|
+
"Explo",
|
|
100
|
+
"Blisqy",
|
|
101
|
+
"Leviathan",
|
|
102
|
+
"SQLScan",
|
|
103
|
+
],
|
|
104
|
+
"phishing": [
|
|
105
|
+
"Setoolkit",
|
|
106
|
+
"SocialFish",
|
|
107
|
+
"HiddenEye",
|
|
108
|
+
"Evilginx2",
|
|
109
|
+
"I-See_You",
|
|
110
|
+
"SayCheese",
|
|
111
|
+
"QR Code Jacking",
|
|
112
|
+
"ShellPhish",
|
|
113
|
+
"BlackPhish",
|
|
114
|
+
],
|
|
115
|
+
"web_attack": [
|
|
116
|
+
"Web2Attack",
|
|
117
|
+
"Skipfish",
|
|
118
|
+
"Sublist3r",
|
|
119
|
+
"CheckURL",
|
|
120
|
+
"Blazy",
|
|
121
|
+
"takeover",
|
|
122
|
+
"Dirb",
|
|
123
|
+
],
|
|
124
|
+
"post_exploitation": ["Vegile", "HeraKeylogger"],
|
|
125
|
+
"forensic": [
|
|
126
|
+
"Autopsy",
|
|
127
|
+
"Wireshark",
|
|
128
|
+
"Bulk extractor",
|
|
129
|
+
"Guymager",
|
|
130
|
+
"Toolsley",
|
|
131
|
+
"Volatility3",
|
|
132
|
+
],
|
|
133
|
+
"payload": [
|
|
134
|
+
"The FatRat",
|
|
135
|
+
"Brutal",
|
|
136
|
+
"Stitch",
|
|
137
|
+
"MSFvenom Payload Creator",
|
|
138
|
+
"Venom",
|
|
139
|
+
"Spycam",
|
|
140
|
+
"Mob-Droid",
|
|
141
|
+
"Enigma",
|
|
142
|
+
],
|
|
143
|
+
"exploit": ["RouterSploit", "WebSploit", "Commix", "Web2Attack"],
|
|
144
|
+
"reverse_engineering": ["Androguard", "Apk2Gold", "JadX"],
|
|
145
|
+
"ddos": ["SlowLoris", "aSYNcrone", "UFOnet", "GoldenEye"],
|
|
146
|
+
"rat": ["Stitch", "Pyshell"],
|
|
147
|
+
"xss": [
|
|
148
|
+
"DalFox",
|
|
149
|
+
"XSS-LOADER",
|
|
150
|
+
"extended-xss-search",
|
|
151
|
+
"XSS-Freak",
|
|
152
|
+
"XSpear",
|
|
153
|
+
"XSSCon",
|
|
154
|
+
"XanXSS",
|
|
155
|
+
"XSStrike",
|
|
156
|
+
"RVuln",
|
|
157
|
+
"Cyclops",
|
|
158
|
+
],
|
|
159
|
+
"steganography": [
|
|
160
|
+
"SteganoHide",
|
|
161
|
+
"StegnoCracker",
|
|
162
|
+
"StegoCracker",
|
|
163
|
+
"Whitespace",
|
|
164
|
+
],
|
|
165
|
+
"other": {
|
|
166
|
+
"social_bruteforce": [
|
|
167
|
+
"Instagram Attack",
|
|
168
|
+
"AllinOne Attack",
|
|
169
|
+
"Facebook Attack",
|
|
170
|
+
"Application Checker",
|
|
171
|
+
],
|
|
172
|
+
"android_hacking": [
|
|
173
|
+
"Keydroid",
|
|
174
|
+
"MySMS",
|
|
175
|
+
"Lockphish",
|
|
176
|
+
"DroidCam",
|
|
177
|
+
"EvilApp",
|
|
178
|
+
"HatCloud",
|
|
179
|
+
],
|
|
180
|
+
"homograph": ["EvilURL"],
|
|
181
|
+
"email_verify": ["KnockMail"],
|
|
182
|
+
"hash_cracking": ["Hash Buster"],
|
|
183
|
+
"wifi_deauth": ["WifiJammer-NG", "KawaiiDeauther"],
|
|
184
|
+
"social_finder": [
|
|
185
|
+
"Social Mapper",
|
|
186
|
+
"finduser",
|
|
187
|
+
"Sherlock",
|
|
188
|
+
"SocialScan",
|
|
189
|
+
],
|
|
190
|
+
"payload_injector": ["Debinject", "Pixload"],
|
|
191
|
+
"web_crawling": ["Gospider"],
|
|
192
|
+
"mix": ["Terminal Multiplexer", "Crivo"],
|
|
193
|
+
},
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
def run_tool(
|
|
197
|
+
self,
|
|
198
|
+
category: str,
|
|
199
|
+
tool_name: str,
|
|
200
|
+
target: Optional[str] = None,
|
|
201
|
+
options: Optional[Dict[str, Any]] = None,
|
|
202
|
+
) -> Dict[str, Any]:
|
|
203
|
+
"""Execute a security tool."""
|
|
204
|
+
scan_id = hashlib.md5(
|
|
205
|
+
f"{category}_{tool_name}_{time.time()}".encode()
|
|
206
|
+
).hexdigest()[:12]
|
|
207
|
+
|
|
208
|
+
self.active_scans[scan_id] = {
|
|
209
|
+
"category": category,
|
|
210
|
+
"tool": tool_name,
|
|
211
|
+
"target": target,
|
|
212
|
+
"options": options or {},
|
|
213
|
+
"status": "running",
|
|
214
|
+
"started_at": time.time(),
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
result = self._execute_tool(category, tool_name, target, options)
|
|
219
|
+
self.active_scans[scan_id]["status"] = "completed"
|
|
220
|
+
self.active_scans[scan_id]["completed_at"] = time.time()
|
|
221
|
+
self.active_scans[scan_id]["result"] = result
|
|
222
|
+
|
|
223
|
+
return {"scan_id": scan_id, "status": "completed", "result": result}
|
|
224
|
+
except Exception as e:
|
|
225
|
+
self.active_scans[scan_id]["status"] = "failed"
|
|
226
|
+
self.active_scans[scan_id]["error"] = str(e)
|
|
227
|
+
|
|
228
|
+
return {"scan_id": scan_id, "status": "failed", "error": str(e)}
|
|
229
|
+
|
|
230
|
+
def _execute_tool(
|
|
231
|
+
self,
|
|
232
|
+
category: str,
|
|
233
|
+
tool_name: str,
|
|
234
|
+
target: Optional[str],
|
|
235
|
+
options: Optional[Dict[str, Any]],
|
|
236
|
+
) -> Dict[str, Any]:
|
|
237
|
+
"""Execute the actual tool command."""
|
|
238
|
+
tool_lower = tool_name.lower().replace(" ", "_").replace("-", "_")
|
|
239
|
+
|
|
240
|
+
cmd_mapping = {
|
|
241
|
+
"nmap": lambda t: ["nmap", "-sV", "-sC", t] if t else ["nmap", "--help"],
|
|
242
|
+
"sqlmap": lambda t: (
|
|
243
|
+
["sqlmap", "-u", t, "--batch"] if t else ["sqlmap", "--help"]
|
|
244
|
+
),
|
|
245
|
+
"dirb": lambda t: (
|
|
246
|
+
["dirb", t, "/usr/share/wordlists/dirb/common.txt"]
|
|
247
|
+
if t
|
|
248
|
+
else ["dirb", "--help"]
|
|
249
|
+
),
|
|
250
|
+
"nikto": lambda t: ["nikto", "-h", t] if t else ["nikto", "--help"],
|
|
251
|
+
"gobuster": lambda t: (
|
|
252
|
+
[
|
|
253
|
+
"gobuster",
|
|
254
|
+
"dir",
|
|
255
|
+
"-u",
|
|
256
|
+
t,
|
|
257
|
+
"-w",
|
|
258
|
+
"/usr/share/wordlists/dirb/common.txt",
|
|
259
|
+
]
|
|
260
|
+
if t
|
|
261
|
+
else ["gobuster", "--help"]
|
|
262
|
+
),
|
|
263
|
+
"wpscan": lambda t: (
|
|
264
|
+
["wpscan", "--url", t, "--enumerate", "vp,u"]
|
|
265
|
+
if t
|
|
266
|
+
else ["wpscan", "--help"]
|
|
267
|
+
),
|
|
268
|
+
"sublist3r": lambda t: (
|
|
269
|
+
["sublist3r", "-d", t] if t else ["sublist3r", "--help"]
|
|
270
|
+
),
|
|
271
|
+
"sherlock": lambda t: ["sherlock", t] if t else ["sherlock", "--help"],
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
cmd_func = cmd_mapping.get(tool_lower)
|
|
275
|
+
|
|
276
|
+
if not cmd_func:
|
|
277
|
+
return {
|
|
278
|
+
"tool": tool_name,
|
|
279
|
+
"category": category,
|
|
280
|
+
"simulated": True,
|
|
281
|
+
"message": f"Tool {tool_name} would be executed (requires installation)",
|
|
282
|
+
"target": target,
|
|
283
|
+
"options": options,
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
cmd = cmd_func(target) if target else cmd_func(None)
|
|
287
|
+
|
|
288
|
+
try:
|
|
289
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
"tool": tool_name,
|
|
293
|
+
"category": category,
|
|
294
|
+
"target": target,
|
|
295
|
+
"stdout": result.stdout,
|
|
296
|
+
"stderr": result.stderr,
|
|
297
|
+
"returncode": result.returncode,
|
|
298
|
+
"execution_time": time.time()
|
|
299
|
+
- self.active_scans.get(cmd.split()[0], {}).get(
|
|
300
|
+
"started_at", time.time()
|
|
301
|
+
),
|
|
302
|
+
}
|
|
303
|
+
except subprocess.TimeoutExpired:
|
|
304
|
+
return {"tool": tool_name, "error": "Tool execution timed out (5 minutes)"}
|
|
305
|
+
except FileNotFoundError:
|
|
306
|
+
return {
|
|
307
|
+
"tool": tool_name,
|
|
308
|
+
"error": f"Tool '{tool_name}' not found. Please install it first.",
|
|
309
|
+
"installation_hint": f"sudo apt install {tool_lower}",
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
def get_scan_status(self, scan_id: str) -> Dict[str, Any]:
|
|
313
|
+
"""Get status of a scan."""
|
|
314
|
+
if scan_id not in self.active_scans:
|
|
315
|
+
return {"error": f"Scan {scan_id} not found"}
|
|
316
|
+
|
|
317
|
+
scan = self.active_scans[scan_id]
|
|
318
|
+
return {
|
|
319
|
+
"scan_id": scan_id,
|
|
320
|
+
"status": scan["status"],
|
|
321
|
+
"category": scan["category"],
|
|
322
|
+
"tool": scan["tool"],
|
|
323
|
+
"target": scan.get("target"),
|
|
324
|
+
"started_at": scan.get("started_at"),
|
|
325
|
+
"completed_at": scan.get("completed_at"),
|
|
326
|
+
"duration": (scan.get("completed_at") or time.time())
|
|
327
|
+
- scan.get("started_at"),
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
def list_scans(self) -> List[Dict[str, Any]]:
|
|
331
|
+
"""List all active scans."""
|
|
332
|
+
return [
|
|
333
|
+
{
|
|
334
|
+
"scan_id": scan_id,
|
|
335
|
+
"status": scan["status"],
|
|
336
|
+
"tool": scan["tool"],
|
|
337
|
+
"target": scan.get("target"),
|
|
338
|
+
"started_at": scan.get("started_at"),
|
|
339
|
+
}
|
|
340
|
+
for scan_id, scan in self.active_scans.items()
|
|
341
|
+
]
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def main():
|
|
345
|
+
"""Main MCP server entry point."""
|
|
346
|
+
import argparse
|
|
347
|
+
|
|
348
|
+
parser = argparse.ArgumentParser(description="HackingTool MCP Server")
|
|
349
|
+
parser.add_argument("--port", type=int, default=8889, help="Server port")
|
|
350
|
+
parser.add_argument("--host", type=str, default="127.0.0.1", help="Server host")
|
|
351
|
+
parser.add_argument("--stdio", action="store_true", help="Use stdio transport")
|
|
352
|
+
|
|
353
|
+
args = parser.parse_args()
|
|
354
|
+
|
|
355
|
+
server = HackingToolServer(port=args.port, host=args.host)
|
|
356
|
+
|
|
357
|
+
if args.stdio:
|
|
358
|
+
print(
|
|
359
|
+
json.dumps({"status": "ready", "message": "HackingTool MCP Server ready"}),
|
|
360
|
+
flush=True,
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
for line in sys.stdin:
|
|
364
|
+
try:
|
|
365
|
+
request = json.loads(line.strip())
|
|
366
|
+
method = request.get("method")
|
|
367
|
+
params = request.get("params", {})
|
|
368
|
+
|
|
369
|
+
if method == "health":
|
|
370
|
+
response = server.get_health()
|
|
371
|
+
elif method == "tools":
|
|
372
|
+
response = server.get_tools()
|
|
373
|
+
elif method == "run_tool":
|
|
374
|
+
response = server.run_tool(
|
|
375
|
+
params.get("category", "other"),
|
|
376
|
+
params.get("tool_name"),
|
|
377
|
+
params.get("target"),
|
|
378
|
+
params.get("options"),
|
|
379
|
+
)
|
|
380
|
+
elif method == "scan_status":
|
|
381
|
+
response = server.get_scan_status(params.get("scan_id"))
|
|
382
|
+
elif method == "list_scans":
|
|
383
|
+
response = server.list_scans()
|
|
384
|
+
else:
|
|
385
|
+
response = {"error": f"Unknown method: {method}"}
|
|
386
|
+
|
|
387
|
+
print(json.dumps({"result": response}), flush=True)
|
|
388
|
+
except Exception as e:
|
|
389
|
+
print(json.dumps({"error": str(e)}), flush=True)
|
|
390
|
+
else:
|
|
391
|
+
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
392
|
+
|
|
393
|
+
class MCPHandler(BaseHTTPRequestHandler):
|
|
394
|
+
def do_POST(self):
|
|
395
|
+
content_length = int(self.headers.get("Content-Length", 0))
|
|
396
|
+
post_data = self.rfile.read(content_length)
|
|
397
|
+
|
|
398
|
+
try:
|
|
399
|
+
request = json.loads(post_data.decode())
|
|
400
|
+
method = request.get("method")
|
|
401
|
+
params = request.get("params", {})
|
|
402
|
+
|
|
403
|
+
if method == "health":
|
|
404
|
+
response = server.get_health()
|
|
405
|
+
elif method == "tools":
|
|
406
|
+
response = server.get_tools()
|
|
407
|
+
elif method == "run_tool":
|
|
408
|
+
response = server.run_tool(
|
|
409
|
+
params.get("category", "other"),
|
|
410
|
+
params.get("tool_name"),
|
|
411
|
+
params.get("target"),
|
|
412
|
+
params.get("options"),
|
|
413
|
+
)
|
|
414
|
+
elif method == "scan_status":
|
|
415
|
+
response = server.get_scan_status(params.get("scan_id"))
|
|
416
|
+
elif method == "list_scans":
|
|
417
|
+
response = server.list_scans()
|
|
418
|
+
else:
|
|
419
|
+
response = {"error": f"Unknown method: {method}"}
|
|
420
|
+
|
|
421
|
+
self.send_response(200)
|
|
422
|
+
self.send_header("Content-Type", "application/json")
|
|
423
|
+
self.end_headers()
|
|
424
|
+
self.wfile.write(json.dumps({"result": response}).encode())
|
|
425
|
+
except Exception as e:
|
|
426
|
+
self.send_response(500)
|
|
427
|
+
self.end_headers()
|
|
428
|
+
self.wfile.write(json.dumps({"error": str(e)}).encode())
|
|
429
|
+
|
|
430
|
+
def do_GET(self):
|
|
431
|
+
if self.path == "/health":
|
|
432
|
+
response = server.get_health()
|
|
433
|
+
elif self.path == "/tools":
|
|
434
|
+
response = server.get_tools()
|
|
435
|
+
elif self.path.startswith("/scan/"):
|
|
436
|
+
scan_id = self.path.split("/")[2]
|
|
437
|
+
response = server.get_scan_status(scan_id)
|
|
438
|
+
elif self.path == "/scans":
|
|
439
|
+
response = server.list_scans()
|
|
440
|
+
else:
|
|
441
|
+
response = {"error": "Not found"}
|
|
442
|
+
|
|
443
|
+
self.send_response(200)
|
|
444
|
+
self.send_header("Content-Type", "application/json")
|
|
445
|
+
self.end_headers()
|
|
446
|
+
self.wfile.write(json.dumps(response).encode())
|
|
447
|
+
|
|
448
|
+
httpd = HTTPServer((args.host, args.port), MCPHandler)
|
|
449
|
+
print(f"HackingTool MCP Server running on http://{args.host}:{args.port}")
|
|
450
|
+
httpd.serve_forever()
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
if __name__ == "__main__":
|
|
454
|
+
main()
|