SAUSERLA commited on
Commit
c0e793f
·
verified ·
1 Parent(s): 5090d56

Delete kali_server.py

Browse files
Files changed (1) hide show
  1. kali_server.py +0 -1240
kali_server.py DELETED
@@ -1,1240 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- # This script connect the MCP AI agent to Kali Linux terminal and API Server.
4
-
5
- # some of the code here was inspired from https://github.com/whit3rabbit0/project_astro , be sure to check them out
6
-
7
- import argparse
8
- import json
9
- import logging
10
- import os
11
- import subprocess
12
- import sys
13
- import traceback
14
- import threading
15
- from typing import Dict, Any
16
- from flask import Flask, request, jsonify
17
-
18
- # Configure logging
19
- logging.basicConfig(
20
- level=logging.INFO,
21
- format="%(asctime)s [%(levelname)s] %(message)s",
22
- handlers=[
23
- logging.StreamHandler(sys.stdout)
24
- ]
25
- )
26
- logger = logging.getLogger(__name__)
27
-
28
- # Configuration
29
- API_PORT = int(os.environ.get("API_PORT", 5000))
30
- DEBUG_MODE = os.environ.get("DEBUG_MODE", "0").lower() in ("1", "true", "yes", "y")
31
- COMMAND_TIMEOUT = 180 # 5 minutes default timeout
32
-
33
- app = Flask(__name__)
34
-
35
- class CommandExecutor:
36
- """Class to handle command execution with better timeout management"""
37
-
38
- def __init__(self, command: str, timeout: int = COMMAND_TIMEOUT):
39
- self.command = command
40
- self.timeout = timeout
41
- self.process = None
42
- self.stdout_data = ""
43
- self.stderr_data = ""
44
- self.stdout_thread = None
45
- self.stderr_thread = None
46
- self.return_code = None
47
- self.timed_out = False
48
-
49
- def _read_stdout(self):
50
- """Thread function to continuously read stdout"""
51
- for line in iter(self.process.stdout.readline, ''):
52
- self.stdout_data += line
53
-
54
- def _read_stderr(self):
55
- """Thread function to continuously read stderr"""
56
- for line in iter(self.process.stderr.readline, ''):
57
- self.stderr_data += line
58
-
59
- def execute(self) -> Dict[str, Any]:
60
- """Execute the command and handle timeout gracefully"""
61
- logger.info(f"Executing command: {self.command}")
62
-
63
- try:
64
- self.process = subprocess.Popen(
65
- self.command,
66
- shell=True,
67
- stdout=subprocess.PIPE,
68
- stderr=subprocess.PIPE,
69
- text=True,
70
- bufsize=1 # Line buffered
71
- )
72
-
73
- # Start threads to read output continuously
74
- self.stdout_thread = threading.Thread(target=self._read_stdout)
75
- self.stderr_thread = threading.Thread(target=self._read_stderr)
76
- self.stdout_thread.daemon = True
77
- self.stderr_thread.daemon = True
78
- self.stdout_thread.start()
79
- self.stderr_thread.start()
80
-
81
- # Wait for the process to complete or timeout
82
- try:
83
- self.return_code = self.process.wait(timeout=self.timeout)
84
- # Process completed, join the threads
85
- self.stdout_thread.join()
86
- self.stderr_thread.join()
87
- except subprocess.TimeoutExpired:
88
- # Process timed out but we might have partial results
89
- self.timed_out = True
90
- logger.warning(f"Command timed out after {self.timeout} seconds. Terminating process.")
91
-
92
- # Try to terminate gracefully first
93
- self.process.terminate()
94
- try:
95
- self.process.wait(timeout=5) # Give it 5 seconds to terminate
96
- except subprocess.TimeoutExpired:
97
- # Force kill if it doesn't terminate
98
- logger.warning("Process not responding to termination. Killing.")
99
- self.process.kill()
100
-
101
- # Update final output
102
- self.return_code = -1
103
-
104
- # Always consider it a success if we have output, even with timeout
105
- success = True if self.timed_out and (self.stdout_data or self.stderr_data) else (self.return_code == 0)
106
-
107
- return {
108
- "stdout": self.stdout_data,
109
- "stderr": self.stderr_data,
110
- "return_code": self.return_code,
111
- "success": success,
112
- "timed_out": self.timed_out,
113
- "partial_results": self.timed_out and (self.stdout_data or self.stderr_data)
114
- }
115
-
116
- except Exception as e:
117
- logger.error(f"Error executing command: {str(e)}")
118
- logger.error(traceback.format_exc())
119
- return {
120
- "stdout": self.stdout_data,
121
- "stderr": f"Error executing command: {str(e)}\n{self.stderr_data}",
122
- "return_code": -1,
123
- "success": False,
124
- "timed_out": False,
125
- "partial_results": bool(self.stdout_data or self.stderr_data)
126
- }
127
-
128
-
129
- def execute_command(command: str) -> Dict[str, Any]:
130
- """
131
- Execute a shell command and return the result
132
-
133
- Args:
134
- command: The command to execute
135
-
136
- Returns:
137
- A dictionary containing the stdout, stderr, and return code
138
- """
139
- executor = CommandExecutor(command)
140
- return executor.execute()
141
-
142
-
143
- @app.route("/api/command", methods=["POST"])
144
- def generic_command():
145
- """Execute any command provided in the request."""
146
- try:
147
- params = request.json
148
- command = params.get("command", "")
149
-
150
- if not command:
151
- logger.warning("Command endpoint called without command parameter")
152
- return jsonify({
153
- "error": "Command parameter is required"
154
- }), 400
155
-
156
- result = execute_command(command)
157
- return jsonify(result)
158
- except Exception as e:
159
- logger.error(f"Error in command endpoint: {str(e)}")
160
- logger.error(traceback.format_exc())
161
- return jsonify({
162
- "error": f"Server error: {str(e)}"
163
- }), 500
164
-
165
-
166
- @app.route("/api/tools/nmap", methods=["POST"])
167
- def nmap():
168
- """Execute nmap scan with the provided parameters."""
169
- try:
170
- params = request.json
171
- target = params.get("target", "")
172
- scan_type = params.get("scan_type", "-sCV")
173
- ports = params.get("ports", "")
174
- additional_args = params.get("additional_args", "-T4 -Pn")
175
-
176
- if not target:
177
- logger.warning("Nmap called without target parameter")
178
- return jsonify({
179
- "error": "Target parameter is required"
180
- }), 400
181
-
182
- command = f"nmap {scan_type}"
183
-
184
- if ports:
185
- command += f" -p {ports}"
186
-
187
- if additional_args:
188
- # Basic validation for additional args - more sophisticated validation would be better
189
- command += f" {additional_args}"
190
-
191
- command += f" {target}"
192
-
193
- result = execute_command(command)
194
- return jsonify(result)
195
- except Exception as e:
196
- logger.error(f"Error in nmap endpoint: {str(e)}")
197
- logger.error(traceback.format_exc())
198
- return jsonify({
199
- "error": f"Server error: {str(e)}"
200
- }), 500
201
-
202
- @app.route("/api/tools/gobuster", methods=["POST"])
203
- def gobuster():
204
- """Execute gobuster with the provided parameters."""
205
- try:
206
- params = request.json
207
- url = params.get("url", "")
208
- mode = params.get("mode", "dir")
209
- wordlist = params.get("wordlist", "/usr/share/wordlists/dirb/common.txt")
210
- additional_args = params.get("additional_args", "")
211
-
212
- if not url:
213
- logger.warning("Gobuster called without URL parameter")
214
- return jsonify({
215
- "error": "URL parameter is required"
216
- }), 400
217
-
218
- # Validate mode
219
- if mode not in ["dir", "dns", "fuzz", "vhost"]:
220
- logger.warning(f"Invalid gobuster mode: {mode}")
221
- return jsonify({
222
- "error": f"Invalid mode: {mode}. Must be one of: dir, dns, fuzz, vhost"
223
- }), 400
224
-
225
- command = f"gobuster {mode} -u {url} -w {wordlist}"
226
-
227
- if additional_args:
228
- command += f" {additional_args}"
229
-
230
- result = execute_command(command)
231
- return jsonify(result)
232
- except Exception as e:
233
- logger.error(f"Error in gobuster endpoint: {str(e)}")
234
- logger.error(traceback.format_exc())
235
- return jsonify({
236
- "error": f"Server error: {str(e)}"
237
- }), 500
238
-
239
- @app.route("/api/tools/dirb", methods=["POST"])
240
- def dirb():
241
- """Execute dirb with the provided parameters."""
242
- try:
243
- params = request.json
244
- url = params.get("url", "")
245
- wordlist = params.get("wordlist", "/usr/share/wordlists/dirb/common.txt")
246
- additional_args = params.get("additional_args", "")
247
-
248
- if not url:
249
- logger.warning("Dirb called without URL parameter")
250
- return jsonify({
251
- "error": "URL parameter is required"
252
- }), 400
253
-
254
- command = f"dirb {url} {wordlist}"
255
-
256
- if additional_args:
257
- command += f" {additional_args}"
258
-
259
- result = execute_command(command)
260
- return jsonify(result)
261
- except Exception as e:
262
- logger.error(f"Error in dirb endpoint: {str(e)}")
263
- logger.error(traceback.format_exc())
264
- return jsonify({
265
- "error": f"Server error: {str(e)}"
266
- }), 500
267
-
268
- @app.route("/api/tools/nikto", methods=["POST"])
269
- def nikto():
270
- """Execute nikto with the provided parameters."""
271
- try:
272
- params = request.json
273
- target = params.get("target", "")
274
- additional_args = params.get("additional_args", "")
275
-
276
- if not target:
277
- logger.warning("Nikto called without target parameter")
278
- return jsonify({
279
- "error": "Target parameter is required"
280
- }), 400
281
-
282
- command = f"nikto -h {target}"
283
-
284
- if additional_args:
285
- command += f" {additional_args}"
286
-
287
- result = execute_command(command)
288
- return jsonify(result)
289
- except Exception as e:
290
- logger.error(f"Error in nikto endpoint: {str(e)}")
291
- logger.error(traceback.format_exc())
292
- return jsonify({
293
- "error": f"Server error: {str(e)}"
294
- }), 500
295
-
296
- @app.route("/api/tools/sqlmap", methods=["POST"])
297
- def sqlmap():
298
- """Execute sqlmap with the provided parameters."""
299
- try:
300
- params = request.json
301
- url = params.get("url", "")
302
- data = params.get("data", "")
303
- additional_args = params.get("additional_args", "")
304
-
305
- if not url:
306
- logger.warning("SQLMap called without URL parameter")
307
- return jsonify({
308
- "error": "URL parameter is required"
309
- }), 400
310
-
311
- command = f"sqlmap -u {url} --batch"
312
-
313
- if data:
314
- command += f" --data=\"{data}\""
315
-
316
- if additional_args:
317
- command += f" {additional_args}"
318
-
319
- result = execute_command(command)
320
- return jsonify(result)
321
- except Exception as e:
322
- logger.error(f"Error in sqlmap endpoint: {str(e)}")
323
- logger.error(traceback.format_exc())
324
- return jsonify({
325
- "error": f"Server error: {str(e)}"
326
- }), 500
327
-
328
- @app.route("/api/tools/metasploit", methods=["POST"])
329
- def metasploit():
330
- """Execute metasploit module with the provided parameters."""
331
- try:
332
- params = request.json
333
- module = params.get("module", "")
334
- options = params.get("options", {})
335
-
336
- if not module:
337
- logger.warning("Metasploit called without module parameter")
338
- return jsonify({
339
- "error": "Module parameter is required"
340
- }), 400
341
-
342
- # Format options for Metasploit
343
- options_str = ""
344
- for key, value in options.items():
345
- options_str += f" {key}={value}"
346
-
347
- # Create an MSF resource script
348
- resource_content = f"use {module}\n"
349
- for key, value in options.items():
350
- resource_content += f"set {key} {value}\n"
351
- resource_content += "exploit\n"
352
-
353
- # Save resource script to a temporary file
354
- resource_file = "/tmp/mcp_msf_resource.rc"
355
- with open(resource_file, "w") as f:
356
- f.write(resource_content)
357
-
358
- command = f"msfconsole -q -r {resource_file}"
359
- result = execute_command(command)
360
-
361
- # Clean up the temporary file
362
- try:
363
- os.remove(resource_file)
364
- except Exception as e:
365
- logger.warning(f"Error removing temporary resource file: {str(e)}")
366
-
367
- return jsonify(result)
368
- except Exception as e:
369
- logger.error(f"Error in metasploit endpoint: {str(e)}")
370
- logger.error(traceback.format_exc())
371
- return jsonify({
372
- "error": f"Server error: {str(e)}"
373
- }), 500
374
-
375
- @app.route("/api/tools/hydra", methods=["POST"])
376
- def hydra():
377
- """Execute hydra with the provided parameters."""
378
- try:
379
- params = request.json
380
- target = params.get("target", "")
381
- service = params.get("service", "")
382
- username = params.get("username", "")
383
- username_file = params.get("username_file", "")
384
- password = params.get("password", "")
385
- password_file = params.get("password_file", "")
386
- additional_args = params.get("additional_args", "")
387
-
388
- if not target or not service:
389
- logger.warning("Hydra called without target or service parameter")
390
- return jsonify({
391
- "error": "Target and service parameters are required"
392
- }), 400
393
-
394
- if not (username or username_file) or not (password or password_file):
395
- logger.warning("Hydra called without username/password parameters")
396
- return jsonify({
397
- "error": "Username/username_file and password/password_file are required"
398
- }), 400
399
-
400
- command = f"hydra -t 4"
401
-
402
- if username:
403
- command += f" -l {username}"
404
- elif username_file:
405
- command += f" -L {username_file}"
406
-
407
- if password:
408
- command += f" -p {password}"
409
- elif password_file:
410
- command += f" -P {password_file}"
411
-
412
- if additional_args:
413
- command += f" {additional_args}"
414
-
415
- command += f" {target} {service}"
416
-
417
- result = execute_command(command)
418
- return jsonify(result)
419
- except Exception as e:
420
- logger.error(f"Error in hydra endpoint: {str(e)}")
421
- logger.error(traceback.format_exc())
422
- return jsonify({
423
- "error": f"Server error: {str(e)}"
424
- }), 500
425
-
426
- @app.route("/api/tools/john", methods=["POST"])
427
- def john():
428
- """Execute john with the provided parameters."""
429
- try:
430
- params = request.json
431
- hash_file = params.get("hash_file", "")
432
- wordlist = params.get("wordlist", "/usr/share/wordlists/rockyou.txt")
433
- format_type = params.get("format", "")
434
- additional_args = params.get("additional_args", "")
435
-
436
- if not hash_file:
437
- logger.warning("John called without hash_file parameter")
438
- return jsonify({
439
- "error": "Hash file parameter is required"
440
- }), 400
441
-
442
- command = f"john"
443
-
444
- if format_type:
445
- command += f" --format={format_type}"
446
-
447
- if wordlist:
448
- command += f" --wordlist={wordlist}"
449
-
450
- if additional_args:
451
- command += f" {additional_args}"
452
-
453
- command += f" {hash_file}"
454
-
455
- result = execute_command(command)
456
- return jsonify(result)
457
- except Exception as e:
458
- logger.error(f"Error in john endpoint: {str(e)}")
459
- logger.error(traceback.format_exc())
460
- return jsonify({
461
- "error": f"Server error: {str(e)}"
462
- }), 500
463
-
464
- @app.route("/api/tools/wpscan", methods=["POST"])
465
- def wpscan():
466
- """Execute wpscan with the provided parameters."""
467
- try:
468
- params = request.json
469
- url = params.get("url", "")
470
- additional_args = params.get("additional_args", "")
471
-
472
- if not url:
473
- logger.warning("WPScan called without URL parameter")
474
- return jsonify({
475
- "error": "URL parameter is required"
476
- }), 400
477
-
478
- command = f"wpscan --url {url}"
479
-
480
- if additional_args:
481
- command += f" {additional_args}"
482
-
483
- result = execute_command(command)
484
- return jsonify(result)
485
- except Exception as e:
486
- logger.error(f"Error in wpscan endpoint: {str(e)}")
487
- logger.error(traceback.format_exc())
488
- return jsonify({
489
- "error": f"Server error: {str(e)}"
490
- }), 500
491
-
492
- @app.route("/api/tools/enum4linux", methods=["POST"])
493
- def enum4linux():
494
- """Execute enum4linux with the provided parameters."""
495
- try:
496
- params = request.json
497
- target = params.get("target", "")
498
- additional_args = params.get("additional_args", "-a")
499
-
500
- if not target:
501
- logger.warning("Enum4linux called without target parameter")
502
- return jsonify({
503
- "error": "Target parameter is required"
504
- }), 400
505
-
506
- command = f"enum4linux {additional_args} {target}"
507
-
508
- result = execute_command(command)
509
- return jsonify(result)
510
- except Exception as e:
511
- logger.error(f"Error in enum4linux endpoint: {str(e)}")
512
- logger.error(traceback.format_exc())
513
- return jsonify({
514
- "error": f"Server error: {str(e)}"
515
- }), 500
516
-
517
- @app.route("/api/tools/aircrack", methods=["POST"])
518
- def aircrack():
519
- """Execute aircrack-ng with the provided parameters."""
520
- try:
521
- params = request.json
522
- capture_file = params.get("capture_file", "")
523
- additional_args = params.get("additional_args", "")
524
-
525
- if not capture_file:
526
- logger.warning("Aircrack called without capture_file parameter")
527
- return jsonify({
528
- "error": "Capture file parameter is required"
529
- }), 400
530
-
531
- command = f"aircrack-ng {additional_args} {capture_file}"
532
-
533
- result = execute_command(command)
534
- return jsonify(result)
535
- except Exception as e:
536
- logger.error(f"Error in aircrack endpoint: {str(e)}")
537
- logger.error(traceback.format_exc())
538
- return jsonify({
539
- "error": f"Server error: {str(e)}"
540
- }), 500
541
-
542
- @app.route("/api/tools/bettercap", methods=["POST"])
543
- def bettercap():
544
- """Execute bettercap with the provided parameters."""
545
- try:
546
- params = request.json
547
- interface = params.get("interface", "")
548
- script = params.get("script", "")
549
- additional_args = params.get("additional_args", "")
550
-
551
- command = "bettercap"
552
- if interface:
553
- command += f" -iface {interface}"
554
- if script:
555
- command += f" -script {script}"
556
- if additional_args:
557
- command += f" {additional_args}"
558
-
559
- result = execute_command(command)
560
- return jsonify(result)
561
- except Exception as e:
562
- logger.error(f"Error in bettercap endpoint: {str(e)}")
563
- logger.error(traceback.format_exc())
564
- return jsonify({
565
- "error": f"Server error: {str(e)}"
566
- }), 500
567
-
568
- @app.route("/api/tools/binwalk", methods=["POST"])
569
- def binwalk():
570
- """Execute binwalk with the provided parameters."""
571
- try:
572
- params = request.json
573
- target_file = params.get("target_file", "")
574
- additional_args = params.get("additional_args", "")
575
-
576
- if not target_file:
577
- logger.warning("Binwalk called without target_file parameter")
578
- return jsonify({
579
- "error": "Target file parameter is required"
580
- }), 400
581
-
582
- command = f"binwalk {additional_args} {target_file}"
583
-
584
- result = execute_command(command)
585
- return jsonify(result)
586
- except Exception as e:
587
- logger.error(f"Error in binwalk endpoint: {str(e)}")
588
- logger.error(traceback.format_exc())
589
- return jsonify({
590
- "error": f"Server error: {str(e)}"
591
- }), 500
592
-
593
- @app.route("/api/tools/dalfox", methods=["POST"])
594
- def dalfox():
595
- """Execute dalfox XSS scanner with the provided parameters."""
596
- try:
597
- params = request.json
598
- url = params.get("url", "")
599
- additional_args = params.get("additional_args", "")
600
-
601
- if not url:
602
- logger.warning("Dalfox called without URL parameter")
603
- return jsonify({
604
- "error": "URL parameter is required"
605
- }), 400
606
-
607
- command = f"dalfox url {url}"
608
- if additional_args:
609
- command += f" {additional_args}"
610
-
611
- result = execute_command(command)
612
- return jsonify(result)
613
- except Exception as e:
614
- logger.error(f"Error in dalfox endpoint: {str(e)}")
615
- logger.error(traceback.format_exc())
616
- return jsonify({
617
- "error": f"Server error: {str(e)}"
618
- }), 500
619
-
620
- @app.route("/api/tools/hashcat", methods=["POST"])
621
- def hashcat():
622
- """Execute hashcat with the provided parameters."""
623
- try:
624
- params = request.json
625
- hash_file = params.get("hash_file", "")
626
- attack_mode = params.get("attack_mode", "")
627
- additional_args = params.get("additional_args", "")
628
-
629
- if not hash_file:
630
- logger.warning("Hashcat called without hash_file parameter")
631
- return jsonify({
632
- "error": "Hash file parameter is required"
633
- }), 400
634
-
635
- command = f"hashcat {additional_args}"
636
- if attack_mode:
637
- command += f" -a {attack_mode}"
638
- command += f" {hash_file}"
639
-
640
- result = execute_command(command)
641
- return jsonify(result)
642
- except Exception as e:
643
- logger.error(f"Error in hashcat endpoint: {str(e)}")
644
- logger.error(traceback.format_exc())
645
- return jsonify({
646
- "error": f"Server error: {str(e)}"
647
- }), 500
648
-
649
- @app.route("/api/tools/impacket", methods=["POST"])
650
- def impacket():
651
- """Execute impacket tools with the provided parameters."""
652
- try:
653
- params = request.json
654
- tool = params.get("tool", "")
655
- target = params.get("target", "")
656
- additional_args = params.get("additional_args", "")
657
-
658
- if not tool:
659
- logger.warning("Impacket called without tool parameter")
660
- return jsonify({
661
- "error": "Tool parameter is required (e.g., GetNPUsers, secretsdump)"
662
- }), 400
663
-
664
- command = f"impacket-{tool}"
665
- if target:
666
- command += f" {target}"
667
- if additional_args:
668
- command += f" {additional_args}"
669
-
670
- result = execute_command(command)
671
- return jsonify(result)
672
- except Exception as e:
673
- logger.error(f"Error in impacket endpoint: {str(e)}")
674
- logger.error(traceback.format_exc())
675
- return jsonify({
676
- "error": f"Server error: {str(e)}"
677
- }), 500
678
-
679
- @app.route("/api/tools/masscan", methods=["POST"])
680
- def masscan():
681
- """Execute masscan with the provided parameters."""
682
- try:
683
- params = request.json
684
- target = params.get("target", "")
685
- ports = params.get("ports", "")
686
- rate = params.get("rate", "1000")
687
- additional_args = params.get("additional_args", "")
688
-
689
- if not target:
690
- logger.warning("Masscan called without target parameter")
691
- return jsonify({
692
- "error": "Target parameter is required"
693
- }), 400
694
-
695
- command = f"masscan --rate {rate}"
696
- if ports:
697
- command += f" -p{ports}"
698
- if additional_args:
699
- command += f" {additional_args}"
700
- command += f" {target}"
701
-
702
- result = execute_command(command)
703
- return jsonify(result)
704
- except Exception as e:
705
- logger.error(f"Error in masscan endpoint: {str(e)}")
706
- logger.error(traceback.format_exc())
707
- return jsonify({
708
- "error": f"Server error: {str(e)}"
709
- }), 500
710
-
711
- @app.route("/api/tools/radare2", methods=["POST"])
712
- def radare2():
713
- """Execute radare2 with the provided parameters."""
714
- try:
715
- params = request.json
716
- target_file = params.get("target_file", "")
717
- commands = params.get("commands", "")
718
- additional_args = params.get("additional_args", "")
719
-
720
- if not target_file:
721
- logger.warning("Radare2 called without target_file parameter")
722
- return jsonify({
723
- "error": "Target file parameter is required"
724
- }), 400
725
-
726
- command = f"r2 {additional_args} {target_file}"
727
- if commands:
728
- command += f" -c '{commands}'"
729
-
730
- result = execute_command(command)
731
- return jsonify(result)
732
- except Exception as e:
733
- logger.error(f"Error in radare2 endpoint: {str(e)}")
734
- logger.error(traceback.format_exc())
735
- return jsonify({
736
- "error": f"Server error: {str(e)}"
737
- }), 500
738
-
739
- @app.route("/api/tools/routersploit", methods=["POST"])
740
- def routersploit():
741
- """Execute routersploit with the provided parameters."""
742
- try:
743
- params = request.json
744
- target = params.get("target", "")
745
- module = params.get("module", "")
746
- additional_args = params.get("additional_args", "")
747
-
748
- command = "rsf.py"
749
- if target:
750
- command += f" -t {target}"
751
- if module:
752
- command += f" -m {module}"
753
- if additional_args:
754
- command += f" {additional_args}"
755
-
756
- result = execute_command(command)
757
- return jsonify(result)
758
- except Exception as e:
759
- logger.error(f"Error in routersploit endpoint: {str(e)}")
760
- logger.error(traceback.format_exc())
761
- return jsonify({
762
- "error": f"Server error: {str(e)}"
763
- }), 500
764
-
765
- @app.route("/api/tools/sherlock", methods=["POST"])
766
- def sherlock():
767
- """Execute sherlock username search with the provided parameters."""
768
- try:
769
- params = request.json
770
- username = params.get("username", "")
771
- additional_args = params.get("additional_args", "")
772
-
773
- if not username:
774
- logger.warning("Sherlock called without username parameter")
775
- return jsonify({
776
- "error": "Username parameter is required"
777
- }), 400
778
-
779
- command = f"sherlock {additional_args} {username}"
780
-
781
- result = execute_command(command)
782
- return jsonify(result)
783
- except Exception as e:
784
- logger.error(f"Error in sherlock endpoint: {str(e)}")
785
- logger.error(traceback.format_exc())
786
- return jsonify({
787
- "error": f"Server error: {str(e)}"
788
- }), 500
789
-
790
-
791
-
792
- @app.route("/api/tools/xsstrike", methods=["POST"])
793
- def xsstrike():
794
- """Execute XSStrike with the provided parameters."""
795
- try:
796
- params = request.json
797
- url = params.get("url", "")
798
- additional_args = params.get("additional_args", "")
799
-
800
- if not url:
801
- logger.warning("XSStrike called without URL parameter")
802
- return jsonify({
803
- "error": "URL parameter is required"
804
- }), 400
805
-
806
- command = f"python3 -m xsstrike {additional_args} -u {url}"
807
-
808
- result = execute_command(command)
809
- return jsonify(result)
810
- except Exception as e:
811
- logger.error(f"Error in xsstrike endpoint: {str(e)}")
812
- logger.error(traceback.format_exc())
813
- return jsonify({
814
- "error": f"Server error: {str(e)}"
815
- }), 500
816
-
817
- @app.route("/api/tools/zaproxy", methods=["POST"])
818
- def zaproxy():
819
- """Execute OWASP ZAP with the provided parameters."""
820
- try:
821
- params = request.json
822
- target = params.get("target", "")
823
- mode = params.get("mode", "daemon")
824
- additional_args = params.get("additional_args", "")
825
-
826
- command = f"zaproxy -{mode}"
827
- if target:
828
- command += f" -cmd -quickurl {target}"
829
- if additional_args:
830
- command += f" {additional_args}"
831
-
832
- result = execute_command(command)
833
- return jsonify(result)
834
- except Exception as e:
835
- logger.error(f"Error in zaproxy endpoint: {str(e)}")
836
- logger.error(traceback.format_exc())
837
- return jsonify({
838
- "error": f"Server error: {str(e)}"
839
- }), 500
840
-
841
-
842
- # Health check endpoint
843
- @app.route("/health", methods=["GET"])
844
- def health_check():
845
- """Health check endpoint."""
846
- # Check if essential tools are installed
847
- essential_tools = ["nmap", "gobuster", "dirb", "nikto"]
848
- tools_status = {}
849
-
850
- for tool in essential_tools:
851
- try:
852
- result = execute_command(f"which {tool}")
853
- tools_status[tool] = result["success"]
854
- except:
855
- tools_status[tool] = False
856
-
857
- all_essential_tools_available = all(tools_status.values())
858
-
859
- return jsonify({
860
- "status": "healthy",
861
- "message": "Kali Linux Tools API Server is running",
862
- "tools_status": tools_status,
863
- "all_essential_tools_available": all_essential_tools_available
864
- })
865
-
866
- @app.route("/mcp/capabilities", methods=["GET"])
867
- def get_capabilities():
868
- """Return MCP tool capabilities"""
869
- tools = [
870
- {
871
- "name": "nmap_scan",
872
- "description": "Execute Nmap network scanning tool",
873
- "parameters": {
874
- "type": "object",
875
- "properties": {
876
- "target": {"type": "string", "description": "Target IP or hostname"},
877
- "scan_type": {"type": "string", "default": "-sV"},
878
- "ports": {"type": "string", "default": ""},
879
- "additional_args": {"type": "string", "default": ""}
880
- },
881
- "required": ["target"]
882
- }
883
- },
884
- {
885
- "name": "gobuster_scan",
886
- "description": "Execute Gobuster directory/file/dns scanner",
887
- "parameters": {
888
- "type": "object",
889
- "properties": {
890
- "url": {"type": "string", "description": "Target URL"},
891
- "mode": {"type": "string", "enum": ["dir", "dns", "fuzz", "vhost"], "default": "dir"},
892
- "wordlist": {"type": "string", "default": "/usr/share/wordlists/dirb/common.txt"},
893
- "additional_args": {"type": "string", "default": ""}
894
- },
895
- "required": ["url"]
896
- }
897
- },
898
- {
899
- "name": "dirb_scan",
900
- "description": "Execute Dirb web content scanner",
901
- "parameters": {
902
- "type": "object",
903
- "properties": {
904
- "url": {"type": "string", "description": "Target URL"},
905
- "wordlist": {"type": "string", "default": "/usr/share/wordlists/dirb/common.txt"},
906
- "additional_args": {"type": "string", "default": ""}
907
- },
908
- "required": ["url"]
909
- }
910
- },
911
- {
912
- "name": "nikto_scan",
913
- "description": "Execute Nikto web server scanner",
914
- "parameters": {
915
- "type": "object",
916
- "properties": {
917
- "target": {"type": "string", "description": "Target URL or IP"},
918
- "additional_args": {"type": "string", "default": ""}
919
- },
920
- "required": ["target"]
921
- }
922
- },
923
- {
924
- "name": "sqlmap_scan",
925
- "description": "Execute SQLmap SQL injection scanner",
926
- "parameters": {
927
- "type": "object",
928
- "properties": {
929
- "url": {"type": "string", "description": "Target URL"},
930
- "data": {"type": "string", "default": ""},
931
- "additional_args": {"type": "string", "default": ""}
932
- },
933
- "required": ["url"]
934
- }
935
- },
936
- {
937
- "name": "metasploit_run",
938
- "description": "Execute Metasploit module",
939
- "parameters": {
940
- "type": "object",
941
- "properties": {
942
- "module": {"type": "string", "description": "Metasploit module path"},
943
- "options": {"type": "object", "default": {}}
944
- },
945
- "required": ["module"]
946
- }
947
- },
948
- {
949
- "name": "hydra_attack",
950
- "description": "Execute Hydra password cracking tool",
951
- "parameters": {
952
- "type": "object",
953
- "properties": {
954
- "target": {"type": "string", "description": "Target IP or hostname"},
955
- "service": {"type": "string", "description": "Service to attack"},
956
- "username": {"type": "string", "default": ""},
957
- "username_file": {"type": "string", "default": ""},
958
- "password": {"type": "string", "default": ""},
959
- "password_file": {"type": "string", "default": ""},
960
- "additional_args": {"type": "string", "default": ""}
961
- },
962
- "required": ["target", "service"]
963
- }
964
- },
965
- {
966
- "name": "john_crack",
967
- "description": "Execute John the Ripper password cracker",
968
- "parameters": {
969
- "type": "object",
970
- "properties": {
971
- "hash_file": {"type": "string", "description": "Path to hash file"},
972
- "wordlist": {"type": "string", "default": "/usr/share/wordlists/rockyou.txt"},
973
- "format_type": {"type": "string", "default": ""},
974
- "additional_args": {"type": "string", "default": ""}
975
- },
976
- "required": ["hash_file"]
977
- }
978
- },
979
- {
980
- "name": "wpscan_analyze",
981
- "description": "Execute WPScan WordPress vulnerability scanner",
982
- "parameters": {
983
- "type": "object",
984
- "properties": {
985
- "url": {"type": "string", "description": "WordPress URL"},
986
- "additional_args": {"type": "string", "default": ""}
987
- },
988
- "required": ["url"]
989
- }
990
- },
991
- {
992
- "name": "enum4linux_scan",
993
- "description": "Execute Enum4linux Windows/Samba enumeration tool",
994
- "parameters": {
995
- "type": "object",
996
- "properties": {
997
- "target": {"type": "string", "description": "Target IP or hostname"},
998
- "additional_args": {"type": "string", "default": "-a"}
999
- },
1000
- "required": ["target"]
1001
- }
1002
- },
1003
- {
1004
- "name": "aircrack_scan",
1005
- "description": "Execute Aircrack-ng wireless network cracking tool",
1006
- "parameters": {
1007
- "type": "object",
1008
- "properties": {
1009
- "capture_file": {"type": "string", "description": "Path to capture file"},
1010
- "additional_args": {"type": "string", "default": ""}
1011
- },
1012
- "required": ["capture_file"]
1013
- }
1014
- },
1015
- {
1016
- "name": "bettercap_run",
1017
- "description": "Execute Bettercap network MITM tool",
1018
- "parameters": {
1019
- "type": "object",
1020
- "properties": {
1021
- "interface": {"type": "string", "default": ""},
1022
- "script": {"type": "string", "default": ""},
1023
- "additional_args": {"type": "string", "default": ""}
1024
- }
1025
- }
1026
- },
1027
- {
1028
- "name": "binwalk_analyze",
1029
- "description": "Execute Binwalk firmware analysis tool",
1030
- "parameters": {
1031
- "type": "object",
1032
- "properties": {
1033
- "target_file": {"type": "string", "description": "File to analyze"},
1034
- "additional_args": {"type": "string", "default": ""}
1035
- },
1036
- "required": ["target_file"]
1037
- }
1038
- },
1039
- {
1040
- "name": "dalfox_scan",
1041
- "description": "Execute Dalfox XSS vulnerability scanner",
1042
- "parameters": {
1043
- "type": "object",
1044
- "properties": {
1045
- "url": {"type": "string", "description": "Target URL"},
1046
- "additional_args": {"type": "string", "default": ""}
1047
- },
1048
- "required": ["url"]
1049
- }
1050
- },
1051
- {
1052
- "name": "hashcat_crack",
1053
- "description": "Execute Hashcat password cracking tool",
1054
- "parameters": {
1055
- "type": "object",
1056
- "properties": {
1057
- "hash_file": {"type": "string", "description": "Path to hash file"},
1058
- "attack_mode": {"type": "string", "default": ""},
1059
- "additional_args": {"type": "string", "default": ""}
1060
- },
1061
- "required": ["hash_file"]
1062
- }
1063
- },
1064
- {
1065
- "name": "impacket_run",
1066
- "description": "Execute Impacket Windows protocol tools",
1067
- "parameters": {
1068
- "type": "object",
1069
- "properties": {
1070
- "tool": {"type": "string", "description": "Impacket tool name"},
1071
- "target": {"type": "string", "default": ""},
1072
- "additional_args": {"type": "string", "default": ""}
1073
- },
1074
- "required": ["tool"]
1075
- }
1076
- },
1077
- {
1078
- "name": "masscan_scan",
1079
- "description": "Execute Masscan fast port scanner",
1080
- "parameters": {
1081
- "type": "object",
1082
- "properties": {
1083
- "target": {"type": "string", "description": "Target IP/range"},
1084
- "ports": {"type": "string", "default": ""},
1085
- "rate": {"type": "string", "default": "1000"},
1086
- "additional_args": {"type": "string", "default": ""}
1087
- },
1088
- "required": ["target"]
1089
- }
1090
- },
1091
- {
1092
- "name": "radare2_analyze",
1093
- "description": "Execute Radare2 reverse engineering framework",
1094
- "parameters": {
1095
- "type": "object",
1096
- "properties": {
1097
- "target_file": {"type": "string", "description": "Binary file"},
1098
- "commands": {"type": "string", "default": ""},
1099
- "additional_args": {"type": "string", "default": ""}
1100
- },
1101
- "required": ["target_file"]
1102
- }
1103
- },
1104
- {
1105
- "name": "routersploit_scan",
1106
- "description": "Execute RouterSploit router exploitation framework",
1107
- "parameters": {
1108
- "type": "object",
1109
- "properties": {
1110
- "target": {"type": "string", "default": ""},
1111
- "module": {"type": "string", "default": ""},
1112
- "additional_args": {"type": "string", "default": ""}
1113
- }
1114
- }
1115
- },
1116
- {
1117
- "name": "sherlock_search",
1118
- "description": "Execute Sherlock username enumeration tool",
1119
- "parameters": {
1120
- "type": "object",
1121
- "properties": {
1122
- "username": {"type": "string", "description": "Username to search"},
1123
- "additional_args": {"type": "string", "default": ""}
1124
- },
1125
- "required": ["username"]
1126
- }
1127
- },
1128
-
1129
- {
1130
- "name": "xsstrike_scan",
1131
- "description": "Execute XSStrike XSS vulnerability scanner",
1132
- "parameters": {
1133
- "type": "object",
1134
- "properties": {
1135
- "url": {"type": "string", "description": "Target URL"},
1136
- "additional_args": {"type": "string", "default": ""}
1137
- },
1138
- "required": ["url"]
1139
- }
1140
- },
1141
- {
1142
- "name": "zaproxy_scan",
1143
- "description": "Execute OWASP ZAP web application scanner",
1144
- "parameters": {
1145
- "type": "object",
1146
- "properties": {
1147
- "target": {"type": "string", "default": ""},
1148
- "mode": {"type": "string", "default": "daemon"},
1149
- "additional_args": {"type": "string", "default": ""}
1150
- }
1151
- }
1152
- },
1153
- {
1154
- "name": "execute_command",
1155
- "description": "Execute arbitrary commands on Kali Linux",
1156
- "parameters": {
1157
- "type": "object",
1158
- "properties": {
1159
- "command": {"type": "string", "description": "Command to execute"}
1160
- },
1161
- "required": ["command"]
1162
- }
1163
- },
1164
- {
1165
- "name": "server_health",
1166
- "description": "Check server health and tool availability",
1167
- "parameters": {"type": "object", "properties": {}}
1168
- }
1169
- ]
1170
-
1171
- return jsonify({
1172
- "tools": tools,
1173
- "version": "1.0.0"
1174
- })
1175
-
1176
- @app.route("/mcp/tools/kali_tools/<tool_name>", methods=["POST"])
1177
- def execute_tool(tool_name):
1178
- """Execute MCP tools directly"""
1179
- try:
1180
- params = request.json
1181
- tool_name = tool_name.lower()
1182
-
1183
- # Map tool names to their functions
1184
- tool_map = {
1185
- "nmap_scan": nmap,
1186
- "gobuster_scan": gobuster,
1187
- "dirb_scan": dirb,
1188
- "nikto_scan": nikto,
1189
- "sqlmap_scan": sqlmap,
1190
- "metasploit_run": metasploit,
1191
- "hydra_attack": hydra,
1192
- "john_crack": john,
1193
- "wpscan_analyze": wpscan,
1194
- "enum4linux_scan": enum4linux,
1195
- "aircrack_scan": aircrack,
1196
- "bettercap_run": bettercap,
1197
- "binwalk_analyze": binwalk,
1198
- "dalfox_scan": dalfox,
1199
- "hashcat_crack": hashcat,
1200
- "impacket_run": impacket,
1201
- "masscan_scan": masscan,
1202
- "radare2_analyze": radare2,
1203
- "routersploit_scan": routersploit,
1204
- "sherlock_search": sherlock,
1205
- "xsstrike_scan": xsstrike,
1206
- "zaproxy_scan": zaproxy,
1207
- "execute_command": generic_command,
1208
- "server_health": health_check
1209
- }
1210
-
1211
- if tool_name in tool_map:
1212
- return tool_map[tool_name]()
1213
- else:
1214
- return jsonify({"error": f"Unknown tool: {tool_name}"}), 404
1215
-
1216
- except Exception as e:
1217
- logger.error(f"Error executing MCP tool {tool_name}: {str(e)}")
1218
- return jsonify({"error": f"Tool execution failed: {str(e)}"}), 500
1219
-
1220
- def parse_args():
1221
- """Parse command line arguments."""
1222
- parser = argparse.ArgumentParser(description="Run the Kali Linux API Server")
1223
- parser.add_argument("--debug", action="store_true", help="Enable debug mode")
1224
- parser.add_argument("--port", type=int, default=API_PORT, help=f"Port for the API server (default: {API_PORT})")
1225
- return parser.parse_args()
1226
-
1227
- if __name__ == "__main__":
1228
- args = parse_args()
1229
-
1230
- # Set configuration from command line arguments
1231
- if args.debug:
1232
- DEBUG_MODE = True
1233
- os.environ["DEBUG_MODE"] = "1"
1234
- logger.setLevel(logging.DEBUG)
1235
-
1236
- if args.port != API_PORT:
1237
- API_PORT = args.port
1238
-
1239
- logger.info(f"Starting Kali Linux Tools API Server on port {API_PORT}")
1240
- app.run(host="0.0.0.0", port=API_PORT, debug=DEBUG_MODE)