Files
dark_hal/pentestgpt.py
2026-03-13 12:56:43 -07:00

301 lines
14 KiB
Python

#!/usr/bin/env python3
"""
PentestGPT Tab Implementation
Handles the PentestGPT interface and controls for DarkHal 2.0
"""
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
from pathlib import Path
import subprocess
import threading
class PentestGPTTab:
"""PentestGPT tab with penetration testing agent controls."""
def __init__(self, parent: ttk.Frame, settings_manager, main_app=None):
self.parent = parent
self.settings = settings_manager
self.main_app = main_app
self.pentestgpt_process = None
# Create main frame
self.main_frame = ttk.Frame(parent)
self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# Create PentestGPT interface
self._create_pentestgpt_interface()
def _create_pentestgpt_interface(self):
"""Create PentestGPT control and configuration interface."""
# PentestGPT configuration frame
config_frame = ttk.LabelFrame(self.main_frame, text="PentestGPT Configuration", padding=10)
config_frame.pack(fill=tk.X, pady=(0, 10))
# Configuration options
options_frame = ttk.Frame(config_frame)
options_frame.pack(fill=tk.X, pady=10)
# Model selection
ttk.Label(options_frame, text="Model:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.pentestgpt_model_var = tk.StringVar(value="gpt-4")
model_combo = ttk.Combobox(options_frame, textvariable=self.pentestgpt_model_var,
values=["gpt-4", "gpt-3.5-turbo", "claude-3", "local-llm"], width=15)
model_combo.grid(row=0, column=1, padx=10)
# Target type
ttk.Label(options_frame, text="Target Type:").grid(row=0, column=2, sticky=tk.W, padx=(20, 0))
self.target_type_var = tk.StringVar(value="web")
target_combo = ttk.Combobox(options_frame, textvariable=self.target_type_var,
values=["web", "network", "mobile", "cloud", "iot"], width=15)
target_combo.grid(row=0, column=3, padx=10)
# Scan depth
ttk.Label(options_frame, text="Scan Depth:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.scan_depth_var = tk.StringVar(value="medium")
depth_combo = ttk.Combobox(options_frame, textvariable=self.scan_depth_var,
values=["light", "medium", "deep", "comprehensive"], width=15)
depth_combo.grid(row=1, column=1, padx=10)
# Output directory
ttk.Label(options_frame, text="Output Dir:").grid(row=1, column=2, sticky=tk.W, padx=(20, 0))
self.output_dir_var = tk.StringVar(value="./pentest_results")
ttk.Entry(options_frame, textvariable=self.output_dir_var, width=25).grid(row=1, column=3, padx=(10, 5))
ttk.Button(options_frame, text="Browse", command=self._browse_output_dir).grid(row=1, column=4, padx=5)
# API Configuration
api_frame = ttk.LabelFrame(config_frame, text="API Configuration", padding=5)
api_frame.pack(fill=tk.X, pady=(0, 10))
# OpenAI API Key
ttk.Label(api_frame, text="OpenAI API Key:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.openai_key_var = tk.StringVar()
ttk.Entry(api_frame, textvariable=self.openai_key_var, show="*", width=40).grid(row=0, column=1, padx=10)
# Claude API Key
ttk.Label(api_frame, text="Claude API Key:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.claude_key_var = tk.StringVar()
ttk.Entry(api_frame, textvariable=self.claude_key_var, show="*", width=40).grid(row=1, column=1, padx=10)
# Control buttons
control_frame = ttk.Frame(config_frame)
control_frame.pack(fill=tk.X, pady=10)
self.pentestgpt_start_btn = ttk.Button(control_frame, text="Start PentestGPT",
command=self._start_pentestgpt)
self.pentestgpt_start_btn.pack(side=tk.LEFT, padx=5)
self.pentestgpt_stop_btn = ttk.Button(control_frame, text="Stop PentestGPT",
command=self._stop_pentestgpt, state="disabled")
self.pentestgpt_stop_btn.pack(side=tk.LEFT, padx=5)
# Configuration management
config_btn_frame = ttk.Frame(control_frame)
config_btn_frame.pack(side=tk.RIGHT, padx=5)
ttk.Button(config_btn_frame, text="Save Config",
command=self._save_pentestgpt_config).pack(side=tk.LEFT, padx=2)
ttk.Button(config_btn_frame, text="Load Config",
command=self._load_pentestgpt_config).pack(side=tk.LEFT, padx=2)
ttk.Button(config_btn_frame, text="Configure",
command=self._configure_pentestgpt).pack(side=tk.LEFT, padx=2)
# Output area
output_frame = ttk.LabelFrame(self.main_frame, text="PentestGPT Output", padding=10)
output_frame.pack(fill=tk.BOTH, expand=True, pady=10)
self.pentestgpt_output = tk.Text(output_frame, height=20, wrap=tk.WORD)
pentestgpt_scrollbar = ttk.Scrollbar(output_frame, orient=tk.VERTICAL, command=self.pentestgpt_output.yview)
self.pentestgpt_output.configure(yscrollcommand=pentestgpt_scrollbar.set)
self.pentestgpt_output.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
pentestgpt_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# Status bar
self.pentestgpt_status_var = tk.StringVar(value="PentestGPT Status: Ready")
ttk.Label(output_frame, textvariable=self.pentestgpt_status_var).pack(anchor=tk.W, pady=(5, 0))
def _start_pentestgpt(self):
"""Start PentestGPT process."""
self.pentestgpt_output.insert(tk.END, "Starting PentestGPT...\n")
self.pentestgpt_output.insert(tk.END, f"Model: {self.pentestgpt_model_var.get()}\n")
self.pentestgpt_output.insert(tk.END, f"Target Type: {self.target_type_var.get()}\n")
self.pentestgpt_output.insert(tk.END, f"Scan Depth: {self.scan_depth_var.get()}\n\n")
# Check if PentestGPT is available
pentestgpt_path = Path("experimental_agent/PentestGPT")
if not pentestgpt_path.exists():
self.pentestgpt_output.insert(tk.END, "Error: PentestGPT not found in experimental_agent directory\n")
self.pentestgpt_status_var.set("PentestGPT Status: Error - Not Found")
return
# This would start the actual PentestGPT process
# For now, we'll simulate the startup
self.pentestgpt_output.insert(tk.END, "PentestGPT started successfully!\n")
self.pentestgpt_output.insert(tk.END, "Ready for penetration testing commands...\n\n")
# Update button states
self.pentestgpt_start_btn.config(state="disabled")
self.pentestgpt_stop_btn.config(state="normal")
self.pentestgpt_status_var.set("PentestGPT Status: Running")
def _stop_pentestgpt(self):
"""Stop PentestGPT process."""
if self.pentestgpt_process:
self.pentestgpt_process.terminate()
self.pentestgpt_process = None
self.pentestgpt_output.insert(tk.END, "PentestGPT stopped.\n\n")
# Update button states
self.pentestgpt_start_btn.config(state="normal")
self.pentestgpt_stop_btn.config(state="disabled")
self.pentestgpt_status_var.set("PentestGPT Status: Stopped")
def _browse_output_dir(self):
"""Browse for output directory."""
directory = filedialog.askdirectory()
if directory:
self.output_dir_var.set(directory)
def _save_pentestgpt_config(self):
"""Save PentestGPT configuration."""
config = {
"model": self.pentestgpt_model_var.get(),
"target_type": self.target_type_var.get(),
"scan_depth": self.scan_depth_var.get(),
"output_dir": self.output_dir_var.get(),
"openai_key": self.openai_key_var.get(),
"claude_key": self.claude_key_var.get()
}
try:
config_file = Path("pentestgpt_config.json")
import json
with open(config_file, 'w') as f:
json.dump(config, f, indent=2)
self.pentestgpt_output.insert(tk.END, f"Configuration saved to {config_file}\n")
except Exception as e:
messagebox.showerror("Save Error", f"Failed to save configuration: {str(e)}")
def _load_pentestgpt_config(self):
"""Load PentestGPT configuration."""
try:
config_file = Path("pentestgpt_config.json")
if not config_file.exists():
messagebox.showwarning("Load Error", "No configuration file found")
return
import json
with open(config_file, 'r') as f:
config = json.load(f)
# Apply configuration
self.pentestgpt_model_var.set(config.get("model", "gpt-4"))
self.target_type_var.set(config.get("target_type", "web"))
self.scan_depth_var.set(config.get("scan_depth", "medium"))
self.output_dir_var.set(config.get("output_dir", "./pentest_results"))
self.openai_key_var.set(config.get("openai_key", ""))
self.claude_key_var.set(config.get("claude_key", ""))
self.pentestgpt_output.insert(tk.END, f"Configuration loaded from {config_file}\n")
except Exception as e:
messagebox.showerror("Load Error", f"Failed to load configuration: {str(e)}")
def _configure_pentestgpt(self):
"""Open PentestGPT configuration dialog."""
PentestGPTConfigDialog(self.parent, self)
class PentestGPTConfigDialog:
"""Dialog for configuring PentestGPT API keys and settings."""
def __init__(self, parent, pentestgpt_tab):
self.pentestgpt_tab = pentestgpt_tab
self.dialog = tk.Toplevel(parent)
self.dialog.title("PentestGPT Configuration")
self.dialog.geometry("500x400")
self.dialog.transient(parent)
self.dialog.grab_set()
# Create configuration interface
self._create_config_interface()
# Center dialog
self.dialog.update_idletasks()
x = (self.dialog.winfo_screenwidth() // 2) - (self.dialog.winfo_width() // 2)
y = (self.dialog.winfo_screenheight() // 2) - (self.dialog.winfo_height() // 2)
self.dialog.geometry(f"+{x}+{y}")
def _create_config_interface(self):
"""Create the configuration interface."""
main_frame = ttk.Frame(self.dialog)
main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
# API Keys section
api_frame = ttk.LabelFrame(main_frame, text="API Configuration", padding=10)
api_frame.pack(fill=tk.X, pady=(0, 20))
# OpenAI API Key
ttk.Label(api_frame, text="OpenAI API Key:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.openai_entry = ttk.Entry(api_frame, show="*", width=40)
self.openai_entry.grid(row=0, column=1, padx=(10, 0), pady=5)
self.openai_entry.insert(0, self.pentestgpt_tab.openai_key_var.get())
# Claude API Key
ttk.Label(api_frame, text="Claude API Key:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.claude_entry = ttk.Entry(api_frame, show="*", width=40)
self.claude_entry.grid(row=1, column=1, padx=(10, 0), pady=5)
self.claude_entry.insert(0, self.pentestgpt_tab.claude_key_var.get())
# Advanced Settings section
advanced_frame = ttk.LabelFrame(main_frame, text="Advanced Settings", padding=10)
advanced_frame.pack(fill=tk.X, pady=(0, 20))
# Max concurrent scans
ttk.Label(advanced_frame, text="Max Concurrent Scans:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.max_scans_var = tk.StringVar(value="3")
ttk.Entry(advanced_frame, textvariable=self.max_scans_var, width=10).grid(row=0, column=1, padx=(10, 0), pady=5)
# Timeout settings
ttk.Label(advanced_frame, text="Request Timeout (s):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.timeout_var = tk.StringVar(value="30")
ttk.Entry(advanced_frame, textvariable=self.timeout_var, width=10).grid(row=1, column=1, padx=(10, 0), pady=5)
# Buttons
button_frame = ttk.Frame(main_frame)
button_frame.pack(fill=tk.X, pady=(20, 0))
ttk.Button(button_frame, text="Save", command=self._save_config).pack(side=tk.RIGHT, padx=(10, 0))
ttk.Button(button_frame, text="Cancel", command=self._cancel).pack(side=tk.RIGHT)
def _save_config(self):
"""Save the configuration."""
try:
# Update the main tab variables
self.pentestgpt_tab.openai_key_var.set(self.openai_entry.get())
self.pentestgpt_tab.claude_key_var.set(self.claude_entry.get())
# Save to file
config = {
"openai_key": self.openai_entry.get(),
"claude_key": self.claude_entry.get(),
"max_scans": self.max_scans_var.get(),
"timeout": self.timeout_var.get()
}
import json
config_file = Path("pentestgpt_advanced_config.json")
with open(config_file, 'w') as f:
json.dump(config, f, indent=2)
messagebox.showinfo("Success", "Configuration saved successfully!")
self.dialog.destroy()
except Exception as e:
messagebox.showerror("Save Error", f"Failed to save configuration: {str(e)}")
def _cancel(self):
"""Cancel the configuration dialog."""
self.dialog.destroy()