diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3c34b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info/ +dist/ +build/ + +# Logs +*.log + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/README.md b/README.md index cfd95e8..ef2bc7c 100644 --- a/README.md +++ b/README.md @@ -1,108 +1,272 @@ -# Djedi Toolbelt +# Djedi Toolbelt v2.0 -This is intended for new Kali installs to install a large amount of useful tools not included with Kali in a short amount of time. +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Python: 3.6+](https://img.shields.io/badge/Python-3.6+-blue.svg)](https://www.python.org/) -It is recommended if this is a new Kali VM to run PimpMyKali and run the 'N' option first. Dewalt has done an excellent job on this and keeps getting better every time I use it. You can check it out here: https://github.com/Dewalt-arch/pimpmykali It is also integrated into toolbelt but I always like running this first anyway. +**Comprehensive security tool installer with interactive menus, pre-built profiles, and distro-specific support.** -## Updates +--- -Python version got some important tweaks to speed things up and smooth out some issues. Actually the python code has not changed yet, it is just now actually working as intended since I fixed the apt-fast installation. It now takes only 1 to 3 minutes compared to 10 to 15 minutes or so using the bash version. Still may have some tweaks to work through but it seems to be working well in the several tests I've done. I will be putting this into a script shortly but here is instructions. +## 🚀 What's New in v2.0 -### toolbelt.py Installation +- ✅ **Interactive 3-Level Menu System** - Browse categories, select tools, install profiles +- ✅ **Pre-Built Profiles** - Bug Bounty, CTF, Web App, Network, Full Pentest +- ✅ **Distro Detection** - Kali, Debian, Ubuntu support with appropriate tool sets +- ✅ **No Root Requirement** - Runs as user, uses sudo only when needed +- ✅ **Comprehensive Logging** - Dual output (console + file) +- ✅ **Fresh Integration** - Detects and recommends modern CLI tools +- ✅ **Modular Architecture** - Clean, maintainable Python code -First we must install apt-fast -```bash -sudo apt install aria2 -y -sudo /bin/bash -c "$(curl -sL https://git.io/vokNn)" -cp apt-fast /usr/local/sbin/ -sudo chmod +x /usr/local/sbin/apt-fast -cp apt-fast.conf /etc -``` +--- -Then we should be good to go: -```bash -curl https://raw.githubusercontent.com/rpriven/toolbelt/main/toolbelt.py | sudo python3 -``` - -Still a couple minor errors and I want to put this into a script soon. - -*However, please note that there is an issue with the go tools and the useful scripts being downloaded in the /root directory instead of /home/kali because the script must be run as root. Working on a fix for this* - -## Overview - -This script installs / updates some of the important key tools for Pentesters and Bug Bounty Hunters. You probably -have most of these tools installed already (as it was designed for use with Kali/Debian/Ubuntu), but it is useful for -me to have it all together in one script so I don't have to take the time to search for everything when I make a -new VM or have to go through and install or update everything manually. - -This is a rough version as it is my first attempt at building some sort of a recon framework (if you can call -it that) for Pentesting, CTFs as well as Bug Bounties. There will be an accompanying automation script as well. - -**This installs a good amount of tools, if you are looking for something light, you may want to remove what you do not want or need before running the script.** -*It is also a good idea to read through unfamiliar code before executing it anyway.* - -## (Old) Installation - -Simply download the script and run it: +## 📋 Quick Start ```bash -wget https://raw.githubusercontent.com/rpriven/toolbelt/main/toolbelt.sh -chmod +x toolbelt.sh -sudo ./toolbelt.sh +# Clone the repository +git clone https://github.com/rpriven/toolbelt.git +cd toolbelt + +# Run toolbelt (no sudo needed!) +python3 toolbelt.py ``` -Easier: +**Important:** Do NOT run as root/sudo. The script will use sudo for specific commands that require it. + +--- + +## 🎯 Features + +### Interactive Menu System + +**Level 1 - Main Menu:** +- Quick Install Profiles +- Browse & Select Categories +- Install Prerequisites (fresh) +- View Installed Tools + +**Level 2 - Categories:** +- 📦 APT Tools - Package manager tools +- 🔷 Go Tools - Security tools written in Go +- 🔧 /opt Tools - Tools cloned to /opt +- 🐍 Python Tools - Tools via pip3 +- 🐳 Docker Tools - Containerized tools +- 📜 Useful Scripts - PEAS, PowerView, etc. + +**Level 3 - Tool Selection:** +- Install all tools in category +- Individual tool selection (coming soon) + +### Pre-Built Profiles + +**Bug Bounty Hunter** - Web app testing and reconnaissance +- nmap, masscan, nikto, sqlmap, burpsuite +- nuclei, httpx, subfinder, katana, amass +- Sublist3r, wafw00f, XSStrike +- wfuzz, arjun, scripts collection + +**CTF Player** - Capture The Flag tools +- nmap, burpsuite, sqlmap, wireshark +- Python tools: wfuzz, scrapy, requests +- Scripts collection + +**Web Application Testing** - Web security focus +- nmap, nikto, sqlmap, burpsuite +- nuclei, httpx, katana +- wafw00f, XSStrike, Striker +- wfuzz, arjun, scrapy + +**Network Pentesting** - Network recon and scanning +- nmap, masscan, wireshark +- naabu, amass, assetfinder, httprobe +- RustScan (Docker) + +**Full Pentesting Arsenal** - Everything (5GB+) +- All APT tools +- All Go tools +- All /opt tools +- All Python tools +- All Docker tools +- All scripts + +--- + +## 🛠️ Tool Categories + +### APT Tools (via package manager) + +**Kali Linux:** +nmap, masscan, naabu, nuclei, burpsuite, feroxbuster, nikto, gobuster, seclists, sqlmap, git, docker.io, docker-compose, golang-go, wireshark + +**Debian/Ubuntu:** +nmap, masscan, nikto, sqlmap, git, docker.io, docker-compose, golang-go, wireshark, burpsuite + +### Go Tools (via go install) + +naabu, nuclei, katana, httpx, subfinder, amass, assetfinder, httprobe, gowitness, subjack, hakrawler, webanalyze + +*All ProjectDiscovery tools included* + +### /opt Tools (cloned to /opt) + +- **pimpmykali** (Kali only) - Golang + Impacket setup +- **xnLinkFinder** - Link finder for bug bounty +- **Knockpy** - Subdomain enumeration +- **Sublist3r** - Subdomain discovery +- **Striker** - Web application scanner +- **wafw00f** - WAF detection +- **waymore** - Web archive scraper +- **XSStrike** - XSS detection suite + +### Python Tools (via pip3) + +wfuzz, arjun, scrapy, tld, requests, fuzzywuzzy + +### Docker Tools + +**RustScan** - Fast port scanner +- Includes alias setup for shell + +### Useful Scripts (downloaded to ~/scripts) + +- **linpeas.sh** - Linux privilege escalation +- **jaws-enum.ps1** - Windows enumeration +- **LinEnum.sh** - Linux enumeration +- **winPEASany_ofs.exe** - Windows privilege escalation +- **php-reverse-shell.php** - PHP reverse shell +- **linux-exploit-suggester.sh** - Linux exploit suggester +- **PowerView.ps1** - PowerShell AD enumeration + +--- + +## 🔧 Requirements + +- **OS:** Kali Linux, Debian, or Ubuntu +- **Python:** 3.6+ +- **Package Manager:** apt +- **Privileges:** sudo access (script runs as user, not root) + +--- + +## 📖 Usage Examples + +### Install a Profile ```bash -curl https://raw.githubusercontent.com/rpriven/toolbelt/main/toolbelt.sh | sudo sh +python3 toolbelt.py +# Select: 1) Quick Install Profiles +# Choose: Bug Bounty Hunter ``` -## What is on the Toolbelt: +### Browse Categories -- Nmap -- naabu -- Nuclei -- Burp Suite -- feroxbuster -- nikto -- masscan -- Gobuster -- SecLists -- SQLmap -- git -- docker -- docker.io -- pimpmykali -- Golang -- Impacket -- knockpy -- Sublist3r -- Striker -- waymore -- wfuzz -- scrapy -- amass -- assetfinder -- httprobe -- gowitness -- subjack -- hakrawler -- webanalyze -- RustScan +```bash +python3 toolbelt.py +# Select: 2) Browse & Select Categories +# Choose category (e.g., Go Tools) +# Install all or select specific tools +``` -## To Do List +### Check Installed Tools -### Add basic syntax to tools +```bash +python3 toolbelt.py +# Select: 4) View Installed Tools +``` -### Add checks for the Go programs if they are the @latest version so it doesn't re-download them every time -the script is run, only when it is either not found or not up to date +--- -### Add to the toolbelt: +## 🔗 Integration with Fresh -- dnmasscan -- interlace -- static-flow -- sn1per -- more... +Toolbelt integrates with [fresh](https://github.com/rpriven/fresh) for modern CLI productivity tools. -### Add colors +**Recommended Setup:** + +1. **Install fresh first** - Modern CLI foundation (fzf, ripgrep, bat, etc.) +2. **Install toolbelt** - Security tools +3. **Install tmux-recon** (optional) - Pentesting automation + +Fresh provides essential CLI tools that enhance the security workflow. Toolbelt will detect if fresh is installed and prompt you to install it if missing. + +--- + +## 📂 Architecture + +``` +toolbelt/ +├── toolbelt.py # Main entry point with interactive menus +├── utils.py # Distro detection, logging, helpers +├── config.py # Tool definitions, profiles, categories +├── installer.py # Installation logic for each category +├── toolbelt_old.py # Original v1.0 (reference) +└── toolbelt.sh.old # Legacy bash version (archived) +``` + +**Modular Design:** +- `utils.py` - System checks, logging setup, helper functions +- `config.py` - Tool lists, profile definitions, category metadata +- `installer.py` - Installation functions for each tool category +- `toolbelt.py` - Interactive menu system and main flow + +--- + +## 🔐 Security Notes + +- **No Root Execution**: Script runs as regular user, uses sudo only for specific commands +- **Logging**: All operations logged to `~/toolbelt-install.log` +- **Smart Detection**: Skips already-installed tools +- **Error Handling**: Comprehensive error checking and reporting + +--- + +## 🐛 Known Issues + +- Individual tool selection menu (Level 3) coming in next update +- Custom profile saving/loading planned for future release + +--- + +## 🤝 Contributing + +Contributions welcome! Please feel free to submit pull requests or open issues for: +- Additional tool suggestions +- New profiles +- Platform support improvements +- Bug fixes + +--- + +## 📝 Version History + +**v2.0.0** (2025-10-31) +- Complete rewrite with interactive menu system +- Pre-built profile support +- Distro detection (Kali, Debian, Ubuntu) +- Removed root requirement +- Added comprehensive logging +- Fresh integration +- Modular architecture + +**v1.0** (2023) +- Original automated installer +- Bash and Python versions +- Root required +- No menu system + +--- + +## 📜 License + +This project is licensed under the MIT License - see the LICENSE file for details. + +--- + +## 🙏 Acknowledgments + +- Built for the pentesting and bug bounty community +- Integrates tools from ProjectDiscovery, OWASP, and many open source developers +- Inspired by the need for quick, consistent tool setup across environments +- Part of the Djedi security tooling ecosystem + +--- + +**Djedi Toolbelt** - Because every pentester deserves a well-equipped toolbelt. 🔧 diff --git a/config.py b/config.py new file mode 100644 index 0000000..513faf9 --- /dev/null +++ b/config.py @@ -0,0 +1,315 @@ +#!/usr/bin/env python3 +""" +Djedi Toolbelt - Configuration and Tool Definitions +Defines all tools, categories, and profiles +""" + +from typing import Dict, List + +# ============================================================================ +# Tool Categories +# ============================================================================ + +# APT Tools - Available via package manager +APT_TOOLS_KALI = [ + "nmap", + "masscan", + "naabu", + "nuclei", + "burpsuite", + "feroxbuster", + "nikto", + "gobuster", + "seclists", + "sqlmap", + "git", + "docker.io", + "docker-compose", + "golang-go", + "wireshark", +] + +APT_TOOLS_DEBIAN = [ + "nmap", + "masscan", + "nikto", + "sqlmap", + "git", + "docker.io", + "docker-compose", + "golang-go", + "wireshark", + "burpsuite", # Community edition available in some repos +] + +# /opt Tools - Cloned to /opt directory +OPT_TOOLS = { + "pimpmykali": { + "url": "https://github.com/Dewalt-arch/pimpmykali", + "post_install": [ + "cd /opt/pimpmykali && sudo ./pimpmykali.sh --go", + "cd /opt/pimpmykali && sudo ./pimpmykali.sh --impacket", + "cd /opt/pimpmykali && sudo ./pimpmykali.sh --upgrade" + ], + "kali_only": True + }, + "xnLinkFinder": { + "url": "https://github.com/xnl-h4ck3r/xnLinkFinder.git", + "post_install": ["cd /opt/xnLinkFinder && sudo python setup.py install"], + "kali_only": False + }, + "knock": { + "url": "https://github.com/guelfoweb/knock.git", + "post_install": ["cd /opt/knock && pip3 install -r requirements.txt"], + "kali_only": False + }, + "Sublist3r": { + "url": "https://github.com/aboul3la/Sublist3r.git", + "post_install": ["cd /opt/Sublist3r && pip install -r requirements.txt"], + "kali_only": False + }, + "Striker": { + "url": "https://github.com/s0md3v/Striker.git", + "post_install": ["cd /opt/Striker && pip install -r requirements.txt"], + "kali_only": False + }, + "wafw00f": { + "url": "https://github.com/EnableSecurity/wafw00f.git", + "post_install": [ + "cd /opt/wafw00f && pip3 install -r requirements.txt", + "cd /opt/wafw00f && sudo python setup.py install" + ], + "kali_only": False + }, + "waymore": { + "url": "https://github.com/xnl-h4ck3r/waymore.git", + "post_install": [ + "cd /opt/waymore && pip3 install -r requirements.txt", + "cd /opt/waymore && sudo python setup.py install" + ], + "kali_only": False + }, + "XSStrike": { + "url": "https://github.com/s0md3v/XSStrike.git", + "post_install": ["cd /opt/XSStrike && pip3 install -r requirements.txt"], + "kali_only": False + }, +} + +# Python Tools - Installed via pip3 +PYTHON_TOOLS = [ + "wfuzz", + "arjun", + "scrapy", + "tld", + "requests", + "fuzzywuzzy", +] + +# Go Tools - Installed via go install +GO_TOOLS = { + "naabu": "github.com/projectdiscovery/naabu/v2/cmd/naabu@latest", + "nuclei": "github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest", + "katana": "github.com/projectdiscovery/katana/cmd/katana@latest", + "httpx": "github.com/projectdiscovery/httpx/cmd/httpx@latest", + "subfinder": "github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest", + "amass": "github.com/OWASP/Amass/v3/...@master", + "assetfinder": "github.com/tomnomnom/assetfinder@latest", + "httprobe": "github.com/tomnomnom/httprobe@latest", + "gowitness": "github.com/sensepost/gowitness@latest", + "subjack": "github.com/haccer/subjack@latest", + "hakrawler": "github.com/hakluke/hakrawler@latest", + "webanalyze": "github.com/rverton/webanalyze/cmd/webanalyze@latest", +} + +# Docker Tools +DOCKER_TOOLS = { + "rustscan": { + "image": "rustscan/rustscan:2.0.1", + "alias": "alias rustscan='docker run -it --rm --name rustscan rustscan/rustscan:2.0.1'" + }, +} + +# Useful Scripts - Downloaded to ~/scripts +USEFUL_SCRIPTS = { + "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", + "LinEnum.sh": "https://github.com/rebootuser/LinEnum/raw/master/LinEnum.sh", + "winPEASany_ofs.exe": "https://github.com/carlospolop/PEASS-ng/releases/download/20230122/winPEASany_ofs.exe", + "php-reverse-shell.php": "https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php", + "linux-exploit-suggester.sh": "https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh", + "PowerView.ps1": "https://github.com/PowerShellMafia/PowerSploit/raw/master/Recon/PowerView.ps1", +} + +# ============================================================================ +# Installation Profiles +# ============================================================================ + +PROFILES = { + "bug-bounty": { + "name": "Bug Bounty Hunter", + "description": "Tools for bug bounty hunting and web application testing", + "categories": { + "apt": ["nmap", "masscan", "nikto", "sqlmap", "burpsuite", "git"], + "go": ["nuclei", "httpx", "subfinder", "katana", "amass", "assetfinder", "httprobe"], + "opt": ["Sublist3r", "wafw00f", "XSStrike"], + "python": ["wfuzz", "arjun", "requests"], + "scripts": True, # Install all scripts + } + }, + "ctf": { + "name": "CTF Player", + "description": "Tools for Capture The Flag competitions", + "categories": { + "apt": ["nmap", "burpsuite", "sqlmap", "git", "wireshark"], + "python": ["wfuzz", "scrapy", "requests"], + "scripts": True, + } + }, + "web-app": { + "name": "Web Application Testing", + "description": "Focused on web application security testing", + "categories": { + "apt": ["nmap", "nikto", "sqlmap", "burpsuite"], + "go": ["nuclei", "httpx", "katana"], + "opt": ["wafw00f", "XSStrike", "Striker"], + "python": ["wfuzz", "arjun", "scrapy"], + } + }, + "network": { + "name": "Network Pentesting", + "description": "Network reconnaissance and scanning tools", + "categories": { + "apt": ["nmap", "masscan", "wireshark"], + "go": ["naabu", "amass", "assetfinder", "httprobe"], + "docker": ["rustscan"], + } + }, + "full-pentest": { + "name": "Full Pentesting Arsenal", + "description": "Complete toolset for comprehensive penetration testing", + "categories": { + "apt": "all", + "go": "all", + "opt": "all", + "python": "all", + "docker": "all", + "scripts": True, + } + }, +} + +# ============================================================================ +# Category Metadata +# ============================================================================ + +CATEGORIES = { + "apt": { + "name": "APT Tools", + "description": "Tools installed via apt package manager", + "icon": "📦", + "requires_sudo": True, + }, + "go": { + "name": "Go Tools", + "description": "Security tools written in Go", + "icon": "🔷", + "requires_sudo": False, + }, + "opt": { + "name": "/opt Tools", + "description": "Tools cloned to /opt directory", + "icon": "🔧", + "requires_sudo": True, + }, + "python": { + "name": "Python Tools", + "description": "Tools installed via pip3", + "icon": "🐍", + "requires_sudo": False, + }, + "docker": { + "name": "Docker Tools", + "description": "Containerized security tools", + "icon": "🐳", + "requires_sudo": False, + }, + "scripts": { + "name": "Useful Scripts", + "description": "PEAS, PowerView, and other scripts", + "icon": "📜", + "requires_sudo": False, + }, +} + +# ============================================================================ +# Helper Functions +# ============================================================================ + +def get_apt_tools_for_distro(distro_type: str) -> List[str]: + """ + Get appropriate APT tools list for distro + + Args: + distro_type: One of 'kali', 'debian', 'ubuntu', 'unknown' + + Returns: + List of APT package names + """ + if distro_type == 'kali': + return APT_TOOLS_KALI + elif distro_type in ['debian', 'ubuntu']: + return APT_TOOLS_DEBIAN + else: + # Conservative list for unknown distros + return [ + "nmap", + "nikto", + "sqlmap", + "git", + "docker.io", + ] + + +def get_opt_tools_for_distro(distro_type: str) -> Dict: + """ + Get appropriate /opt tools for distro + + Args: + distro_type: One of 'kali', 'debian', 'ubuntu', 'unknown' + + Returns: + Dictionary of /opt tools + """ + if distro_type == 'kali': + return OPT_TOOLS + + # Filter out Kali-only tools for other distros + return { + name: config + for name, config in OPT_TOOLS.items() + if not config.get('kali_only', False) + } + + +def get_profile(profile_name: str) -> Dict: + """ + Get profile configuration by name + + Args: + profile_name: Profile identifier + + Returns: + Profile configuration dictionary or None + """ + return PROFILES.get(profile_name) + + +def list_profiles() -> List[str]: + """ + Get list of available profile names + + Returns: + List of profile names + """ + return list(PROFILES.keys()) diff --git a/installer.py b/installer.py new file mode 100644 index 0000000..01b687d --- /dev/null +++ b/installer.py @@ -0,0 +1,479 @@ +#!/usr/bin/env python3 +""" +Djedi Toolbelt - Installation Functions +Handles installation of tools across all categories +""" + +import os +import subprocess +import logging +from typing import List, Dict, Optional +from concurrent.futures import ThreadPoolExecutor, as_completed +from pathlib import Path + +from utils import ( + run_command, + ensure_directory, + get_home_dir, + check_command_exists, + print_success, + print_info, + print_warning, + print_error, +) +import config + + +# ============================================================================ +# APT Tools Installation +# ============================================================================ + +def install_apt_tools( + tools: Optional[List[str]] = None, + distro_type: str = 'unknown', + logger: Optional[logging.Logger] = None +) -> bool: + """ + Install tools via APT package manager + + Args: + tools: List of package names (None for all) + distro_type: Distro type for filtering + logger: Logger instance + + Returns: + True if successful + """ + if tools is None: + tools = config.get_apt_tools_for_distro(distro_type) + + if not tools: + print_warning("No APT tools to install for this distribution") + return True + + print_info(f"Installing {len(tools)} APT tools...") + if logger: + logger.info(f"Installing APT tools: {', '.join(tools)}") + + # Update apt cache + try: + print_info("Updating APT cache...") + run_command(['apt', 'update'], use_sudo=True, logger=logger) + except Exception as e: + print_error(f"Failed to update APT cache: {e}") + if logger: + logger.error(f"APT update failed: {e}") + return False + + # Check which tools are already installed + tools_to_install = [] + for tool in tools: + # Handle cases like docker.io where command name != package name + check_name = tool.replace('.io', '').replace('-', '') + if check_command_exists(check_name): + print_success(f"{tool} already installed") + if logger: + logger.debug(f"{tool} already installed") + else: + tools_to_install.append(tool) + + if not tools_to_install: + print_success("All APT tools already installed") + return True + + # Install tools + print_info(f"Installing {len(tools_to_install)} new tools...") + try: + cmd = ['apt', 'install', '-y'] + tools_to_install + result = run_command(cmd, use_sudo=True, logger=logger) + + print_success(f"Installed {len(tools_to_install)} APT tools") + if logger: + logger.info(f"APT installation complete: {', '.join(tools_to_install)}") + return True + + except Exception as e: + print_error(f"Failed to install some APT tools: {e}") + if logger: + logger.error(f"APT installation failed: {e}") + return False + + +# ============================================================================ +# /opt Tools Installation +# ============================================================================ + +def install_opt_tool( + tool_name: str, + tool_config: Dict, + logger: Optional[logging.Logger] = None +) -> bool: + """ + Install a single /opt tool + + Args: + tool_name: Name of the tool + tool_config: Tool configuration dict + logger: Logger instance + + Returns: + True if successful + """ + opt_path = f"/opt/{tool_name}" + + # Check if already installed + if os.path.isdir(opt_path): + print_success(f"{tool_name} already installed") + if logger: + logger.debug(f"{tool_name} already installed at {opt_path}") + return True + + print_info(f"Installing {tool_name}...") + if logger: + logger.info(f"Installing /opt tool: {tool_name}") + + try: + # Clone repository + cmd = ['git', 'clone', tool_config['url'], opt_path] + run_command(cmd, use_sudo=True, logger=logger) + + # Run post-install commands if specified + if 'post_install' in tool_config: + for post_cmd in tool_config['post_install']: + run_command(post_cmd, use_sudo=True, shell=True, logger=logger) + + print_success(f"{tool_name} installed") + if logger: + logger.info(f"{tool_name} installation complete") + return True + + except Exception as e: + print_error(f"Failed to install {tool_name}: {e}") + if logger: + logger.error(f"Failed to install {tool_name}: {e}") + return False + + +def install_opt_tools( + tools: Optional[List[str]] = None, + distro_type: str = 'unknown', + logger: Optional[logging.Logger] = None +) -> bool: + """ + Install /opt tools + + Args: + tools: List of tool names (None for all) + distro_type: Distro type for filtering + logger: Logger instance + + Returns: + True if successful + """ + all_tools = config.get_opt_tools_for_distro(distro_type) + + if tools is None: + tools_to_install = all_tools + else: + tools_to_install = {k: v for k, v in all_tools.items() if k in tools} + + if not tools_to_install: + print_warning("No /opt tools to install for this distribution") + return True + + print_info(f"Installing {len(tools_to_install)} /opt tools...") + + # Ensure /opt exists + ensure_directory("/opt", use_sudo=True) + + # Install each tool + success_count = 0 + for tool_name, tool_config in tools_to_install.items(): + if install_opt_tool(tool_name, tool_config, logger): + success_count += 1 + + print_success(f"Installed {success_count}/{len(tools_to_install)} /opt tools") + return success_count == len(tools_to_install) + + +# ============================================================================ +# Python Tools Installation +# ============================================================================ + +def install_python_tools( + tools: Optional[List[str]] = None, + logger: Optional[logging.Logger] = None +) -> bool: + """ + Install Python tools via pip3 + + Args: + tools: List of package names (None for all) + logger: Logger instance + + Returns: + True if successful + """ + if tools is None: + tools = config.PYTHON_TOOLS + + if not tools: + print_warning("No Python tools to install") + return True + + print_info(f"Installing {len(tools)} Python tools...") + if logger: + logger.info(f"Installing Python tools: {', '.join(tools)}") + + try: + cmd = ['pip3', 'install', '--upgrade'] + tools + run_command(cmd, logger=logger) + + print_success(f"Installed {len(tools)} Python tools") + if logger: + logger.info(f"Python tools installation complete") + return True + + except Exception as e: + print_error(f"Failed to install Python tools: {e}") + if logger: + logger.error(f"Python tools installation failed: {e}") + return False + + +# ============================================================================ +# Go Tools Installation +# ============================================================================ + +def install_go_tool( + tool_name: str, + tool_path: str, + logger: Optional[logging.Logger] = None +) -> bool: + """ + Install a single Go tool + + Args: + tool_name: Name of the tool + tool_path: Go module path + logger: Logger instance + + Returns: + True if successful + """ + try: + cmd = ['go', 'install', '-v', tool_path] + run_command(cmd, logger=logger) + return True + except Exception as e: + if logger: + logger.error(f"Failed to install {tool_name}: {e}") + return False + + +def install_go_tools( + tools: Optional[List[str]] = None, + logger: Optional[logging.Logger] = None, + parallel: bool = True +) -> bool: + """ + Install Go tools + + Args: + tools: List of tool names (None for all) + logger: Logger instance + parallel: Install in parallel if True + + Returns: + True if successful + """ + all_tools = config.GO_TOOLS + + if tools is None: + tools_to_install = all_tools + else: + tools_to_install = {k: v for k, v in all_tools.items() if k in tools} + + if not tools_to_install: + print_warning("No Go tools to install") + return True + + print_info(f"Installing {len(tools_to_install)} Go tools...") + if logger: + logger.info(f"Installing Go tools: {', '.join(tools_to_install.keys())}") + + # Check if Go is installed + if not check_command_exists('go'): + print_error("Go is not installed! Install golang-go first.") + return False + + success_count = 0 + + if parallel: + # Install in parallel using ThreadPoolExecutor + with ThreadPoolExecutor(max_workers=5) as executor: + futures = { + executor.submit(install_go_tool, name, path, logger): name + for name, path in tools_to_install.items() + } + + for future in as_completed(futures): + tool_name = futures[future] + try: + if future.result(): + print_success(f"{tool_name} installed") + success_count += 1 + else: + print_error(f"{tool_name} failed") + except Exception as e: + print_error(f"{tool_name} failed: {e}") + else: + # Install sequentially + for tool_name, tool_path in tools_to_install.items(): + if install_go_tool(tool_name, tool_path, logger): + print_success(f"{tool_name} installed") + success_count += 1 + else: + print_error(f"{tool_name} failed") + + print_success(f"Installed {success_count}/{len(tools_to_install)} Go tools") + return success_count == len(tools_to_install) + + +# ============================================================================ +# Docker Tools Installation +# ============================================================================ + +def install_docker_tools( + tools: Optional[List[str]] = None, + logger: Optional[logging.Logger] = None +) -> bool: + """ + Install Docker tools + + Args: + tools: List of tool names (None for all) + logger: Logger instance + + Returns: + True if successful + """ + all_tools = config.DOCKER_TOOLS + + if tools is None: + tools_to_install = all_tools + else: + tools_to_install = {k: v for k, v in all_tools.items() if k in tools} + + if not tools_to_install: + print_warning("No Docker tools to install") + return True + + print_info(f"Installing {len(tools_to_install)} Docker tools...") + if logger: + logger.info(f"Installing Docker tools: {', '.join(tools_to_install.keys())}") + + # Check if Docker is installed + if not check_command_exists('docker'): + print_error("Docker is not installed! Install docker.io first.") + return False + + success_count = 0 + + for tool_name, tool_config in tools_to_install.items(): + try: + # Pull Docker image + cmd = ['docker', 'pull', tool_config['image']] + run_command(cmd, logger=logger) + + # Add alias to shell config if specified + if 'alias' in tool_config: + home = get_home_dir() + shell_configs = [ + os.path.join(home, '.zshrc'), + os.path.join(home, '.bashrc') + ] + + for config_file in shell_configs: + if os.path.exists(config_file): + with open(config_file, 'r') as f: + content = f.read() + + if tool_name not in content: + with open(config_file, 'a') as f: + f.write(f"\n# {tool_name} alias (added by toolbelt)\n") + f.write(f"{tool_config['alias']}\n") + print_info(f"Added {tool_name} alias to {config_file}") + + print_success(f"{tool_name} installed") + success_count += 1 + + except Exception as e: + print_error(f"Failed to install {tool_name}: {e}") + if logger: + logger.error(f"Failed to install {tool_name}: {e}") + + print_success(f"Installed {success_count}/{len(tools_to_install)} Docker tools") + return success_count == len(tools_to_install) + + +# ============================================================================ +# Useful Scripts Download +# ============================================================================ + +def download_useful_scripts( + scripts: Optional[Dict[str, str]] = None, + logger: Optional[logging.Logger] = None +) -> bool: + """ + Download useful scripts to ~/scripts + + Args: + scripts: Dict of {filename: url} (None for all) + logger: Logger instance + + Returns: + True if successful + """ + if scripts is None: + scripts = config.USEFUL_SCRIPTS + + if not scripts: + print_warning("No scripts to download") + return True + + print_info(f"Downloading {len(scripts)} useful scripts...") + if logger: + logger.info(f"Downloading scripts: {', '.join(scripts.keys())}") + + # Create scripts directory in user's home (not /root!) + home = get_home_dir() + scripts_dir = os.path.join(home, 'scripts') + ensure_directory(scripts_dir) + + success_count = 0 + + for filename, url in scripts.items(): + try: + output_path = os.path.join(scripts_dir, filename) + + # Skip if already exists + if os.path.exists(output_path): + print_success(f"{filename} already exists") + success_count += 1 + continue + + # Download with wget + cmd = ['wget', '-O', output_path, url] + run_command(cmd, logger=logger) + + print_success(f"Downloaded {filename}") + success_count += 1 + + except Exception as e: + print_error(f"Failed to download {filename}: {e}") + if logger: + logger.error(f"Failed to download {filename}: {e}") + + print_success(f"Downloaded {success_count}/{len(scripts)} scripts to {scripts_dir}") + return success_count == len(scripts) diff --git a/toolbelt.py b/toolbelt.py old mode 100644 new mode 100755 index 0183035..89c97b5 --- a/toolbelt.py +++ b/toolbelt.py @@ -1,306 +1,397 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 +""" +Djedi Toolbelt v2.0 - Security Tool Installer +Interactive package manager for pentesting and security research tools +""" -###################### -''' Djedi Toolbelt ''' -''' Python3 Reboot ''' -###################### +import sys +import os +from typing import Optional, List, Dict -''' -######################################################################### +# Import local modules +from utils import ( + setup_logging, + detect_distro, + check_root_discourage, + check_apt, + check_sudo, + check_command_exists, + print_banner, + print_section, + print_success, + print_info, + print_warning, + print_error, + colorize, +) +import config +import installer -WARNING: - This script is approximately 5 GB and will take a while to run. +# ============================================================================ +# Fresh Detection & Integration +# ============================================================================ - Please make sure you check this before installing. +def check_fresh_installed() -> bool: + """Check if fresh CLI tools are installed""" + fresh_tools = ['fzf', 'rg', 'bat'] + return all(check_command_exists(tool) for tool in fresh_tools) - Menu will be coming in one of the next updates to help - cater to your preferences and custom requirements. -######################################################################### -''' +def prompt_install_fresh(): + """Prompt user to install fresh if not detected""" + if check_fresh_installed(): + return -''' -TO DO: + print() + print_warning("Fresh CLI tools not detected") + print_info("Fresh provides modern CLI productivity tools (fzf, ripgrep, bat, etc.)") + print_info("Repository: https://github.com/rpriven/fresh") + print() - Finish - apt threading (sort of, with apt-fast) + response = input(colorize("Would you like to install fresh first? [y/N]: ", 'yellow')).strip().lower() + if response == 'y': + print() + print_info("To install fresh, run:") + print() + print(" git clone https://github.com/rpriven/fresh.git && cd fresh") + print(" ./fresh.sh") + print() + print_info("Then come back and run toolbelt again!") + sys.exit(0) - Add - Menu selection for the various categories: - - apt tools only - - opt tools only - - python tools only - - go tools only - - docker tools only - - scripts only - Threading for /opt tools +# ============================================================================ +# Level 1: Main Menu +# ============================================================================ - Find out where scripts are actually downloading +def show_main_menu(distro_name: str, distro_type: str): + """Display the main menu""" + print_banner() + print(colorize(f"Detected: {distro_name}", 'cyan')) + print() + print(colorize("=" * 60, 'white')) + print(colorize(" MAIN MENU", 'cyan')) + print(colorize("=" * 60, 'white')) + print() + print(colorize("1)", 'green') + " Quick Install Profiles") + print(colorize("2)", 'green') + " Browse & Select Categories") + print(colorize("3)", 'green') + " Install Prerequisites (fresh)") + print(colorize("4)", 'green') + " View Installed Tools") + print() + print(colorize("0)", 'red') + " Exit") + print() - Add C2 - Probably Havoc - Add PowerView (if not already included) - Double-check all tools +def main_menu_loop(distro_name: str, distro_type: str, logger): + """Main menu interaction loop""" + while True: + show_main_menu(distro_name, distro_type) + choice = input(colorize("Select option: ", 'yellow')).strip() - Add section for Bug Bounty tools - - Add section for API tools - - Add option to download the recon.py automation script, - which uses this toolbelt - -''' - -import subprocess, os, threading -from concurrent.futures import ThreadPoolExecutor, as_completed -from termcolor import colored -from tqdm import tqdm - -threads = [] - -# Check if the user is running as root -if os.geteuid() != 0: - print(colored("Please run as root", 'red')) - exit(1) - -''' -subprocess.run(["pip", "install", "progress"]) - -tools = ["tool1", "tool2", "tool3"] -bar = Bar('Installing', max=len(tools)) -for tool in tools: - # Code to install the tool - bar.next() -bar.finish() -''' - -# Figlet -os.system("figlet DjediToolbelt | lolcat") - -# Version -print("v.0.3\n") - -# Message -print(colored("[*] Installing Pentest & Bug Bounty Toolbox Suite", 'magenta')) - -######################### -''' Aptitude Programs ''' -######################### - -def apt_tools(): - subprocess.run(["sudo", "apt", "update"]) - subprocess.run(["sudo", "apt", "install", "apt-fast"]) - - programs = ["nmap", "naabu", "nuclei", "burpsuite", "feroxbuster", "nikto", "masscan", "gobuster", "seclists", "sqlmap", "git"] - - for program in programs: - if os.system(f"command -v {program}") == 0: - print(colored(f"[*] {program} is already installed", 'blue')) + if choice == '1': + profile_menu(distro_type, logger) + elif choice == '2': + category_menu(distro_type, logger) + elif choice == '3': + prompt_install_fresh() + elif choice == '4': + view_installed_tools() + elif choice == '0': + print() + print_success("Thank you for using Djedi Toolbelt!") + sys.exit(0) else: - print(colored(f"[+] Installing / updating {program}", 'green')) - os.system(f"sudo apt-fast install {program} -y") - if os.system(f"command -v {program}") != 0: - print(colored(f"[*] Error: Failed to install the program: {program}", 'red')) - exit(1) - os.system(f"sudo apt-fast install docker docker.io golang-go -y") + print_error("Invalid option. Please try again.") + input("\nPress Enter to continue...") -################## -''' /opt Tools ''' -################## -def opt_tools(): - # Pimpmykali - os.chdir("/opt") - if not os.path.isdir("/opt/pimpmykali"): - print(colored("[+] Installing pimpmykali...", 'green')) - os.system("sudo git clone https://github.com/Dewalt-arch/pimpmykali") - os.chdir("pimpmykali") - print(colored("[+] Installing Golang...", 'green')) - os.system("sudo ./pimpmykali.sh --go") - print(colored("[+] Installing Impacket...", 'green')) - os.system("sudo ./pimpmykali.sh --impacket") - os.system("sudo ./pimpmykali.sh --upgrade") - os.chdir("/opt") - else: - print(colored("[*] pimpmykali is already installed", 'blue')) +# ============================================================================ +# Level 2: Profile Menu +# ============================================================================ - # xnLinkFinder - if not os.path.isdir("/opt/xnLinkFinder"): - print(colored("[+] Installing xnLinkFinder...", 'green')) - os.system("git clone https://github.com/xnl-h4ck3r/xnLinkFinder.git") - os.chdir("xnLinkFinder") - os.system("sudo python setup.py install") - os.chdir("/opt") - else: - print(colored("[*] xnLinkFinder is already installed", 'blue')) +def show_profile_menu(): + """Display profile selection menu""" + print_section("QUICK INSTALL PROFILES") - # Knockpy - if not os.path.isdir("/opt/knock"): - print(colored("[+] Installing Knockpy...", 'green')) - os.system("sudo git clone https://github.com/guelfoweb/knock.git") - os.chdir("knock") - os.system("pip3 install -r requirements.txt") - os.chdir("/opt") - else: - print(colored("[*] Knockpy is already installed", 'blue')) + profiles = config.PROFILES + idx = 1 + profile_map = {} - # Sublist3r - if not os.path.isdir("/opt/Sublist3r"): - print(colored("[+] Installing Sublist3r...", 'green')) - os.system("sudo git clone https://github.com/aboul3la/Sublist3r.git") - os.chdir("Sublist3r") - os.system("pip install -r requirements.txt") - os.chdir("/opt") - else: - print(colored("[*] Sublist3r is already installed", 'blue')) + for profile_id, profile_info in profiles.items(): + print(f"{colorize(str(idx) + ')', 'green')} {colorize(profile_info['name'], 'white')}") + print(f" {profile_info['description']}") + print() + profile_map[str(idx)] = profile_id + idx += 1 - # Striker - if not os.path.isdir("/opt/Striker"): - print(colored("[+] Installing Striker...", 'green')) - os.system("sudo git clone https://github.com/s0md3v/Striker.git") - os.chdir("Striker") - os.system("pip install -r requirements.txt") - os.chdir("/opt") - else: - print(colored("[*] Striker is already installed", 'blue')) + print(colorize("0)", 'red') + " Back to Main Menu") + print() - # wafw00f - if not os.path.isdir("/opt/wafw00f"): - print(colored("[+] Installing wafw00f...", 'green')) - os.system("git clone https://github.com/EnableSecurity/wafw00f.git") - os.chdir("wafw00f") - os.system("pip3 install -r requirements.txt") - os.system("sudo python setup.py install") - os.chdir("/opt") - else: - print(colored("[*] wafw00f is already installed", 'blue')) + return profile_map - # Waymore - if not os.path.isdir("/opt/waymore"): - print(colored("[+] Installing waymore...", 'green')) - os.system("git clone https://github.com/xnl-h4ck3r/waymore.git") - os.chdir("waymore") - os.system("pip3 install -r requirements.txt") - os.system("sudo python setup.py install") - os.chdir("/opt") - else: - print(colored("[*] waymore is already installed", 'blue')) - # XSStrike - if not os.path.isdir("/opt/XSStrike"): - print(colored("[+] Installing XSStrike...", 'green')) - os.system("git clone https://github.com/s0md3v/XSStrike.git") - os.chdir("XSStrike") - os.system("pip3 install -r requirements.txt") - os.system("sudo python setup.py install") - os.chdir("/opt") - else: - print(colored("[*] XSStrike is already installed", 'blue')) +def install_profile(profile_id: str, distro_type: str, logger): + """Install tools from a profile""" + profile = config.get_profile(profile_id) + if not profile: + print_error(f"Profile not found: {profile_id}") + return -#################### -''' Python Tools ''' -#################### + print_section(f"Installing Profile: {profile['name']}") + print_info(profile['description']) + print() -def python_tools(): - print(colored("[+] Installing / Updating Python Tools...", 'green')) - subprocess.run(["pip3", "install", "--upgrade", "wfuzz"]) - subprocess.run(["pip3", "install", "arjun"]) - subprocess.run(["pip3", "install", "scrapy"]) - subprocess.run(["pip3", "install", "tld"]) - subprocess.run(["pip3", "install", "requests"]) - subprocess.run(["pip3", "install", "fuzzywuzzy"]) + categories = profile['categories'] -################ -''' Go Tools ''' -################ + # APT Tools + if 'apt' in categories: + if categories['apt'] == 'all': + installer.install_apt_tools(distro_type=distro_type, logger=logger) + elif isinstance(categories['apt'], list): + installer.install_apt_tools(tools=categories['apt'], distro_type=distro_type, logger=logger) -def go_tools(): - print(colored("[+] Installing / Updating Go Tools...", 'green')) - commands = [ - ["go", "install", "-v", "github.com/projectdiscovery/naabu/v2/cmd/naabu@latest"], - ["go", "install", "-v", "github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest"], - ["go", "install", "-v", "github.com/projectdiscovery/katana/cmd/katana@latest"], - ["go", "install", "-v", "github.com/projectdiscovery/httpx/cmd/httpx@latest"], - ["go", "install", "-v", "github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest"], - ["go", "install", "-v", "github.com/OWASP/Amass/v3/...@master"], - ["go", "install", "-v", "github.com/tomnomnom/assetfinder@latest"], - ["go", "install", "-v", "github.com/tomnomnom/httprobe@latest"], - ["go", "install", "-v", "github.com/sensepost/gowitness@latest"], - ["go", "install", "-v", "github.com/haccer/subjack@latest"], - ["go", "install", "-v", "github.com/hakluke/hakrawler@latest"], - ["go", "install", "-v", "github.com/rverton/webanalyze/cmd/webanalyze@latest"], - ] + # Go Tools + if 'go' in categories: + if categories['go'] == 'all': + installer.install_go_tools(logger=logger) + elif isinstance(categories['go'], list): + installer.install_go_tools(tools=categories['go'], logger=logger) - with ThreadPoolExecutor() as executor: - results = [executor.submit(subprocess.run, cmd) for cmd in commands] - for f in as_completed(results): - print(colored(f.result(), 'green')) + # /opt Tools + if 'opt' in categories: + if categories['opt'] == 'all': + installer.install_opt_tools(distro_type=distro_type, logger=logger) + elif isinstance(categories['opt'], list): + installer.install_opt_tools(tools=categories['opt'], distro_type=distro_type, logger=logger) -#################### -''' Docker Tools ''' -#################### + # Python Tools + if 'python' in categories: + if categories['python'] == 'all': + installer.install_python_tools(logger=logger) + elif isinstance(categories['python'], list): + installer.install_python_tools(tools=categories['python'], logger=logger) -def docker_tools(): - # RustScan - print(colored("[+] Installing / Updating RustScan...", 'green')) - os.system("docker pull rustscan/rustscan:2.0.1") - if os.path.isfile("~/.zshrc"): - print(colored("[+] adding rustscan alias to ~/.zshrc", 'green')) - with open("~/.zshrc", "a") as f: - f.write("alias rustscan='docker run -it --rm --name rustscan rustscan/rustscan:2.0.1'") - elif os.path.isfile("~/.bashrc"): - print(colored("[+] adding rustscan alias to ~/.bashrc", 'green')) - with open("~/.bashrc", "a") as f: - f.write("alias rustscan='docker run -it --rm --name rustscan rustscan/rustscan:2.0.1'") + # Docker Tools + if 'docker' in categories: + if categories['docker'] == 'all': + installer.install_docker_tools(logger=logger) + elif isinstance(categories['docker'], list): + installer.install_docker_tools(tools=categories['docker'], logger=logger) -############### -''' Scripts ''' -############### + # Scripts + if 'scripts' in categories and categories['scripts']: + installer.download_useful_scripts(logger=logger) -def useful_scripts(): - def scripts_dir(): - if not os.path.isdir(os.path.expanduser("~/scripts")): - # os.chdir(["cd", os.path.expanduser("~")]) - os.chdir(os.path.expanduser("~")) - os.makedirs(os.path.expanduser("~/scripts"), exist_ok=True) - os.chdir(os.path.expanduser("~/scripts")) - subprocess.run(["echo", "created", "scripts", "and", "moved", "into", "it"]) + print() + print_success(f"Profile '{profile['name']}' installation complete!") + input("\nPress Enter to continue...") + + +def profile_menu(distro_type: str, logger): + """Profile selection menu""" + while True: + profile_map = show_profile_menu() + choice = input(colorize("Select profile: ", 'yellow')).strip() + + if choice == '0': + return + elif choice in profile_map: + install_profile(profile_map[choice], distro_type, logger) else: - os.chdir(os.path.expanduser("~/scripts")) - subprocess.run(["echo", "directory", "/scripts", "already", "exists,", "moving", "into", "it"]) + print_error("Invalid option. Please try again.") + input("\nPress Enter to continue...") - scripts_dir() - scripts = ["https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh", "https://github.com/411Hall/JAWS/raw/master/jaws-enum.ps1", "https://github.com/rebootuser/LinEnum/raw/master/LinEnum.sh", "https://github.com/carlospolop/PEASS-ng/releases/download/20230122/winPEASany_ofs.exe", "https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php", "https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh", "https://github.com/PowerShellMafia/PowerSploit/raw/master/Recon/PowerView.ps1"] +# ============================================================================ +# Level 2: Category Menu +# ============================================================================ - script_threads = [] +def show_category_menu(): + """Display category selection menu""" + print_section("BROWSE & SELECT CATEGORIES") - def download_script_thread(script): - subprocess.run(f"wget {script}", shell=True) + idx = 1 + category_map = {} - def download_script(scripts): - for script in tqdm(scripts): - print(colored(f"[+] Grabbing {script}", 'green')) - t = threading.Thread(target=download_script_thread, args=(script,)) - script_threads.append(t) - t.start() + for cat_id, cat_info in config.CATEGORIES.items(): + icon = cat_info.get('icon', '•') + name = cat_info['name'] + desc = cat_info['description'] - for t in script_threads: - t.join() + print(f"{colorize(str(idx) + ')', 'green')} {icon} {colorize(name, 'white')}") + print(f" {desc}") + print() - print(colored("[*] All scripts downloaded", 'green')) + category_map[str(idx)] = cat_id + idx += 1 - download_script(scripts) + print(colorize("0)", 'red') + " Back to Main Menu") + print() -try: - apt_tools() - opt_tools() - go_tools() - docker_tools() - useful_scripts() -except KeyboardInterrupt: - print(colored(f"[*] Exiting: KeyboardInterrupt", 'red')) + return category_map -print(colored("[*] Installation Complete", 'magenta')) -print(colored("[*] Reboot Recommended", 'magenta')) -print(colored("[*] You are now Equipped!", 'green')) + +def category_menu(distro_type: str, logger): + """Category selection menu""" + while True: + category_map = show_category_menu() + choice = input(colorize("Select category: ", 'yellow')).strip() + + if choice == '0': + return + elif choice in category_map: + category_id = category_map[choice] + tool_selection_menu(category_id, distro_type, logger) + else: + print_error("Invalid option. Please try again.") + input("\nPress Enter to continue...") + + +# ============================================================================ +# Level 3: Tool Selection Menu +# ============================================================================ + +def show_tool_selection_menu(category_id: str, distro_type: str): + """Display tool selection menu for a category""" + cat_info = config.CATEGORIES[category_id] + print_section(f"{cat_info['icon']} {cat_info['name']}") + print_info(cat_info['description']) + print() + + print(colorize("1)", 'green') + " Install All Tools in Category") + print(colorize("2)", 'green') + " Select Specific Tools (Coming Soon)") + print() + print(colorize("0)", 'red') + " Back") + print() + + +def tool_selection_menu(category_id: str, distro_type: str, logger): + """Tool selection menu for a category""" + while True: + show_tool_selection_menu(category_id, distro_type) + choice = input(colorize("Select option: ", 'yellow')).strip() + + if choice == '0': + return + elif choice == '1': + install_category_all(category_id, distro_type, logger) + elif choice == '2': + print_warning("Individual tool selection coming in next update!") + input("\nPress Enter to continue...") + else: + print_error("Invalid option. Please try again.") + input("\nPress Enter to continue...") + + +def install_category_all(category_id: str, distro_type: str, logger): + """Install all tools in a category""" + cat_info = config.CATEGORIES[category_id] + print_section(f"Installing All {cat_info['name']}") + + success = False + + if category_id == 'apt': + success = installer.install_apt_tools(distro_type=distro_type, logger=logger) + elif category_id == 'go': + success = installer.install_go_tools(logger=logger) + elif category_id == 'opt': + success = installer.install_opt_tools(distro_type=distro_type, logger=logger) + elif category_id == 'python': + success = installer.install_python_tools(logger=logger) + elif category_id == 'docker': + success = installer.install_docker_tools(logger=logger) + elif category_id == 'scripts': + success = installer.download_useful_scripts(logger=logger) + + print() + if success: + print_success(f"{cat_info['name']} installation complete!") + else: + print_warning(f"{cat_info['name']} installation completed with some errors") + + input("\nPress Enter to continue...") + + +# ============================================================================ +# View Installed Tools +# ============================================================================ + +def view_installed_tools(): + """Display currently installed tools""" + print_section("INSTALLED TOOLS") + + # Check APT tools + print(colorize("📦 APT Tools:", 'cyan')) + apt_tools = config.get_apt_tools_for_distro('kali') # Use max list + for tool in apt_tools: + check_name = tool.replace('.io', '').replace('-', '') + if check_command_exists(check_name): + print(colorize(f" ✓ {tool}", 'green')) + + print() + + # Check Go tools + print(colorize("🔷 Go Tools:", 'cyan')) + for tool_name in config.GO_TOOLS.keys(): + if check_command_exists(tool_name): + print(colorize(f" ✓ {tool_name}", 'green')) + + print() + + # Check Docker tools + print(colorize("🐳 Docker Tools:", 'cyan')) + for tool_name in config.DOCKER_TOOLS.keys(): + if check_command_exists(tool_name): + print(colorize(f" ✓ {tool_name}", 'green')) + + print() + input("Press Enter to continue...") + + +# ============================================================================ +# Main Entry Point +# ============================================================================ + +def main(): + """Main entry point""" + # System checks + check_root_discourage() + + if not check_apt(): + print_error("APT package manager not found!") + print_error("This tool currently only supports Debian-based systems.") + sys.exit(1) + + if not check_sudo(): + print_error("sudo not found! Please install sudo first.") + sys.exit(1) + + # Setup logging + logger = setup_logging() + + # Detect distribution + distro_name, distro_type = detect_distro() + logger.info(f"Detected distribution: {distro_name} (type: {distro_type})") + + # Check for fresh (optional) + prompt_install_fresh() + + # Enter main menu loop + try: + main_menu_loop(distro_name, distro_type, logger) + except KeyboardInterrupt: + print() + print() + print_warning("Installation interrupted by user") + logger.info("Installation interrupted by user (KeyboardInterrupt)") + sys.exit(0) + except Exception as e: + print() + print_error(f"Unexpected error: {e}") + logger.error(f"Unexpected error: {e}", exc_info=True) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/toolbelt.sh b/toolbelt.sh.old similarity index 100% rename from toolbelt.sh rename to toolbelt.sh.old diff --git a/toolbelt_old.py b/toolbelt_old.py new file mode 100644 index 0000000..0183035 --- /dev/null +++ b/toolbelt_old.py @@ -0,0 +1,306 @@ +#!/usr/bin/python3 + +###################### +''' Djedi Toolbelt ''' +''' Python3 Reboot ''' +###################### + +''' +######################################################################### + +WARNING: + + This script is approximately 5 GB and will take a while to run. + + Please make sure you check this before installing. + + Menu will be coming in one of the next updates to help + cater to your preferences and custom requirements. + +######################################################################### +''' + +''' +TO DO: + + Finish - apt threading (sort of, with apt-fast) + + Add - Menu selection for the various categories: + - apt tools only + - opt tools only + - python tools only + - go tools only + - docker tools only + - scripts only + + Threading for /opt tools + + Find out where scripts are actually downloading + + Add C2 - Probably Havoc + Add PowerView (if not already included) + + Double-check all tools + + Add section for Bug Bounty tools + + Add section for API tools + + Add option to download the recon.py automation script, + which uses this toolbelt + +''' + +import subprocess, os, threading +from concurrent.futures import ThreadPoolExecutor, as_completed +from termcolor import colored +from tqdm import tqdm + +threads = [] + +# Check if the user is running as root +if os.geteuid() != 0: + print(colored("Please run as root", 'red')) + exit(1) + +''' +subprocess.run(["pip", "install", "progress"]) + +tools = ["tool1", "tool2", "tool3"] +bar = Bar('Installing', max=len(tools)) +for tool in tools: + # Code to install the tool + bar.next() +bar.finish() +''' + +# Figlet +os.system("figlet DjediToolbelt | lolcat") + +# Version +print("v.0.3\n") + +# Message +print(colored("[*] Installing Pentest & Bug Bounty Toolbox Suite", 'magenta')) + +######################### +''' Aptitude Programs ''' +######################### + +def apt_tools(): + subprocess.run(["sudo", "apt", "update"]) + subprocess.run(["sudo", "apt", "install", "apt-fast"]) + + programs = ["nmap", "naabu", "nuclei", "burpsuite", "feroxbuster", "nikto", "masscan", "gobuster", "seclists", "sqlmap", "git"] + + for program in programs: + if os.system(f"command -v {program}") == 0: + print(colored(f"[*] {program} is already installed", 'blue')) + else: + print(colored(f"[+] Installing / updating {program}", 'green')) + os.system(f"sudo apt-fast install {program} -y") + if os.system(f"command -v {program}") != 0: + print(colored(f"[*] Error: Failed to install the program: {program}", 'red')) + exit(1) + os.system(f"sudo apt-fast install docker docker.io golang-go -y") + +################## +''' /opt Tools ''' +################## + +def opt_tools(): + # Pimpmykali + os.chdir("/opt") + if not os.path.isdir("/opt/pimpmykali"): + print(colored("[+] Installing pimpmykali...", 'green')) + os.system("sudo git clone https://github.com/Dewalt-arch/pimpmykali") + os.chdir("pimpmykali") + print(colored("[+] Installing Golang...", 'green')) + os.system("sudo ./pimpmykali.sh --go") + print(colored("[+] Installing Impacket...", 'green')) + os.system("sudo ./pimpmykali.sh --impacket") + os.system("sudo ./pimpmykali.sh --upgrade") + os.chdir("/opt") + else: + print(colored("[*] pimpmykali is already installed", 'blue')) + + # xnLinkFinder + if not os.path.isdir("/opt/xnLinkFinder"): + print(colored("[+] Installing xnLinkFinder...", 'green')) + os.system("git clone https://github.com/xnl-h4ck3r/xnLinkFinder.git") + os.chdir("xnLinkFinder") + os.system("sudo python setup.py install") + os.chdir("/opt") + else: + print(colored("[*] xnLinkFinder is already installed", 'blue')) + + # Knockpy + if not os.path.isdir("/opt/knock"): + print(colored("[+] Installing Knockpy...", 'green')) + os.system("sudo git clone https://github.com/guelfoweb/knock.git") + os.chdir("knock") + os.system("pip3 install -r requirements.txt") + os.chdir("/opt") + else: + print(colored("[*] Knockpy is already installed", 'blue')) + + # Sublist3r + if not os.path.isdir("/opt/Sublist3r"): + print(colored("[+] Installing Sublist3r...", 'green')) + os.system("sudo git clone https://github.com/aboul3la/Sublist3r.git") + os.chdir("Sublist3r") + os.system("pip install -r requirements.txt") + os.chdir("/opt") + else: + print(colored("[*] Sublist3r is already installed", 'blue')) + + # Striker + if not os.path.isdir("/opt/Striker"): + print(colored("[+] Installing Striker...", 'green')) + os.system("sudo git clone https://github.com/s0md3v/Striker.git") + os.chdir("Striker") + os.system("pip install -r requirements.txt") + os.chdir("/opt") + else: + print(colored("[*] Striker is already installed", 'blue')) + + # wafw00f + if not os.path.isdir("/opt/wafw00f"): + print(colored("[+] Installing wafw00f...", 'green')) + os.system("git clone https://github.com/EnableSecurity/wafw00f.git") + os.chdir("wafw00f") + os.system("pip3 install -r requirements.txt") + os.system("sudo python setup.py install") + os.chdir("/opt") + else: + print(colored("[*] wafw00f is already installed", 'blue')) + + # Waymore + if not os.path.isdir("/opt/waymore"): + print(colored("[+] Installing waymore...", 'green')) + os.system("git clone https://github.com/xnl-h4ck3r/waymore.git") + os.chdir("waymore") + os.system("pip3 install -r requirements.txt") + os.system("sudo python setup.py install") + os.chdir("/opt") + else: + print(colored("[*] waymore is already installed", 'blue')) + + # XSStrike + if not os.path.isdir("/opt/XSStrike"): + print(colored("[+] Installing XSStrike...", 'green')) + os.system("git clone https://github.com/s0md3v/XSStrike.git") + os.chdir("XSStrike") + os.system("pip3 install -r requirements.txt") + os.system("sudo python setup.py install") + os.chdir("/opt") + else: + print(colored("[*] XSStrike is already installed", 'blue')) + +#################### +''' Python Tools ''' +#################### + +def python_tools(): + print(colored("[+] Installing / Updating Python Tools...", 'green')) + subprocess.run(["pip3", "install", "--upgrade", "wfuzz"]) + subprocess.run(["pip3", "install", "arjun"]) + subprocess.run(["pip3", "install", "scrapy"]) + subprocess.run(["pip3", "install", "tld"]) + subprocess.run(["pip3", "install", "requests"]) + subprocess.run(["pip3", "install", "fuzzywuzzy"]) + +################ +''' Go Tools ''' +################ + +def go_tools(): + print(colored("[+] Installing / Updating Go Tools...", 'green')) + commands = [ + ["go", "install", "-v", "github.com/projectdiscovery/naabu/v2/cmd/naabu@latest"], + ["go", "install", "-v", "github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest"], + ["go", "install", "-v", "github.com/projectdiscovery/katana/cmd/katana@latest"], + ["go", "install", "-v", "github.com/projectdiscovery/httpx/cmd/httpx@latest"], + ["go", "install", "-v", "github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest"], + ["go", "install", "-v", "github.com/OWASP/Amass/v3/...@master"], + ["go", "install", "-v", "github.com/tomnomnom/assetfinder@latest"], + ["go", "install", "-v", "github.com/tomnomnom/httprobe@latest"], + ["go", "install", "-v", "github.com/sensepost/gowitness@latest"], + ["go", "install", "-v", "github.com/haccer/subjack@latest"], + ["go", "install", "-v", "github.com/hakluke/hakrawler@latest"], + ["go", "install", "-v", "github.com/rverton/webanalyze/cmd/webanalyze@latest"], + ] + + with ThreadPoolExecutor() as executor: + results = [executor.submit(subprocess.run, cmd) for cmd in commands] + for f in as_completed(results): + print(colored(f.result(), 'green')) + +#################### +''' Docker Tools ''' +#################### + +def docker_tools(): + # RustScan + print(colored("[+] Installing / Updating RustScan...", 'green')) + os.system("docker pull rustscan/rustscan:2.0.1") + if os.path.isfile("~/.zshrc"): + print(colored("[+] adding rustscan alias to ~/.zshrc", 'green')) + with open("~/.zshrc", "a") as f: + f.write("alias rustscan='docker run -it --rm --name rustscan rustscan/rustscan:2.0.1'") + elif os.path.isfile("~/.bashrc"): + print(colored("[+] adding rustscan alias to ~/.bashrc", 'green')) + with open("~/.bashrc", "a") as f: + f.write("alias rustscan='docker run -it --rm --name rustscan rustscan/rustscan:2.0.1'") + +############### +''' Scripts ''' +############### + +def useful_scripts(): + def scripts_dir(): + if not os.path.isdir(os.path.expanduser("~/scripts")): + # os.chdir(["cd", os.path.expanduser("~")]) + os.chdir(os.path.expanduser("~")) + os.makedirs(os.path.expanduser("~/scripts"), exist_ok=True) + os.chdir(os.path.expanduser("~/scripts")) + subprocess.run(["echo", "created", "scripts", "and", "moved", "into", "it"]) + else: + os.chdir(os.path.expanduser("~/scripts")) + subprocess.run(["echo", "directory", "/scripts", "already", "exists,", "moving", "into", "it"]) + + scripts_dir() + + scripts = ["https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh", "https://github.com/411Hall/JAWS/raw/master/jaws-enum.ps1", "https://github.com/rebootuser/LinEnum/raw/master/LinEnum.sh", "https://github.com/carlospolop/PEASS-ng/releases/download/20230122/winPEASany_ofs.exe", "https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php", "https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh", "https://github.com/PowerShellMafia/PowerSploit/raw/master/Recon/PowerView.ps1"] + + script_threads = [] + + def download_script_thread(script): + subprocess.run(f"wget {script}", shell=True) + + def download_script(scripts): + for script in tqdm(scripts): + print(colored(f"[+] Grabbing {script}", 'green')) + t = threading.Thread(target=download_script_thread, args=(script,)) + script_threads.append(t) + t.start() + + for t in script_threads: + t.join() + + print(colored("[*] All scripts downloaded", 'green')) + + download_script(scripts) + +try: + apt_tools() + opt_tools() + go_tools() + docker_tools() + useful_scripts() +except KeyboardInterrupt: + print(colored(f"[*] Exiting: KeyboardInterrupt", 'red')) + +print(colored("[*] Installation Complete", 'magenta')) +print(colored("[*] Reboot Recommended", 'magenta')) +print(colored("[*] You are now Equipped!", 'green')) diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..440b8f2 --- /dev/null +++ b/utils.py @@ -0,0 +1,354 @@ +#!/usr/bin/env python3 +""" +Djedi Toolbelt - Utility Functions +Provides distro detection, logging, and helper functions +""" + +import os +import sys +import subprocess +import logging +from pathlib import Path +from datetime import datetime +from typing import Optional, List, Tuple + + +# ============================================================================ +# Distro Detection +# ============================================================================ + +def detect_distro() -> Tuple[str, str]: + """ + Detect the Linux distribution + + Returns: + Tuple of (distro_name, distro_type) + distro_type is one of: 'kali', 'debian', 'ubuntu', 'unknown' + """ + distro_name = "Unknown" + distro_type = "unknown" + + if not os.path.exists('/etc/os-release'): + return (distro_name, distro_type) + + try: + with open('/etc/os-release', 'r') as f: + content = f.read() + + # Extract PRETTY_NAME + for line in content.split('\n'): + if line.startswith('PRETTY_NAME='): + distro_name = line.split('=')[1].strip('"') + break + + # Determine distro type + content_lower = content.lower() + if 'kali' in content_lower: + distro_type = 'kali' + elif 'debian' in content_lower: + distro_type = 'debian' + elif 'ubuntu' in content_lower: + distro_type = 'ubuntu' + + except Exception as e: + logging.error(f"Error detecting distro: {e}") + + return (distro_name, distro_type) + + +def is_kali() -> bool: + """Check if running on Kali Linux""" + _, distro_type = detect_distro() + return distro_type == 'kali' + + +def is_debian_based() -> bool: + """Check if running on Debian-based system (Debian, Ubuntu, Kali)""" + _, distro_type = detect_distro() + return distro_type in ['kali', 'debian', 'ubuntu'] + + +# ============================================================================ +# Logging Setup +# ============================================================================ + +def setup_logging(log_file: Optional[str] = None) -> logging.Logger: + """ + Setup logging with both file and console output + + Args: + log_file: Optional path to log file. Defaults to ~/toolbelt-install.log + + Returns: + Configured logger instance + """ + if log_file is None: + log_file = os.path.expanduser("~/toolbelt-install.log") + + # Create logger + logger = logging.getLogger('toolbelt') + logger.setLevel(logging.DEBUG) + + # Clear existing handlers + logger.handlers.clear() + + # File handler (DEBUG level) + file_handler = logging.FileHandler(log_file, mode='a') + file_handler.setLevel(logging.DEBUG) + file_formatter = logging.Formatter( + '[%(asctime)s] [%(levelname)s] %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' + ) + file_handler.setFormatter(file_formatter) + + # Console handler (INFO level) + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setLevel(logging.INFO) + console_formatter = logging.Formatter('[%(levelname)s] %(message)s') + console_handler.setFormatter(console_formatter) + + # Add handlers + logger.addHandler(file_handler) + logger.addHandler(console_handler) + + # Log session start + logger.info("=" * 60) + logger.info(f"Toolbelt session started: {datetime.now()}") + logger.info("=" * 60) + + return logger + + +# ============================================================================ +# System Checks +# ============================================================================ + +def is_root() -> bool: + """Check if running as root""" + return os.geteuid() == 0 + + +def check_root_discourage(): + """Warn user if running as root (we don't want root!)""" + if is_root(): + print("\033[91m") # Red + print("=" * 60) + print("WARNING: Running as root is NOT recommended!") + print("=" * 60) + print("\033[0m") # Reset + print() + print("This script will use sudo for specific commands that need it.") + print("Running the entire script as root can cause issues:") + print(" • Scripts download to /root instead of your home directory") + print(" • Files owned by root instead of your user") + print(" • Potential security issues") + print() + response = input("Continue anyway? [y/N]: ").strip().lower() + if response != 'y': + print("Exiting. Please run without sudo/root.") + sys.exit(0) + + +def check_command_exists(command: str) -> bool: + """ + Check if a command exists in PATH + + Args: + command: Command name to check + + Returns: + True if command exists, False otherwise + """ + try: + result = subprocess.run( + ['which', command], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + return result.returncode == 0 + except Exception: + return False + + +def check_apt() -> bool: + """Check if apt package manager is available""" + return check_command_exists('apt') + + +def check_sudo() -> bool: + """Check if sudo is available""" + return check_command_exists('sudo') + + +# ============================================================================ +# Helper Functions +# ============================================================================ + +def run_command( + cmd: List[str], + use_sudo: bool = False, + shell: bool = False, + check: bool = True, + logger: Optional[logging.Logger] = None +) -> subprocess.CompletedProcess: + """ + Run a command with optional sudo + + Args: + cmd: Command and arguments as list + use_sudo: Prepend sudo if True + shell: Run as shell command if True + check: Raise exception on non-zero exit if True + logger: Optional logger instance + + Returns: + CompletedProcess instance + """ + if use_sudo and not is_root(): + if isinstance(cmd, list): + cmd = ['sudo'] + cmd + else: + cmd = f"sudo {cmd}" + + if logger: + cmd_str = ' '.join(cmd) if isinstance(cmd, list) else cmd + logger.debug(f"Running: {cmd_str}") + + try: + result = subprocess.run( + cmd, + shell=shell, + check=check, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + return result + except subprocess.CalledProcessError as e: + if logger: + logger.error(f"Command failed: {e.cmd}") + logger.error(f"Exit code: {e.returncode}") + if e.stdout: + logger.error(f"Stdout: {e.stdout}") + if e.stderr: + logger.error(f"Stderr: {e.stderr}") + raise + + +def ensure_directory(path: str, use_sudo: bool = False) -> bool: + """ + Ensure directory exists, create if necessary + + Args: + path: Directory path + use_sudo: Use sudo to create if True + + Returns: + True if directory exists or was created successfully + """ + expanded_path = os.path.expanduser(path) + + if os.path.isdir(expanded_path): + return True + + try: + if use_sudo: + subprocess.run(['sudo', 'mkdir', '-p', expanded_path], check=True) + else: + os.makedirs(expanded_path, exist_ok=True) + return True + except Exception as e: + logging.error(f"Failed to create directory {expanded_path}: {e}") + return False + + +def get_home_dir() -> str: + """ + Get the actual user's home directory (not /root even if running as root) + + Returns: + Path to user's home directory + """ + # If running as root, try to get the original user's home + if is_root(): + sudo_user = os.environ.get('SUDO_USER') + if sudo_user: + return os.path.expanduser(f"~{sudo_user}") + + # Otherwise return normal home + return os.path.expanduser("~") + + +def colorize(text: str, color: str) -> str: + """ + Colorize text for terminal output + + Args: + text: Text to colorize + color: Color name (red, green, yellow, blue, magenta, cyan) + + Returns: + Colorized text string + """ + colors = { + 'red': '\033[91m', + 'green': '\033[92m', + 'yellow': '\033[93m', + 'blue': '\033[94m', + 'magenta': '\033[95m', + 'cyan': '\033[96m', + 'white': '\033[97m', + 'reset': '\033[0m' + } + + color_code = colors.get(color.lower(), colors['reset']) + return f"{color_code}{text}{colors['reset']}" + + +# ============================================================================ +# Display Functions +# ============================================================================ + +def print_banner(): + """Print the toolbelt banner""" + banner = """ +╔══════════════════════════════════════════════════════════╗ +║ ║ +║ 🔧 DJEDI TOOLBELT 🔧 ║ +║ ║ +║ Comprehensive Security Tool Installer ║ +║ ║ +╚══════════════════════════════════════════════════════════╝ +""" + print(colorize(banner, 'cyan')) + print(colorize(" v2.0.0", 'magenta')) + print() + + +def print_section(title: str): + """Print a section header""" + print() + print(colorize("=" * 60, 'cyan')) + print(colorize(f" {title}", 'white')) + print(colorize("=" * 60, 'cyan')) + print() + + +def print_success(message: str): + """Print success message""" + print(colorize(f"✓ {message}", 'green')) + + +def print_info(message: str): + """Print info message""" + print(colorize(f"• {message}", 'blue')) + + +def print_warning(message: str): + """Print warning message""" + print(colorize(f"⚠ {message}", 'yellow')) + + +def print_error(message: str): + """Print error message""" + print(colorize(f"✗ {message}", 'red'))