mirror of
https://github.com/Z4nzu/hackingtool
synced 2026-05-22 08:28:57 +00:00
post_exploitation.py: - Rename INSTALL_OS -> SUPPORTED_OS in Havoc class (typo, field was ignored) - Sliver: replace curl|sudo bash pipe with download-then-execute pattern ddos.py: - Add DDoSTool() to DDOSTools.TOOLS list (was defined but unreachable) phishing_attack.py: - Rename class Evilginx2 -> Evilginx3 (installs v3 via go install) - Update instance in TOOLS list to match - Fix stale comment: wireless_attack_tools.py -> wireless_attack.py forensics.py: - Remove installable=False from Guymager (conflicted with INSTALL_COMMANDS) tool_manager.py: - Skip sudo prefix when already root (os.geteuid() == 0), matching the pattern already used in install.py install.py: - Add chown -R root:root after cp -a to prevent git "dubious ownership" errors when the source clone has different ownership update.sh: - Add git config safe.directory before pull to prevent dubious ownership - Add --upgrade flag to pip install so dependencies actually update os_detect.py: - Add pkg (FreeBSD) entries to PACKAGE_INSTALL_CMDS, PACKAGE_UPDATE_CMDS, and REQUIRED_PACKAGES — was detected but had no command mappings (KeyError) Skipped (not applicable): - #1 subprocess import: already fixed in prior commit - #11 Path.home() under sudo: by design (installer runs as root)
272 lines
11 KiB
Python
Executable file
272 lines
11 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
# ── Python version check (must be before any other local import) ──────────────
|
|
if sys.version_info < (3, 10):
|
|
print(
|
|
f"[ERROR] Python 3.10 or newer is required.\n"
|
|
f"You are running Python {sys.version_info.major}.{sys.version_info.minor}.\n"
|
|
f"Install with: sudo apt install python3.10"
|
|
)
|
|
sys.exit(1)
|
|
|
|
from rich.console import Console
|
|
from rich.panel import Panel
|
|
from rich.prompt import Confirm
|
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
from rich.text import Text
|
|
from rich import box
|
|
|
|
from constants import (
|
|
REPO_URL, APP_INSTALL_DIR, APP_BIN_PATH,
|
|
VERSION, VERSION_DISPLAY,
|
|
USER_CONFIG_DIR, USER_TOOLS_DIR, USER_CONFIG_FILE,
|
|
DEFAULT_CONFIG,
|
|
)
|
|
from os_detect import CURRENT_OS, REQUIRED_PACKAGES, PACKAGE_UPDATE_CMDS, PACKAGE_INSTALL_CMDS
|
|
|
|
console = Console()
|
|
|
|
VENV_DIR_NAME = "venv"
|
|
REQUIREMENTS = "requirements.txt"
|
|
|
|
|
|
# ── Privilege check ────────────────────────────────────────────────────────────
|
|
|
|
def check_root():
|
|
if os.geteuid() != 0:
|
|
console.print(Panel(
|
|
"[error]This installer must be run as root.\n"
|
|
"Use: [bold]sudo python3 install.py[/bold][/error]",
|
|
border_style="red",
|
|
))
|
|
sys.exit(1)
|
|
|
|
|
|
# ── OS compatibility check ─────────────────────────────────────────────────────
|
|
|
|
def check_os_compatibility():
|
|
"""Print detected OS info and exit on unsupported systems."""
|
|
info = CURRENT_OS
|
|
console.print(
|
|
f"[dim]Detected: OS={info.system} | distro={info.distro_id or 'n/a'} | "
|
|
f"pkg_mgr={info.pkg_manager or 'none'} | arch={info.arch}[/dim]"
|
|
)
|
|
|
|
if info.system == "windows":
|
|
console.print(Panel(
|
|
"[error]Windows is not supported natively.[/error]\n"
|
|
"Use WSL2 with a Kali or Ubuntu image.",
|
|
border_style="red",
|
|
))
|
|
sys.exit(1)
|
|
|
|
if info.is_wsl:
|
|
console.print("[warning]WSL detected. Wireless tools will NOT work in WSL.[/warning]")
|
|
|
|
if info.system == "macos":
|
|
console.print(Panel(
|
|
"[warning]macOS support is partial.[/warning]\n"
|
|
"Network/wireless tools require Linux. OSINT and web tools work.",
|
|
border_style="yellow",
|
|
))
|
|
if not shutil.which("brew"):
|
|
console.print("[error]Homebrew not found. Install it first: https://brew.sh[/error]")
|
|
sys.exit(1)
|
|
|
|
if not info.pkg_manager:
|
|
console.print("[warning]No supported package manager found.[/warning]")
|
|
console.print("[dim]Supported: apt-get, pacman, dnf, zypper, apk, brew[/dim]")
|
|
|
|
|
|
# ── Internet check ─────────────────────────────────────────────────────────────
|
|
|
|
def check_internet() -> bool:
|
|
console.print("[dim]Checking internet...[/dim]")
|
|
for host in ("https://github.com", "https://www.google.com"):
|
|
r = subprocess.run(
|
|
["curl", "-sSf", "--max-time", "8", host],
|
|
capture_output=True,
|
|
)
|
|
if r.returncode == 0:
|
|
console.print("[success]✔ Internet connection OK[/success]")
|
|
return True
|
|
console.print("[error]✘ No internet connection[/error]")
|
|
return False
|
|
|
|
|
|
# ── System packages ────────────────────────────────────────────────────────────
|
|
|
|
def install_system_packages():
|
|
mgr = CURRENT_OS.pkg_manager
|
|
if not mgr:
|
|
console.print("[warning]Skipping system packages — no package manager found.[/warning]")
|
|
return
|
|
|
|
# Use sudo only when not already root (uid != 0).
|
|
# Inside Docker we run as root and sudo is not installed.
|
|
priv = "" if os.geteuid() == 0 else "sudo "
|
|
|
|
# Update index first (skip for brew — not needed)
|
|
if mgr != "brew":
|
|
update_cmd = PACKAGE_UPDATE_CMDS.get(mgr, "")
|
|
if update_cmd:
|
|
console.print(f"[dim]Updating package index ({mgr})...[/dim]")
|
|
subprocess.run(f"{priv}{update_cmd}", shell=True, check=False)
|
|
|
|
packages = REQUIRED_PACKAGES.get(mgr, [])
|
|
if not packages:
|
|
return
|
|
|
|
install_tpl = PACKAGE_INSTALL_CMDS[mgr]
|
|
cmd = install_tpl.format(packages=" ".join(packages))
|
|
console.print(f"[dim]Installing system dependencies ({mgr})...[/dim]")
|
|
result = subprocess.run(f"{priv}{cmd}", shell=True, check=False)
|
|
if result.returncode != 0:
|
|
console.print("[warning]Some packages failed — you may need to install them manually.[/warning]")
|
|
|
|
|
|
# ── App directory ──────────────────────────────────────────────────────────────
|
|
|
|
def _is_source_dir() -> bool:
|
|
"""Check if install.py is being run from a local clone (hackingtool.py exists alongside it)."""
|
|
return (Path(__file__).resolve().parent / "hackingtool.py").exists()
|
|
|
|
|
|
def prepare_install_dir():
|
|
if APP_INSTALL_DIR.exists():
|
|
console.print(f"[warning]{APP_INSTALL_DIR} already exists.[/warning]")
|
|
if not Confirm.ask("Replace it? This removes the existing installation.", default=False):
|
|
console.print("[error]Installation aborted.[/error]")
|
|
sys.exit(1)
|
|
subprocess.run(["rm", "-rf", str(APP_INSTALL_DIR)], check=True)
|
|
APP_INSTALL_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
def install_source() -> bool:
|
|
"""Clone the repo or copy from local source if already in a clone."""
|
|
source_dir = Path(__file__).resolve().parent
|
|
|
|
if _is_source_dir() and source_dir != APP_INSTALL_DIR:
|
|
# Already in a local clone — copy instead of re-cloning
|
|
console.print(f"[dim]Copying source from {source_dir}...[/dim]")
|
|
# Remove first to ensure clean copy (prepare_install_dir may have created it)
|
|
if APP_INSTALL_DIR.exists():
|
|
subprocess.run(["rm", "-rf", str(APP_INSTALL_DIR)], check=True)
|
|
subprocess.run(["cp", "-a", str(source_dir), str(APP_INSTALL_DIR)], check=True)
|
|
# Fix ownership so git doesn't complain about "dubious ownership"
|
|
subprocess.run(["chown", "-R", "root:root", str(APP_INSTALL_DIR)], check=False)
|
|
console.print("[success]✔ Source copied (no re-clone needed)[/success]")
|
|
return True
|
|
|
|
# Not running from source — clone from GitHub
|
|
console.print(f"[dim]Cloning {REPO_URL}...[/dim]")
|
|
r = subprocess.run(["git", "clone", "--depth", "1", REPO_URL, str(APP_INSTALL_DIR)], check=False)
|
|
if r.returncode == 0:
|
|
console.print("[success]✔ Repository cloned[/success]")
|
|
return True
|
|
console.print("[error]✘ Failed to clone repository[/error]")
|
|
return False
|
|
|
|
|
|
# ── Python venv ────────────────────────────────────────────────────────────────
|
|
|
|
def create_venv_and_install():
|
|
venv_path = APP_INSTALL_DIR / VENV_DIR_NAME
|
|
console.print("[dim]Creating virtual environment...[/dim]")
|
|
subprocess.run([sys.executable, "-m", "venv", str(venv_path)], check=True)
|
|
|
|
pip = str(venv_path / "bin" / "pip")
|
|
req = APP_INSTALL_DIR / REQUIREMENTS
|
|
if req.exists():
|
|
console.print("[dim]Installing Python requirements...[/dim]")
|
|
subprocess.run([pip, "install", "--quiet", "-r", str(req)], check=False)
|
|
else:
|
|
console.print("[warning]requirements.txt not found — skipping pip install.[/warning]")
|
|
|
|
|
|
# ── Launcher script ────────────────────────────────────────────────────────────
|
|
|
|
def create_launcher():
|
|
launcher = APP_INSTALL_DIR / "hackingtool.sh"
|
|
launcher.write_text(
|
|
"#!/bin/bash\n"
|
|
f'source "{APP_INSTALL_DIR / VENV_DIR_NAME}/bin/activate"\n'
|
|
f'python3 "{APP_INSTALL_DIR / "hackingtool.py"}" "$@"\n'
|
|
)
|
|
launcher.chmod(0o755)
|
|
if APP_BIN_PATH.exists():
|
|
APP_BIN_PATH.unlink()
|
|
shutil.move(str(launcher), str(APP_BIN_PATH))
|
|
console.print(f"[success]✔ Launcher installed at {APP_BIN_PATH}[/success]")
|
|
|
|
|
|
# ── User directories ───────────────────────────────────────────────────────────
|
|
|
|
def create_user_directories():
|
|
"""
|
|
Create ~/.hackingtool/ and write initial config.json.
|
|
Uses Path.home() — always correct regardless of username or OS.
|
|
Safe to run as root (creates /root/.hackingtool/) or as a normal user.
|
|
"""
|
|
import json
|
|
USER_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
USER_TOOLS_DIR.mkdir(parents=True, exist_ok=True)
|
|
if not USER_CONFIG_FILE.exists():
|
|
USER_CONFIG_FILE.write_text(json.dumps(DEFAULT_CONFIG, indent=2, sort_keys=True))
|
|
console.print(f"[success]✔ Config created at {USER_CONFIG_FILE}[/success]")
|
|
console.print(f"[success]✔ Tools directory: {USER_TOOLS_DIR}[/success]")
|
|
|
|
|
|
# ── Entry point ────────────────────────────────────────────────────────────────
|
|
|
|
def main():
|
|
check_root()
|
|
console.clear()
|
|
|
|
console.print(Panel(
|
|
Text(f"HackingTool Installer {VERSION_DISPLAY}", style="bold magenta"),
|
|
box=box.DOUBLE, border_style="bright_magenta",
|
|
))
|
|
|
|
check_os_compatibility()
|
|
|
|
if not check_internet():
|
|
sys.exit(1)
|
|
|
|
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}")) as p:
|
|
p.add_task("Installing system packages...", total=None)
|
|
install_system_packages()
|
|
|
|
prepare_install_dir()
|
|
|
|
if not install_source():
|
|
sys.exit(1)
|
|
|
|
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}")) as p:
|
|
p.add_task("Setting up virtualenv & requirements...", total=None)
|
|
create_venv_and_install()
|
|
|
|
create_launcher()
|
|
create_user_directories()
|
|
|
|
console.print(Panel(
|
|
"[bold magenta]Installation complete![/bold magenta]\n\n"
|
|
"Type [bold cyan]hackingtool[/bold cyan] in a terminal to start.",
|
|
border_style="magenta",
|
|
))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except KeyboardInterrupt:
|
|
console.print("\n[error]Installation interrupted.[/error]")
|
|
sys.exit(1)
|
|
except subprocess.CalledProcessError as e:
|
|
console.print(f"[error]Command failed: {e}[/error]")
|
|
sys.exit(1)
|