@burtthecoder/mcp-dnstwist 1.0.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/LICENSE +21 -0
- package/README.md +158 -0
- package/build/index.js +207 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 mcp-dnstwist contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# DNStwist MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server for [dnstwist](https://github.com/elceef/dnstwist), a powerful DNS fuzzing tool that helps detect typosquatting, phishing, and corporate espionage. This server provides tools for analyzing domain permutations and identifying potentially malicious domains. It is designed to integrate seamlessly with MCP-compatible applications like [Claude Desktop](https://claude.ai).
|
|
4
|
+
|
|
5
|
+
## ⚠️ Warning
|
|
6
|
+
|
|
7
|
+
This tool is designed for legitimate security research purposes. Please:
|
|
8
|
+
- Only analyze domains you own or have permission to test
|
|
9
|
+
- Respect rate limits and DNS server policies
|
|
10
|
+
- Use responsibly and ethically
|
|
11
|
+
- Be aware that some DNS servers may rate-limit or block automated queries
|
|
12
|
+
- Consider the impact on DNS infrastructure when running large scans
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Node.js (v18 or later)
|
|
17
|
+
- Docker
|
|
18
|
+
- macOS, Linux, or Windows with Docker Desktop installed
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
1. Install Docker:
|
|
23
|
+
- macOS: Install [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
|
24
|
+
- Linux: Follow the [Docker Engine installation guide](https://docs.docker.com/engine/install/)
|
|
25
|
+
|
|
26
|
+
2. Install the server globally via npm:
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g mcp-dnstwist
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
3. Add to your Claude Desktop configuration file:
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"dnstwist": {
|
|
36
|
+
"command": "mcp-dnstwist"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Configuration file location:
|
|
43
|
+
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
44
|
+
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
45
|
+
|
|
46
|
+
4. Restart Claude Desktop
|
|
47
|
+
|
|
48
|
+
## Alternative Setup (From Source)
|
|
49
|
+
|
|
50
|
+
If you prefer to run from source or need to modify the code:
|
|
51
|
+
|
|
52
|
+
1. Clone and build:
|
|
53
|
+
```bash
|
|
54
|
+
git clone <repository_url>
|
|
55
|
+
cd mcp-dnstwist
|
|
56
|
+
npm install
|
|
57
|
+
npm run build
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
2. Add to your Claude Desktop configuration:
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"dnstwist": {
|
|
65
|
+
"command": "node",
|
|
66
|
+
"args": ["/absolute/path/to/mcp-dnstwist/build/index.js"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Features
|
|
73
|
+
|
|
74
|
+
- **Domain Fuzzing**: Generate domain permutations using various algorithms
|
|
75
|
+
- **Registration Check**: Verify if permutated domains are registered
|
|
76
|
+
- **DNS Analysis**: Check A, AAAA, MX, and NS records
|
|
77
|
+
- **Web Presence**: Capture HTTP banner information
|
|
78
|
+
- **WHOIS Data**: Retrieve registration dates and registrar information
|
|
79
|
+
- **Phishing Detection**: Generate fuzzy hashes of web pages
|
|
80
|
+
- **Configurable**: Custom DNS servers and parallel processing
|
|
81
|
+
- **Multiple Formats**: Support for json, csv, and list output formats
|
|
82
|
+
|
|
83
|
+
## Tools
|
|
84
|
+
|
|
85
|
+
### Domain Fuzzing Tool
|
|
86
|
+
- Name: `fuzz_domain`
|
|
87
|
+
- Description: Generate and analyze domain permutations to detect potential typosquatting, phishing, and brand impersonation
|
|
88
|
+
- Parameters:
|
|
89
|
+
* `domain` (required): Domain name to analyze (e.g., example.com)
|
|
90
|
+
* `nameservers` (optional, default: "1.1.1.1"): Comma-separated list of DNS servers
|
|
91
|
+
* `threads` (optional, default: 50): Number of threads for parallel processing
|
|
92
|
+
* `format` (optional, default: "json"): Output format (json, csv, list)
|
|
93
|
+
* `registered_only` (optional, default: true): Show only registered domains
|
|
94
|
+
* `mxcheck` (optional, default: true): Check for MX records
|
|
95
|
+
* `ssdeep` (optional, default: false): Generate fuzzy hashes of web pages
|
|
96
|
+
* `banners` (optional, default: true): Capture HTTP banner information
|
|
97
|
+
|
|
98
|
+
Example:
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"domain": "example.com",
|
|
102
|
+
"nameservers": "1.1.1.1,8.8.8.8",
|
|
103
|
+
"threads": 50,
|
|
104
|
+
"format": "json",
|
|
105
|
+
"registered_only": true,
|
|
106
|
+
"mxcheck": true,
|
|
107
|
+
"banners": true
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Troubleshooting
|
|
112
|
+
|
|
113
|
+
### Docker Issues
|
|
114
|
+
|
|
115
|
+
1. Verify Docker is installed and running:
|
|
116
|
+
```bash
|
|
117
|
+
docker --version
|
|
118
|
+
docker ps
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
2. Check Docker permissions:
|
|
122
|
+
- Ensure your user has permissions to run Docker commands
|
|
123
|
+
- On Linux, add your user to the docker group: `sudo usermod -aG docker $USER`
|
|
124
|
+
|
|
125
|
+
### Common Issues
|
|
126
|
+
|
|
127
|
+
1. DNS resolution problems:
|
|
128
|
+
- Verify DNS servers are accessible
|
|
129
|
+
- Try alternative DNS servers (e.g., 8.8.8.8)
|
|
130
|
+
- Check for rate limiting or blocking
|
|
131
|
+
|
|
132
|
+
2. Performance issues:
|
|
133
|
+
- Adjust thread count based on system capabilities
|
|
134
|
+
- Consider network bandwidth and latency
|
|
135
|
+
- Monitor DNS server response times
|
|
136
|
+
|
|
137
|
+
3. After fixing any issues:
|
|
138
|
+
- Save the configuration file
|
|
139
|
+
- Restart Claude Desktop
|
|
140
|
+
|
|
141
|
+
## Error Messages
|
|
142
|
+
|
|
143
|
+
- "Docker is not installed or not running": Install Docker and start the Docker daemon
|
|
144
|
+
- "Failed to parse dnstwist output": Check if the domain is valid and the format is correct
|
|
145
|
+
- "Error executing dnstwist": Check Docker logs and ensure proper permissions
|
|
146
|
+
- "DNS server not responding": Verify DNS server accessibility and try alternative servers
|
|
147
|
+
|
|
148
|
+
## Contributing
|
|
149
|
+
|
|
150
|
+
1. Fork the repository
|
|
151
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
152
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
153
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
154
|
+
5. Open a Pull Request
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/build/index.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { exec } from 'child_process';
|
|
6
|
+
import { promisify } from 'util';
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
const DOCKER_IMAGE = 'elceef/dnstwist';
|
|
9
|
+
function isFuzzDomainArgs(args) {
|
|
10
|
+
if (!args || typeof args !== 'object')
|
|
11
|
+
return false;
|
|
12
|
+
const a = args;
|
|
13
|
+
return typeof a.domain === 'string' &&
|
|
14
|
+
(a.nameservers === undefined || typeof a.nameservers === 'string') &&
|
|
15
|
+
(a.threads === undefined || typeof a.threads === 'number') &&
|
|
16
|
+
(a.format === undefined || ['json', 'csv', 'list'].includes(a.format)) &&
|
|
17
|
+
(a.registered_only === undefined || typeof a.registered_only === 'boolean') &&
|
|
18
|
+
(a.mxcheck === undefined || typeof a.mxcheck === 'boolean') &&
|
|
19
|
+
(a.ssdeep === undefined || typeof a.ssdeep === 'boolean') &&
|
|
20
|
+
(a.banners === undefined || typeof a.banners === 'boolean');
|
|
21
|
+
}
|
|
22
|
+
class DnstwistServer {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.server = new Server({
|
|
25
|
+
name: 'dnstwist-server',
|
|
26
|
+
version: '0.1.0',
|
|
27
|
+
capabilities: {
|
|
28
|
+
tools: {}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
this.setupToolHandlers();
|
|
32
|
+
this.server.onerror = (error) => console.error('[MCP Error]', error);
|
|
33
|
+
process.on('SIGINT', async () => {
|
|
34
|
+
await this.server.close();
|
|
35
|
+
process.exit(0);
|
|
36
|
+
});
|
|
37
|
+
// Trigger setup immediately
|
|
38
|
+
this.ensureSetup().catch(error => {
|
|
39
|
+
console.error('Failed to setup dnstwist:', error);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async execCommand(command) {
|
|
44
|
+
console.error('Executing command:', command);
|
|
45
|
+
try {
|
|
46
|
+
const result = await execAsync(command, {
|
|
47
|
+
maxBuffer: 10 * 1024 * 1024
|
|
48
|
+
});
|
|
49
|
+
console.error('Command output:', result.stdout);
|
|
50
|
+
if (result.stderr)
|
|
51
|
+
console.error('Command stderr:', result.stderr);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error('Command failed:', error);
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async ensureSetup() {
|
|
60
|
+
try {
|
|
61
|
+
console.error('Checking Docker...');
|
|
62
|
+
try {
|
|
63
|
+
await this.execCommand('docker --version');
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
throw new Error('Docker is not installed or not running. Please install Docker and try again.');
|
|
67
|
+
}
|
|
68
|
+
console.error('Checking if dnstwist image exists...');
|
|
69
|
+
try {
|
|
70
|
+
await this.execCommand(`docker image inspect ${DOCKER_IMAGE}`);
|
|
71
|
+
console.error('Dnstwist image found');
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('Dnstwist image not found, pulling...');
|
|
75
|
+
await this.execCommand(`docker pull ${DOCKER_IMAGE}`);
|
|
76
|
+
console.error('Dnstwist image pulled successfully');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error('Setup failed:', error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
setupToolHandlers() {
|
|
85
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
86
|
+
tools: [
|
|
87
|
+
{
|
|
88
|
+
name: 'fuzz_domain',
|
|
89
|
+
description: 'Generate and analyze domain permutations to detect potential typosquatting, phishing, and brand impersonation',
|
|
90
|
+
inputSchema: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {
|
|
93
|
+
domain: {
|
|
94
|
+
type: 'string',
|
|
95
|
+
description: 'Domain name to analyze (e.g., example.com)'
|
|
96
|
+
},
|
|
97
|
+
nameservers: {
|
|
98
|
+
type: 'string',
|
|
99
|
+
description: 'Comma-separated list of DNS servers to use (default: 1.1.1.1)',
|
|
100
|
+
default: '1.1.1.1'
|
|
101
|
+
},
|
|
102
|
+
threads: {
|
|
103
|
+
type: 'number',
|
|
104
|
+
description: 'Number of threads to use for parallel processing',
|
|
105
|
+
minimum: 1,
|
|
106
|
+
maximum: 100,
|
|
107
|
+
default: 50
|
|
108
|
+
},
|
|
109
|
+
format: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
enum: ['json', 'csv', 'list'],
|
|
112
|
+
description: 'Output format',
|
|
113
|
+
default: 'json'
|
|
114
|
+
},
|
|
115
|
+
registered_only: {
|
|
116
|
+
type: 'boolean',
|
|
117
|
+
description: 'Show only registered domain permutations',
|
|
118
|
+
default: true
|
|
119
|
+
},
|
|
120
|
+
mxcheck: {
|
|
121
|
+
type: 'boolean',
|
|
122
|
+
description: 'Check for MX records',
|
|
123
|
+
default: true
|
|
124
|
+
},
|
|
125
|
+
ssdeep: {
|
|
126
|
+
type: 'boolean',
|
|
127
|
+
description: 'Generate fuzzy hashes of web pages to detect phishing',
|
|
128
|
+
default: false
|
|
129
|
+
},
|
|
130
|
+
banners: {
|
|
131
|
+
type: 'boolean',
|
|
132
|
+
description: 'Capture HTTP banner information',
|
|
133
|
+
default: true
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
required: ['domain']
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
}));
|
|
141
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
142
|
+
try {
|
|
143
|
+
await this.ensureSetup();
|
|
144
|
+
if (request.params.name !== 'fuzz_domain') {
|
|
145
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
146
|
+
}
|
|
147
|
+
if (!isFuzzDomainArgs(request.params.arguments)) {
|
|
148
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments for fuzz_domain');
|
|
149
|
+
}
|
|
150
|
+
const { domain, nameservers = '1.1.1.1', threads = 50, format = 'json', registered_only = true, mxcheck = true, ssdeep = false, banners = true } = request.params.arguments;
|
|
151
|
+
// Build command arguments
|
|
152
|
+
const args = [
|
|
153
|
+
domain,
|
|
154
|
+
'--format', format
|
|
155
|
+
];
|
|
156
|
+
if (registered_only)
|
|
157
|
+
args.push('--registered');
|
|
158
|
+
if (nameservers)
|
|
159
|
+
args.push('--nameservers', nameservers);
|
|
160
|
+
if (threads)
|
|
161
|
+
args.push('-t', threads.toString());
|
|
162
|
+
if (mxcheck)
|
|
163
|
+
args.push('--mxcheck');
|
|
164
|
+
if (ssdeep)
|
|
165
|
+
args.push('--ssdeep');
|
|
166
|
+
if (banners)
|
|
167
|
+
args.push('-b');
|
|
168
|
+
// Run dnstwist in Docker
|
|
169
|
+
const { stdout, stderr } = await this.execCommand(`docker run --rm ${DOCKER_IMAGE} ${args.join(' ')}`);
|
|
170
|
+
let results;
|
|
171
|
+
try {
|
|
172
|
+
results = JSON.parse(stdout);
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
throw new Error(`Failed to parse dnstwist output: ${error}`);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
content: [
|
|
179
|
+
{
|
|
180
|
+
type: 'text',
|
|
181
|
+
text: JSON.stringify(results, null, 2)
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
188
|
+
return {
|
|
189
|
+
content: [
|
|
190
|
+
{
|
|
191
|
+
type: 'text',
|
|
192
|
+
text: `Error executing dnstwist: ${errorMessage}`
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
isError: true
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
async run() {
|
|
201
|
+
const transport = new StdioServerTransport();
|
|
202
|
+
await this.server.connect(transport);
|
|
203
|
+
console.error('Dnstwist MCP server running on stdio');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const server = new DnstwistServer();
|
|
207
|
+
server.run().catch(console.error);
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@burtthecoder/mcp-dnstwist",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for dnstwist - DNS fuzzing to detect typosquatting, phishing and corporate espionage",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-dnstwist": "build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"build",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc && chmod +x build/index.js",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "^0.4.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^20.0.0",
|
|
24
|
+
"typescript": "^5.0.0"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/burtthecoder/mcp-dnstwist.git"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"mcp",
|
|
32
|
+
"dnstwist",
|
|
33
|
+
"dns",
|
|
34
|
+
"security",
|
|
35
|
+
"phishing",
|
|
36
|
+
"typosquatting",
|
|
37
|
+
"domain-security",
|
|
38
|
+
"claude",
|
|
39
|
+
"claude-desktop"
|
|
40
|
+
],
|
|
41
|
+
"author": "burtmacklin",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
}
|
|
46
|
+
}
|