Compare commits
10 commits
52f654dd32
...
1413c05860
| Author | SHA1 | Date | |
|---|---|---|---|
| 1413c05860 | |||
| a2fa5c3ae9 | |||
| 0ff4c87123 | |||
| 37cfb017f0 | |||
|
|
2006ba5a45 | ||
| 37085d853a | |||
| c4f40e79c8 | |||
| bb18a5c070 | |||
| 5bc00b9643 | |||
| a210803453 |
61
README.md
|
|
@ -1,5 +1,9 @@
|
||||||
# Djedi Toolbelt v2.0
|
# Djedi Toolbelt v2.0
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/toolbelt.png" alt="Djedi Toolbelt" width="500">
|
||||||
|
</p>
|
||||||
|
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://www.python.org/)
|
[](https://www.python.org/)
|
||||||
|
|
||||||
|
|
@ -43,6 +47,8 @@ python3 toolbelt.py
|
||||||
- Browse & Select Categories
|
- Browse & Select Categories
|
||||||
- Install Prerequisites (fresh)
|
- Install Prerequisites (fresh)
|
||||||
- View Installed Tools
|
- View Installed Tools
|
||||||
|
- Check for Tool Updates
|
||||||
|
- Manage Wordlists
|
||||||
|
|
||||||
**Level 2 - Categories:**
|
**Level 2 - Categories:**
|
||||||
- 📦 APT Tools - Package manager tools
|
- 📦 APT Tools - Package manager tools
|
||||||
|
|
@ -54,7 +60,18 @@ python3 toolbelt.py
|
||||||
|
|
||||||
**Level 3 - Tool Selection:**
|
**Level 3 - Tool Selection:**
|
||||||
- Install all tools in category
|
- Install all tools in category
|
||||||
- Individual tool selection (coming soon)
|
- Individual tool selection (gum multi-select)
|
||||||
|
|
||||||
|
**Tool Update Management:**
|
||||||
|
- Check versions of installed tools
|
||||||
|
- Update all ProjectDiscovery tools (pdtm)
|
||||||
|
- Update all Go tools to @latest
|
||||||
|
- Select individual tools to update (gum multi-select)
|
||||||
|
|
||||||
|
**Wordlist Management:**
|
||||||
|
- Install SecLists (comprehensive wordlist collection)
|
||||||
|
- View installed wordlists and directory structure
|
||||||
|
- Update SecLists from GitHub
|
||||||
|
|
||||||
### Pre-Built Profiles
|
### Pre-Built Profiles
|
||||||
|
|
||||||
|
|
@ -126,7 +143,7 @@ wfuzz, arjun, scrapy, tld, requests, fuzzywuzzy
|
||||||
**RustScan** - Fast port scanner
|
**RustScan** - Fast port scanner
|
||||||
- Includes alias setup for shell
|
- Includes alias setup for shell
|
||||||
|
|
||||||
### Useful Scripts (downloaded to ~/scripts)
|
### Useful Scripts (downloaded to ~/scripts/payloads)
|
||||||
|
|
||||||
- **linpeas.sh** - Linux privilege escalation
|
- **linpeas.sh** - Linux privilege escalation
|
||||||
- **jaws-enum.ps1** - Windows enumeration
|
- **jaws-enum.ps1** - Windows enumeration
|
||||||
|
|
@ -190,6 +207,46 @@ python3 toolbelt.py
|
||||||
# Select: 4) View Installed Tools
|
# Select: 4) View Installed Tools
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Update Tools
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 toolbelt.py
|
||||||
|
# Select: 5) Check for Tool Updates
|
||||||
|
|
||||||
|
# Option 1: Check versions only (see what's outdated)
|
||||||
|
# Option 2: Update all ProjectDiscovery tools (pdtm -ua)
|
||||||
|
# Option 3: Update all Go tools to @latest
|
||||||
|
# Option 4: Select specific tools to update (gum multi-select)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Update strategies:**
|
||||||
|
- **Fast PD Update:** Option 2 uses `pdtm` for lightning-fast ProjectDiscovery tool updates
|
||||||
|
- **Comprehensive Update:** Option 3 updates ALL Go tools (PD + non-PD)
|
||||||
|
- **Selective Update:** Option 4 lets you cherry-pick which tools to update
|
||||||
|
|
||||||
|
### Manage Wordlists
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 toolbelt.py
|
||||||
|
# Select: 6) Manage Wordlists
|
||||||
|
|
||||||
|
# Option 1: Install SecLists (~500MB)
|
||||||
|
# Option 2: View installed wordlists and structure
|
||||||
|
# Option 3: Update SecLists from GitHub
|
||||||
|
```
|
||||||
|
|
||||||
|
**SecLists includes:**
|
||||||
|
- **Passwords**: rockyou, common passwords, leaked databases
|
||||||
|
- **Usernames**: Common usernames and names
|
||||||
|
- **Subdomains**: DNS enumeration wordlists
|
||||||
|
- **Directories**: Web content discovery lists
|
||||||
|
- **Fuzzing**: XSS, SQLi, and other injection payloads
|
||||||
|
|
||||||
|
**Installation locations:**
|
||||||
|
- Kali default: `/usr/share/seclists` (via apt package)
|
||||||
|
- Custom install: `~/wordlists/SecLists/` (via git clone)
|
||||||
|
- Toolbelt automatically detects both locations
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔗 Integration with Fresh
|
## 🔗 Integration with Fresh
|
||||||
|
|
|
||||||
6
TODO.md
|
|
@ -312,10 +312,10 @@ def download_with_progress(url: str, output: str):
|
||||||
|
|
||||||
## Implementation Priority
|
## Implementation Priority
|
||||||
|
|
||||||
**v2.1 (Next Release):**
|
**v2.1 (COMPLETE):**
|
||||||
1. Individual Tool Selection (gum multi-select) ✅ **COMPLETED**
|
1. Individual Tool Selection (gum multi-select) ✅ **COMPLETED**
|
||||||
2. Tool Update Detection 🔜
|
2. Tool Update Detection ✅ **COMPLETED**
|
||||||
3. Wordlist Management 🔜
|
3. Wordlist Management ✅ **COMPLETED**
|
||||||
|
|
||||||
**v2.2:**
|
**v2.2:**
|
||||||
4. Resource Monitoring
|
4. Resource Monitoring
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ DOCKER_TOOLS = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Useful Scripts - Downloaded to ~/scripts
|
# Useful Scripts - Downloaded to ~/scripts/payloads
|
||||||
USEFUL_SCRIPTS = {
|
USEFUL_SCRIPTS = {
|
||||||
"linpeas.sh": "https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh",
|
"linpeas.sh": "https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh",
|
||||||
"jaws-enum.ps1": "https://github.com/411Hall/JAWS/raw/master/jaws-enum.ps1",
|
"jaws-enum.ps1": "https://github.com/411Hall/JAWS/raw/master/jaws-enum.ps1",
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 64 KiB |
BIN
images/toolbelt.png
Normal file
|
After Width: | Height: | Size: 1,020 KiB |
|
|
@ -446,9 +446,9 @@ def download_useful_scripts(
|
||||||
if logger:
|
if logger:
|
||||||
logger.info(f"Downloading scripts: {', '.join(scripts.keys())}")
|
logger.info(f"Downloading scripts: {', '.join(scripts.keys())}")
|
||||||
|
|
||||||
# Create scripts directory in user's home (not /root!)
|
# Create scripts/payloads directory in user's home (not /root!)
|
||||||
home = get_home_dir()
|
home = get_home_dir()
|
||||||
scripts_dir = os.path.join(home, 'scripts')
|
scripts_dir = os.path.join(home, 'scripts', 'payloads')
|
||||||
ensure_directory(scripts_dir)
|
ensure_directory(scripts_dir)
|
||||||
|
|
||||||
success_count = 0
|
success_count = 0
|
||||||
|
|
|
||||||
555
toolbelt.py
|
|
@ -6,6 +6,8 @@ Interactive package manager for pentesting and security research tools
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional, List, Dict
|
from typing import Optional, List, Dict
|
||||||
|
|
||||||
# Import local modules
|
# Import local modules
|
||||||
|
|
@ -79,6 +81,8 @@ def show_main_menu(distro_name: str, distro_type: str):
|
||||||
print(colorize("2)", 'green') + " Browse & Select Categories")
|
print(colorize("2)", 'green') + " Browse & Select Categories")
|
||||||
print(colorize("3)", 'green') + " Install Prerequisites (fresh)")
|
print(colorize("3)", 'green') + " Install Prerequisites (fresh)")
|
||||||
print(colorize("4)", 'green') + " View Installed Tools")
|
print(colorize("4)", 'green') + " View Installed Tools")
|
||||||
|
print(colorize("5)", 'green') + " Check for Tool Updates")
|
||||||
|
print(colorize("6)", 'green') + " Manage Wordlists")
|
||||||
print()
|
print()
|
||||||
print(colorize("0)", 'red') + " Exit")
|
print(colorize("0)", 'red') + " Exit")
|
||||||
print()
|
print()
|
||||||
|
|
@ -98,6 +102,10 @@ def main_menu_loop(distro_name: str, distro_type: str, logger):
|
||||||
prompt_install_fresh()
|
prompt_install_fresh()
|
||||||
elif choice == '4':
|
elif choice == '4':
|
||||||
view_installed_tools()
|
view_installed_tools()
|
||||||
|
elif choice == '5':
|
||||||
|
update_tools_menu(logger)
|
||||||
|
elif choice == '6':
|
||||||
|
wordlist_menu(logger)
|
||||||
elif choice == '0':
|
elif choice == '0':
|
||||||
print()
|
print()
|
||||||
print_success("Thank you for using Djedi Toolbelt!")
|
print_success("Thank you for using Djedi Toolbelt!")
|
||||||
|
|
@ -350,7 +358,7 @@ def install_category_selected(category_id: str, distro_type: str, logger):
|
||||||
elif category_id == 'opt':
|
elif category_id == 'opt':
|
||||||
tools_list = list(config.get_opt_tools_for_distro(distro_type).keys())
|
tools_list = list(config.get_opt_tools_for_distro(distro_type).keys())
|
||||||
elif category_id == 'python':
|
elif category_id == 'python':
|
||||||
tools_list = list(config.PYTHON_TOOLS.keys())
|
tools_list = config.PYTHON_TOOLS # Already a list, not a dict
|
||||||
elif category_id == 'docker':
|
elif category_id == 'docker':
|
||||||
tools_list = list(config.DOCKER_TOOLS.keys())
|
tools_list = list(config.DOCKER_TOOLS.keys())
|
||||||
elif category_id == 'scripts':
|
elif category_id == 'scripts':
|
||||||
|
|
@ -457,6 +465,551 @@ def view_installed_tools():
|
||||||
input("Press Enter to continue...")
|
input("Press Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Tool Update Management
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
def update_tools_menu(logger):
|
||||||
|
"""Tool update management menu"""
|
||||||
|
while True:
|
||||||
|
print_section("🔄 TOOL UPDATE MANAGEMENT")
|
||||||
|
|
||||||
|
print(colorize("1)", 'green') + " 📊 Check Versions Only")
|
||||||
|
print(" Show which tools are outdated")
|
||||||
|
print()
|
||||||
|
print(colorize("2)", 'green') + " ⚡ Update All ProjectDiscovery Tools")
|
||||||
|
print(" Fast bulk update using pdtm")
|
||||||
|
print()
|
||||||
|
print(colorize("3)", 'green') + " 🔧 Update All Go Tools")
|
||||||
|
print(" Update all Go tools to @latest")
|
||||||
|
print()
|
||||||
|
print(colorize("4)", 'green') + " 🎯 Select Individual Tools to Update")
|
||||||
|
print(" Choose specific tools with multi-select")
|
||||||
|
print()
|
||||||
|
print(colorize("0)", 'red') + " Back to Main Menu")
|
||||||
|
print()
|
||||||
|
|
||||||
|
choice = input(colorize("Select option: ", 'yellow')).strip()
|
||||||
|
|
||||||
|
if choice == '0':
|
||||||
|
return
|
||||||
|
elif choice == '1':
|
||||||
|
check_tool_versions(logger)
|
||||||
|
elif choice == '2':
|
||||||
|
update_pd_tools_bulk(logger)
|
||||||
|
elif choice == '3':
|
||||||
|
update_all_go_tools(logger)
|
||||||
|
elif choice == '4':
|
||||||
|
update_selected_tools(logger)
|
||||||
|
else:
|
||||||
|
print_error("Invalid option. Please try again.")
|
||||||
|
input("\nPress Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
def check_tool_versions(logger):
|
||||||
|
"""Check and display tool versions vs latest"""
|
||||||
|
print_section("📊 Checking Tool Versions")
|
||||||
|
|
||||||
|
print_info("Checking installed Go tools...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
outdated = []
|
||||||
|
up_to_date = []
|
||||||
|
not_installed = []
|
||||||
|
|
||||||
|
for tool_name, module_path in config.GO_TOOLS.items():
|
||||||
|
# Check if tool is installed
|
||||||
|
if not check_command_exists(tool_name):
|
||||||
|
not_installed.append(tool_name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get installed version
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
[tool_name, '-version'],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=5
|
||||||
|
)
|
||||||
|
|
||||||
|
# Try to extract just the version number, not the full banner
|
||||||
|
version_output = result.stdout.strip() or result.stderr.strip()
|
||||||
|
|
||||||
|
# Many tools print version on first line - extract it
|
||||||
|
if version_output:
|
||||||
|
first_line = version_output.split('\n')[0]
|
||||||
|
# Look for version patterns like "v1.2.3" or "1.2.3"
|
||||||
|
import re
|
||||||
|
version_match = re.search(r'v?\d+\.\d+\.\d+', first_line)
|
||||||
|
if version_match:
|
||||||
|
installed_version = version_match.group(0)
|
||||||
|
else:
|
||||||
|
# Fallback to first line if no version pattern found
|
||||||
|
installed_version = first_line[:50]
|
||||||
|
else:
|
||||||
|
installed_version = "installed"
|
||||||
|
|
||||||
|
up_to_date.append((tool_name, installed_version))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Could not get version for {tool_name}: {e}")
|
||||||
|
up_to_date.append((tool_name, "installed"))
|
||||||
|
|
||||||
|
# Display results
|
||||||
|
if up_to_date:
|
||||||
|
print(colorize("✓ Installed Tools:", 'green'))
|
||||||
|
for tool, version in up_to_date:
|
||||||
|
version_str = version[:50] + "..." if len(version) > 50 else version
|
||||||
|
print(f" • {tool}: {version_str}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if not_installed:
|
||||||
|
print(colorize("○ Not Installed:", 'yellow'))
|
||||||
|
for tool in not_installed:
|
||||||
|
print(f" • {tool}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
print_info("💡 To update tools, use options 2-4 from the update menu")
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
def update_pd_tools_bulk(logger):
|
||||||
|
"""Update all ProjectDiscovery tools using pdtm"""
|
||||||
|
print_section("⚡ Updating ProjectDiscovery Tools")
|
||||||
|
|
||||||
|
# Check if pdtm is installed
|
||||||
|
if not check_command_exists('pdtm'):
|
||||||
|
print_warning("pdtm not found!")
|
||||||
|
print_info("Installing pdtm...")
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
['go', 'install', '-v', 'github.com/projectdiscovery/pdtm/cmd/pdtm@latest'],
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
print_success("pdtm installed successfully")
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Failed to install pdtm: {e}")
|
||||||
|
logger.error(f"Failed to install pdtm: {e}")
|
||||||
|
input("\nPress Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
print_info("Running: pdtm -ua (update all)")
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Run pdtm with direct terminal access
|
||||||
|
result = subprocess.run(
|
||||||
|
['pdtm', '-ua'],
|
||||||
|
check=False # Don't raise on non-zero exit
|
||||||
|
)
|
||||||
|
|
||||||
|
print()
|
||||||
|
if result.returncode == 0:
|
||||||
|
print_success("ProjectDiscovery tools updated successfully!")
|
||||||
|
else:
|
||||||
|
print_warning("Update completed with some issues")
|
||||||
|
|
||||||
|
logger.info(f"pdtm update completed with exit code {result.returncode}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Update failed: {e}")
|
||||||
|
logger.error(f"pdtm update failed: {e}", exc_info=True)
|
||||||
|
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
def update_all_go_tools(logger):
|
||||||
|
"""Update all Go tools to @latest"""
|
||||||
|
print_section("🔧 Updating All Go Tools")
|
||||||
|
|
||||||
|
print_warning("This will update ALL Go tools to @latest")
|
||||||
|
print_info(f"Total tools: {len(config.GO_TOOLS)}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# List all tools that will be updated
|
||||||
|
print(colorize("Tools to update:", 'cyan'))
|
||||||
|
for tool_name in config.GO_TOOLS.keys():
|
||||||
|
# Check if installed
|
||||||
|
if check_command_exists(tool_name):
|
||||||
|
print(colorize(f" ✓ {tool_name}", 'green'))
|
||||||
|
else:
|
||||||
|
print(colorize(f" ○ {tool_name} (not installed, will skip)", 'yellow'))
|
||||||
|
print()
|
||||||
|
|
||||||
|
response = input(colorize("Continue? [y/N]: ", 'yellow')).strip().lower()
|
||||||
|
if response != 'y':
|
||||||
|
print_warning("Update cancelled")
|
||||||
|
input("\nPress Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
print()
|
||||||
|
success_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
skipped_count = 0
|
||||||
|
|
||||||
|
for tool_name, module_path in config.GO_TOOLS.items():
|
||||||
|
# Skip if not installed
|
||||||
|
if not check_command_exists(tool_name):
|
||||||
|
skipped_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"Updating {tool_name}...", end=' ')
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
['go', 'install', '-v', module_path],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=300
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(colorize("✓", 'green'))
|
||||||
|
success_count += 1
|
||||||
|
logger.info(f"Updated {tool_name}")
|
||||||
|
else:
|
||||||
|
print(colorize("✗", 'red'))
|
||||||
|
fail_count += 1
|
||||||
|
logger.warning(f"Failed to update {tool_name}: {result.stderr}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(colorize("✗", 'red'))
|
||||||
|
fail_count += 1
|
||||||
|
logger.error(f"Error updating {tool_name}: {e}")
|
||||||
|
|
||||||
|
print()
|
||||||
|
print_info(f"Updated: {success_count} | Failed: {fail_count} | Skipped: {skipped_count}")
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
def update_selected_tools(logger):
|
||||||
|
"""Update selected Go tools using gum multi-select"""
|
||||||
|
print_section("🎯 Select Tools to Update")
|
||||||
|
|
||||||
|
# Check if gum is available
|
||||||
|
if not check_command_exists('gum'):
|
||||||
|
print()
|
||||||
|
print_error("gum is not installed!")
|
||||||
|
print_info("gum is required for interactive multi-select")
|
||||||
|
print()
|
||||||
|
print_info("Install gum with:")
|
||||||
|
print(" go install github.com/charmbracelet/gum@latest")
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
tool_list = list(config.GO_TOOLS.keys())
|
||||||
|
|
||||||
|
print_info(f"Available tools: {len(tool_list)}")
|
||||||
|
print()
|
||||||
|
print(colorize("TIP: Use SPACE to select, ENTER when done", 'yellow'))
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Use gum for multi-select
|
||||||
|
selected = gum_multi_select(
|
||||||
|
tool_list,
|
||||||
|
header="Select tools to update:"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not selected:
|
||||||
|
print()
|
||||||
|
print_warning("No tools selected")
|
||||||
|
input("\nPress Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Show selection
|
||||||
|
print()
|
||||||
|
print_section(f"Updating {len(selected)} Selected Tools")
|
||||||
|
for tool in selected:
|
||||||
|
print(colorize(f" • {tool}", 'cyan'))
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Confirm
|
||||||
|
response = input(colorize("Proceed with update? [Y/n]: ", 'yellow')).strip().lower()
|
||||||
|
if response == 'n':
|
||||||
|
print_warning("Update cancelled")
|
||||||
|
input("\nPress Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
print()
|
||||||
|
success_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
|
||||||
|
for tool_name in selected:
|
||||||
|
module_path = config.GO_TOOLS[tool_name]
|
||||||
|
print(f"Updating {tool_name}...", end=' ')
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
['go', 'install', '-v', module_path],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=300
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(colorize("✓", 'green'))
|
||||||
|
success_count += 1
|
||||||
|
logger.info(f"Updated {tool_name}")
|
||||||
|
else:
|
||||||
|
print(colorize("✗", 'red'))
|
||||||
|
fail_count += 1
|
||||||
|
logger.warning(f"Failed to update {tool_name}: {result.stderr}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(colorize("✗", 'red'))
|
||||||
|
fail_count += 1
|
||||||
|
logger.error(f"Error updating {tool_name}: {e}")
|
||||||
|
|
||||||
|
print()
|
||||||
|
print_info(f"Updated: {success_count} | Failed: {fail_count}")
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Wordlist Management
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
def find_seclists_path():
|
||||||
|
"""
|
||||||
|
Find SecLists installation path
|
||||||
|
|
||||||
|
Checks common locations:
|
||||||
|
1. /usr/share/seclists (Kali default, lowercase)
|
||||||
|
2. ~/wordlists/SecLists (custom install)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (path, found) - path is the location, found is True if exists
|
||||||
|
"""
|
||||||
|
# Check Kali default location first (lowercase)
|
||||||
|
kali_path = "/usr/share/seclists"
|
||||||
|
if os.path.isdir(kali_path):
|
||||||
|
return (kali_path, True)
|
||||||
|
|
||||||
|
# Check custom install location
|
||||||
|
custom_path = os.path.expanduser("~/wordlists/SecLists")
|
||||||
|
if os.path.isdir(custom_path):
|
||||||
|
return (custom_path, True)
|
||||||
|
|
||||||
|
# Default to custom path if neither exists (for installation)
|
||||||
|
return (custom_path, False)
|
||||||
|
|
||||||
|
|
||||||
|
def wordlist_menu(logger):
|
||||||
|
"""Wordlist management menu"""
|
||||||
|
while True:
|
||||||
|
print_section("📚 WORDLIST MANAGEMENT")
|
||||||
|
|
||||||
|
# Check if SecLists is installed
|
||||||
|
seclists_path, seclists_installed = find_seclists_path()
|
||||||
|
|
||||||
|
print(colorize("1)", 'green') + " Install SecLists")
|
||||||
|
if seclists_installed:
|
||||||
|
print(colorize(f" ✓ Already installed at {seclists_path}", 'green'))
|
||||||
|
else:
|
||||||
|
print(" Comprehensive wordlist collection")
|
||||||
|
print()
|
||||||
|
|
||||||
|
print(colorize("2)", 'green') + " View Installed Wordlists")
|
||||||
|
print(" Browse wordlist directory structure")
|
||||||
|
print()
|
||||||
|
|
||||||
|
print(colorize("3)", 'green') + " Update SecLists")
|
||||||
|
if seclists_installed:
|
||||||
|
print(" Pull latest updates from GitHub")
|
||||||
|
else:
|
||||||
|
print(colorize(" (Requires SecLists to be installed first)", 'yellow'))
|
||||||
|
print()
|
||||||
|
|
||||||
|
print(colorize("0)", 'red') + " Back to Main Menu")
|
||||||
|
print()
|
||||||
|
|
||||||
|
choice = input(colorize("Select option: ", 'yellow')).strip()
|
||||||
|
|
||||||
|
if choice == '0':
|
||||||
|
return
|
||||||
|
elif choice == '1':
|
||||||
|
install_seclists(logger)
|
||||||
|
elif choice == '2':
|
||||||
|
view_wordlists(logger)
|
||||||
|
elif choice == '3':
|
||||||
|
update_seclists(logger, seclists_installed)
|
||||||
|
else:
|
||||||
|
print_error("Invalid option. Please try again.")
|
||||||
|
input("\nPress Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
def install_seclists(logger):
|
||||||
|
"""Install SecLists wordlist collection"""
|
||||||
|
print_section("📥 Installing SecLists")
|
||||||
|
|
||||||
|
wordlists_dir = os.path.expanduser("~/wordlists")
|
||||||
|
seclists_path = os.path.join(wordlists_dir, "SecLists")
|
||||||
|
|
||||||
|
# Check if already installed
|
||||||
|
if os.path.isdir(seclists_path):
|
||||||
|
print_warning("SecLists is already installed!")
|
||||||
|
print_info(f"Location: {seclists_path}")
|
||||||
|
print()
|
||||||
|
response = input(colorize("Reinstall? This will delete and re-clone. [y/N]: ", 'yellow')).strip().lower()
|
||||||
|
if response != 'y':
|
||||||
|
print_warning("Installation cancelled")
|
||||||
|
input("\nPress Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Remove existing
|
||||||
|
print_info("Removing existing SecLists...")
|
||||||
|
try:
|
||||||
|
subprocess.run(['rm', '-rf', seclists_path], check=True)
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Failed to remove existing SecLists: {e}")
|
||||||
|
logger.error(f"Failed to remove SecLists: {e}")
|
||||||
|
input("\nPress Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create wordlists directory
|
||||||
|
if not os.path.isdir(wordlists_dir):
|
||||||
|
print_info(f"Creating {wordlists_dir}...")
|
||||||
|
os.makedirs(wordlists_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Clone SecLists
|
||||||
|
print_info("Cloning SecLists from GitHub...")
|
||||||
|
print_warning("This is a large repository (~500MB), it may take a few minutes...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
['git', 'clone', '--depth', '1', 'https://github.com/danielmiessler/SecLists.git', seclists_path],
|
||||||
|
check=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print()
|
||||||
|
print_success("SecLists installed successfully!")
|
||||||
|
print_info(f"Location: {seclists_path}")
|
||||||
|
print()
|
||||||
|
print_info("Popular wordlists:")
|
||||||
|
print(f" • Passwords: {seclists_path}/Passwords/")
|
||||||
|
print(f" • Usernames: {seclists_path}/Usernames/")
|
||||||
|
print(f" • Subdomains: {seclists_path}/Discovery/DNS/")
|
||||||
|
print(f" • Directories: {seclists_path}/Discovery/Web-Content/")
|
||||||
|
print(f" • Fuzzing: {seclists_path}/Fuzzing/")
|
||||||
|
logger.info("SecLists installed successfully")
|
||||||
|
else:
|
||||||
|
print_error("Failed to clone SecLists repository")
|
||||||
|
logger.error("SecLists installation failed")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Installation failed: {e}")
|
||||||
|
logger.error(f"SecLists installation error: {e}", exc_info=True)
|
||||||
|
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
def view_wordlists(logger):
|
||||||
|
"""View installed wordlist directory structure"""
|
||||||
|
print_section("📂 Installed Wordlists")
|
||||||
|
|
||||||
|
seclists_path, seclists_installed = find_seclists_path()
|
||||||
|
|
||||||
|
if not seclists_installed:
|
||||||
|
print_warning("SecLists not found")
|
||||||
|
print_info("Use option 1 to install SecLists")
|
||||||
|
print_info(f"Checked locations:")
|
||||||
|
print_info(f" • /usr/share/seclists (Kali default)")
|
||||||
|
print_info(f" • ~/wordlists/SecLists (custom install)")
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Show SecLists structure
|
||||||
|
print(colorize(f"SecLists Location: {seclists_path}", 'cyan'))
|
||||||
|
print()
|
||||||
|
|
||||||
|
categories = [
|
||||||
|
"Discovery",
|
||||||
|
"Fuzzing",
|
||||||
|
"IOCs",
|
||||||
|
"Miscellaneous",
|
||||||
|
"Passwords",
|
||||||
|
"Pattern-Matching",
|
||||||
|
"Payloads",
|
||||||
|
"Usernames",
|
||||||
|
"Web-Shells"
|
||||||
|
]
|
||||||
|
|
||||||
|
for category in categories:
|
||||||
|
category_path = os.path.join(seclists_path, category)
|
||||||
|
if os.path.isdir(category_path):
|
||||||
|
# Count files in category
|
||||||
|
try:
|
||||||
|
file_count = sum(1 for _ in Path(category_path).rglob('*') if _.is_file())
|
||||||
|
print(colorize(f" 📁 {category}/", 'green') + f" ({file_count} files)")
|
||||||
|
except Exception:
|
||||||
|
print(colorize(f" 📁 {category}/", 'green'))
|
||||||
|
|
||||||
|
print()
|
||||||
|
print_info(f"Full path: {seclists_path}")
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
|
def update_seclists(logger, seclists_installed: bool):
|
||||||
|
"""Update SecLists from GitHub"""
|
||||||
|
print_section("🔄 Updating SecLists")
|
||||||
|
|
||||||
|
if not seclists_installed:
|
||||||
|
print_warning("SecLists is not installed!")
|
||||||
|
print_info("Use option 1 to install SecLists first")
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
seclists_path, _ = find_seclists_path()
|
||||||
|
|
||||||
|
print_info(f"Updating SecLists at: {seclists_path}")
|
||||||
|
|
||||||
|
# Check if this is a system-installed version
|
||||||
|
if seclists_path.startswith('/usr/'):
|
||||||
|
print_warning("SecLists is installed in system directory (/usr/share/seclists)")
|
||||||
|
print_info("This was likely installed via apt package manager")
|
||||||
|
print_info("To update: sudo apt update && sudo apt upgrade seclists")
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
return
|
||||||
|
|
||||||
|
print_info("Pulling latest updates from GitHub...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Run git pull
|
||||||
|
result = subprocess.run(
|
||||||
|
['git', '-C', seclists_path, 'pull'],
|
||||||
|
check=False
|
||||||
|
)
|
||||||
|
|
||||||
|
print()
|
||||||
|
if result.returncode == 0:
|
||||||
|
print_success("SecLists updated successfully!")
|
||||||
|
else:
|
||||||
|
print_warning("Update completed with issues")
|
||||||
|
print_info("If this is a git repository, try: cd {seclists_path} && git pull")
|
||||||
|
print_info("Otherwise, reinstall with option 1")
|
||||||
|
|
||||||
|
logger.info(f"SecLists update completed with exit code {result.returncode}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Update failed: {e}")
|
||||||
|
logger.error(f"SecLists update error: {e}", exc_info=True)
|
||||||
|
|
||||||
|
print()
|
||||||
|
input("Press Enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Main Entry Point
|
# Main Entry Point
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
|
||||||
5
utils.py
|
|
@ -188,9 +188,12 @@ def gum_multi_select(
|
||||||
return []
|
return []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# gum needs direct terminal access - don't redirect stdin/stderr
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
['gum', 'choose', '--no-limit', '--header', header] + options,
|
['gum', 'choose', '--no-limit', '--header', header] + options,
|
||||||
capture_output=True,
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=None, # Let stderr go to terminal
|
||||||
|
stdin=None, # Let gum access the terminal directly
|
||||||
text=True,
|
text=True,
|
||||||
timeout=300 # 5 minute timeout
|
timeout=300 # 5 minute timeout
|
||||||
)
|
)
|
||||||
|
|
|
||||||