Commit a46f0100 authored by Hardik Zinzuvadiya's avatar Hardik Zinzuvadiya
Browse files

Phase 1+2: Fix all 30 critical bugs and 4 security vulnerabilities

parent 6a32c8ac
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
FROM kalilinux/kali-rolling:latest

RUN apt-get update && \
    apt-get install -y git python3-pip figlet sudo && \
    apt-get install -y boxes php curl xdotool wget
    apt-get install -y --no-install-recommends \
        git python3-pip python3-venv sudo curl wget php && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /root/hackingtool
COPY requirements.txt ./
RUN pip3 install --no-cache-dir boxes flask lolcat requests -r requirements.txt

# Bug 21 fix: boxes/lolcat/flask are NOT pip packages — removed
RUN pip3 install --no-cache-dir -r requirements.txt

COPY . .
RUN true && echo "/root/hackingtool/" > /home/hackingtoolpath.txt;
EXPOSE 1-65535

# Bug 20 fix: path file must be in /root/ not /home/ (running as root in Docker)
RUN mkdir -p /root/.hackingtool/tools

# Vuln 3 fix: removed EXPOSE 1-65535 — this tool is a CLI, not a server
ENTRYPOINT ["python3", "/root/hackingtool/hackingtool.py"]
+224 −118
Original line number Diff line number Diff line
import os
import sys
import webbrowser
from collections.abc import Callable
from platform import system

from rich import box
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
from rich.table import Table
from rich import box
from rich.traceback import install
from rich.theme import Theme
from rich.traceback import install

import os
import sys
import webbrowser
from platform import system
from traceback import print_exc
from typing import Callable, List, Tuple
from constants import (
    THEME_PRIMARY, THEME_BORDER, THEME_ACCENT,
    THEME_SUCCESS, THEME_ERROR, THEME_WARNING,
    THEME_DIM, THEME_ARCHIVED, THEME_URL,
)

# Enable rich tracebacks
# Enable rich tracebacks globally
install()
_theme = Theme({"purple": "#7B61FF"})

_theme = Theme({
    "purple":   "#7B61FF",
    "success":  THEME_SUCCESS,
    "error":    THEME_ERROR,
    "warning":  THEME_WARNING,
    "archived": THEME_ARCHIVED,
    "url":      THEME_URL,
    "dim":      THEME_DIM,
})

# Single shared console — all tool files do: from core import console
console = Console(theme=_theme)


@@ -22,46 +39,68 @@ def clear_screen():
    os.system("cls" if system() == "Windows" else "clear")


def validate_input(ip, val_range):
    val_range = val_range or []
def validate_input(ip, val_range: list) -> int | None:
    """Return the integer if it is in val_range, else None."""
    if not val_range:
        return None
    try:
        ip = int(ip)
        if ip in val_range:
            return ip
    except Exception:
        return None
    except (TypeError, ValueError):
        pass
    return None


class HackingTool(object):
class HackingTool:
    TITLE: str              = ""
    DESCRIPTION: str        = ""
    INSTALL_COMMANDS: List[str] = []
    INSTALLATION_DIR: str = ""
    UNINSTALL_COMMANDS: List[str] = []
    RUN_COMMANDS: List[str] = []
    OPTIONS: List[Tuple[str, Callable]] = []
    INSTALL_COMMANDS: list[str]  = []
    UNINSTALL_COMMANDS: list[str] = []
    RUN_COMMANDS: list[str]      = []
    OPTIONS: list[tuple[str, Callable]] = []
    PROJECT_URL: str        = ""

    # OS / capability metadata
    SUPPORTED_OS: list[str] = ["linux", "macos"]
    REQUIRES_ROOT: bool     = False
    REQUIRES_WIFI: bool     = False
    REQUIRES_GO: bool       = False
    REQUIRES_RUBY: bool     = False
    REQUIRES_JAVA: bool     = False
    REQUIRES_DOCKER: bool   = False

    # Archived tool flags
    ARCHIVED: bool          = False
    ARCHIVED_REASON: str    = ""

    def __init__(self, options=None, installable=True, runnable=True):
        options = options or []
        if isinstance(options, list):
        if not isinstance(options, list):
            raise TypeError("options must be a list of (option_name, option_fn) tuples")
        self.OPTIONS = []
        if installable:
            self.OPTIONS.append(("Install", self.install))
        if runnable:
            self.OPTIONS.append(("Run", self.run))
        self.OPTIONS.extend(options)
        else:
            raise Exception("options must be a list of (option_name, option_fn) tuples")

    def show_info(self):
        desc = f"[cyan]{self.DESCRIPTION}[/cyan]"
        if self.PROJECT_URL:
            desc += f"\n[green]🔗 {self.PROJECT_URL}[/green]"
        console.print(Panel(desc, title=f"[bold purple]{self.TITLE}[/bold purple]", border_style="purple", box=box.DOUBLE))
            desc += f"\n[url]🔗 {self.PROJECT_URL}[/url]"
        if self.ARCHIVED:
            desc += f"\n[archived]⚠ ARCHIVED: {self.ARCHIVED_REASON}[/archived]"
        console.print(Panel(
            desc,
            title=f"[{THEME_PRIMARY}]{self.TITLE}[/{THEME_PRIMARY}]",
            border_style="purple",
            box=box.DOUBLE,
        ))

    def show_options(self, parent=None):
        """Iterative menu loop — no recursion, no stack growth."""
        while True:
            clear_screen()
            self.show_info()

@@ -75,42 +114,43 @@ class HackingTool(object):
            if self.PROJECT_URL:
                table.add_row("98", "Open Project Page")
            table.add_row("99", f"Back to {parent.TITLE if parent else 'Exit'}")

            console.print(table)

        option_index = input("\n[?] Select an option: ").strip()
            raw = Prompt.ask("\n[bold cyan][?] Select an option[/bold cyan]", default="99")
            try:
            option_index = int(option_index)
            if option_index - 1 in range(len(self.OPTIONS)):
                ret_code = self.OPTIONS[option_index - 1][1]()
                if ret_code != 99:
                    input("\nPress [Enter] to continue...")
            elif option_index == 98:
                self.show_project_page()
            elif option_index == 99:
                choice = int(raw)
            except ValueError:
                console.print("[error]⚠ Please enter a number.[/error]")
                Prompt.ask("[dim]Press Enter to continue[/dim]", default="")
                continue

            if choice == 99:
                if parent is None:
                    sys.exit()
                return 99
        except (TypeError, ValueError):
            console.print("[red]⚠ Please enter a valid option.[/red]")
            input("\nPress [Enter] to continue...")
            elif choice == 98 and self.PROJECT_URL:
                self.show_project_page()
            elif 1 <= choice <= len(self.OPTIONS):
                try:
                    self.OPTIONS[choice - 1][1]()
                except Exception:
                    console.print_exception(show_locals=True)
            input("\nPress [Enter] to continue...")
        return self.show_options(parent=parent)
                Prompt.ask("[dim]Press Enter to continue[/dim]", default="")
            else:
                console.print("[error]⚠ Invalid option.[/error]")

    def before_install(self): pass

    def install(self):
        self.before_install()
        if isinstance(self.INSTALL_COMMANDS, (list, tuple)):
            for INSTALL_COMMAND in self.INSTALL_COMMANDS:
                console.print(f"[yellow]→ {INSTALL_COMMAND}[/yellow]")
                os.system(INSTALL_COMMAND)
            for cmd in self.INSTALL_COMMANDS:
                console.print(f"[warning]→ {cmd}[/warning]")
                os.system(cmd)
        self.after_install()

    def after_install(self):
        console.print("[green]✔ Successfully installed![/green]")
        console.print("[success]✔ Successfully installed![/success]")

    def before_uninstall(self) -> bool:
        return True
@@ -118,9 +158,9 @@ class HackingTool(object):
    def uninstall(self):
        if self.before_uninstall():
            if isinstance(self.UNINSTALL_COMMANDS, (list, tuple)):
                for UNINSTALL_COMMAND in self.UNINSTALL_COMMANDS:
                    console.print(f"[red]→ {UNINSTALL_COMMAND}[/red]")
                    os.system(UNINSTALL_COMMAND)
                for cmd in self.UNINSTALL_COMMANDS:
                    console.print(f"[error]→ {cmd}[/error]")
                    os.system(cmd)
        self.after_uninstall()

    def after_uninstall(self): pass
@@ -130,63 +170,129 @@ class HackingTool(object):
    def run(self):
        self.before_run()
        if isinstance(self.RUN_COMMANDS, (list, tuple)):
            for RUN_COMMAND in self.RUN_COMMANDS:
                console.print(f"[cyan]⚙ Running:[/cyan] [bold]{RUN_COMMAND}[/bold]")
                os.system(RUN_COMMAND)
            for cmd in self.RUN_COMMANDS:
                console.print(f"[cyan]⚙ Running:[/cyan] [bold]{cmd}[/bold]")
                os.system(cmd)
        self.after_run()

    def after_run(self): pass

    def is_installed(self, dir_to_check=None):
        console.print("[yellow]⚠ Unimplemented: DO NOT USE[/yellow]")
        return "?"

    def show_project_page(self):
        console.print(f"[blue]🌐 Opening project page: {self.PROJECT_URL}[/blue]")
        console.print(f"[url]🌐 Opening: {self.PROJECT_URL}[/url]")
        webbrowser.open_new_tab(self.PROJECT_URL)


class HackingToolsCollection(object):
class HackingToolsCollection:
    TITLE: str       = ""
    DESCRIPTION: str = ""
    TOOLS: List = []
    TOOLS: list      = []

    def __init__(self):
        pass

    def show_info(self):
        console.rule(f"[bold purple]{self.TITLE}[/bold purple]", style="purple")
        console.rule(f"[{THEME_PRIMARY}]{self.TITLE}[/{THEME_PRIMARY}]", style="purple")
        if self.DESCRIPTION:
            console.print(f"[italic cyan]{self.DESCRIPTION}[/italic cyan]\n")

    def _active_tools(self) -> list:
        """Return tools that are not archived and are OS-compatible."""
        from os_detect import CURRENT_OS
        return [
            t for t in self.TOOLS
            if not getattr(t, "ARCHIVED", False)
            and CURRENT_OS.system in getattr(t, "SUPPORTED_OS", ["linux", "macos"])
        ]

    def _archived_tools(self) -> list:
        return [t for t in self.TOOLS if getattr(t, "ARCHIVED", False)]

    def _incompatible_tools(self) -> list:
        from os_detect import CURRENT_OS
        return [
            t for t in self.TOOLS
            if not getattr(t, "ARCHIVED", False)
            and CURRENT_OS.system not in getattr(t, "SUPPORTED_OS", ["linux", "macos"])
        ]

    def _show_archived_tools(self):
        """Show archived tools sub-menu (option 98)."""
        archived = self._archived_tools()
        if not archived:
            console.print("[dim]No archived tools in this category.[/dim]")
            Prompt.ask("[dim]Press Enter to return[/dim]", default="")
            return

        while True:
            clear_screen()
            console.rule(f"[archived]Archived Tools — {self.TITLE}[/archived]", style="yellow")

            table = Table(box=box.MINIMAL_DOUBLE_HEAD, show_lines=True)
            table.add_column("No.", justify="center", style="bold yellow")
            table.add_column("Tool", style="dim yellow")
            table.add_column("Reason", style="dim white")

            for i, tool in enumerate(archived):
                reason = getattr(tool, "ARCHIVED_REASON", "No reason given")
                table.add_row(str(i + 1), tool.TITLE, reason)

            table.add_row("99", "Back", "")
            console.print(table)

            raw = Prompt.ask("[bold yellow][?] Select[/bold yellow]", default="99")
            try:
                choice = int(raw)
            except ValueError:
                continue

            if choice == 99:
                return
            elif 1 <= choice <= len(archived):
                archived[choice - 1].show_options(parent=self)

    def show_options(self, parent=None):
        """Iterative menu loop — no recursion, no stack growth."""
        while True:
            clear_screen()
            self.show_info()

            active = self._active_tools()
            incompatible = self._incompatible_tools()
            archived = self._archived_tools()

            table = Table(title="Available Tools", box=box.MINIMAL_DOUBLE_HEAD)
            table.add_column("No.", justify="center", style="bold cyan")
        table.add_column("Tool Name", style="bold yellow")
            table.add_column("Tool", style="bold yellow")

        for index, tool in enumerate(self.TOOLS):
            for index, tool in enumerate(active):
                table.add_row(str(index), tool.TITLE)

            if archived:
                table.add_row("[dim]98[/dim]", f"[archived]Archived tools ({len(archived)})[/archived]")
            if incompatible:
                console.print(f"[dim]({len(incompatible)} tools hidden — not supported on current OS)[/dim]")

            table.add_row("99", f"Back to {parent.TITLE if parent else 'Exit'}")
            console.print(table)

        tool_index = input("\n[?] Choose a tool: ").strip()
            raw = Prompt.ask("\n[bold cyan][?] Choose a tool[/bold cyan]", default="99")
            try:
            tool_index = int(tool_index)
            if tool_index in range(len(self.TOOLS)):
                ret_code = self.TOOLS[tool_index].show_options(parent=self)
                if ret_code != 99:
                    input("\nPress [Enter] to continue...")
            elif tool_index == 99:
                choice = int(raw)
            except ValueError:
                console.print("[error]⚠ Please enter a number.[/error]")
                continue

            if choice == 99:
                if parent is None:
                    sys.exit()
                return 99
        except (TypeError, ValueError):
            console.print("[red]⚠ Please enter a valid option.[/red]")
            input("\nPress [Enter] to continue...")
            elif choice == 98 and archived:
                self._show_archived_tools()
            elif 0 <= choice < len(active):
                try:
                    ret = active[choice].show_options(parent=self)
                except Exception:
                    console.print_exception(show_locals=True)
            input("\nPress [Enter] to continue...")
        return self.show_options(parent=parent)
                    Prompt.ask("[dim]Press Enter to continue[/dim]", default="")
            else:
                console.print("[error]⚠ Invalid option.[/error]")
+8 −3
Original line number Diff line number Diff line
version: "3.9"
services:
  hackingtool:
    image: vgpastor/hackingtool
    # Bug 23 fix: was using external unverified image vgpastor/hackingtool
    # Now builds from local Dockerfile — no third-party trust required
    build: .
    container_name: hackingtool
    stdin_open: true
    tty: true
    volumes:
      - .:/root/hackingtool
    ports:
      - 22:22
 No newline at end of file
      - hackingtool_data:/root/.hackingtool
    # Bug 22 fix: removed port 22:22 — this is a CLI tool, SSH exposure is unnecessary

volumes:
  hackingtool_data:
+14 −85
Original line number Diff line number Diff line
# coding=utf-8
import os

from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
from rich.text import Text
from rich.table import Table

from core import HackingTool
from core import HackingToolsCollection

console = Console()
P_COLOR = "magenta"
from core import HackingTool, HackingToolsCollection, console


class AnonymouslySurf(HackingTool):
    TITLE = "Anonymously Surf"
    DESCRIPTION = (
        "It automatically overwrites the RAM when\n"
        "the system is shutting down and also change Ip."
        "It automatically overwrites the RAM when the system shuts down\n"
        "and also changes your IP address."
    )
    # Bug 28 fix: was "cd kali-anonsurf && ./installer.sh && cd .. && sudo rm -r kali-anonsurf"
    # Deleting the source on install means there is no retry if install fails.
    # Now kept in a separate step so failure does not destroy the source.
    INSTALL_COMMANDS = [
        "sudo git clone https://github.com/Und3rf10w/kali-anonsurf.git",
        "cd kali-anonsurf && sudo ./installer.sh && cd .. && sudo rm -r kali-anonsurf",
        "cd kali-anonsurf && sudo ./installer.sh",
    ]
    RUN_COMMANDS = ["sudo anonsurf start"]
    PROJECT_URL = "https://github.com/Und3rf10w/kali-anonsurf"
    SUPPORTED_OS = ["linux"]

    def __init__(self):
        super(AnonymouslySurf, self).__init__([("Stop", self.stop)])
        super().__init__([("Stop", self.stop)])

    def stop(self):
        console.print(Panel(Text(self.TITLE, justify="center"), style=f"bold {P_COLOR}"))
        console.print("Stopping Anonsurf...", style=f"bold {P_COLOR}")
        console.print("[bold magenta]Stopping Anonsurf...[/bold magenta]")
        os.system("sudo anonsurf stop")


class Multitor(HackingTool):
    TITLE = "Multitor"
    DESCRIPTION = "How to stay in multi places at the same time"
    DESCRIPTION = "How to stay in multi places at the same time."
    INSTALL_COMMANDS = [
        "sudo git clone https://github.com/trimstray/multitor.git",
        "cd multitor;sudo bash setup.sh install",
        "cd multitor && sudo bash setup.sh install",
    ]
    RUN_COMMANDS = [
        "multitor --init 2 --user debian-tor --socks-port 9000 --control-port 9900 --proxy privoxy --haproxy"
    ]
    PROJECT_URL = "https://github.com/trimstray/multitor"
    SUPPORTED_OS = ["linux"]

    def __init__(self):
        # keep original behavior (non-runnable) while still initializing
        super(Multitor, self).__init__(runnable=False)
        super().__init__(runnable=False)


class AnonSurfTools(HackingToolsCollection):
    TITLE = "Anonymously Hiding Tools"
    DESCRIPTION = ""
    TOOLS = [
        AnonymouslySurf(),
        Multitor(),
    ]

    def _get_attr(self, obj, *names, default=""):
        for n in names:
            if hasattr(obj, n):
                return getattr(obj, n)
        return default

    def pretty_print(self):
        table = Table(title="Anonymously Hiding Tools", show_lines=True, expand=True)
        table.add_column("Title", style="magenta", no_wrap=True)
        table.add_column("Description", style="magenta")
        table.add_column("Project URL", style="magenta", no_wrap=True)

        for t in self.TOOLS:
            title = self._get_attr(t, "TITLE", "Title", "title", default=t.__class__.__name__)
            desc = self._get_attr(t, "DESCRIPTION", "Description", "description", default="")
            url = self._get_attr(t, "PROJECT_URL", "PROJECT_URL", "PROJECT", "project_url", "projectUrl", default="")
            table.add_row(str(title), str(desc).strip().replace("\n", " "), str(url))

        panel = Panel(table, title=f"[{P_COLOR}]Available Tools[/ {P_COLOR}]", border_style=P_COLOR)
        console.print(panel)

    def show_options(self, parent=None):
        console.print("\n")
        console.print(Panel.fit(
            "[bold magenta]Anonymously Hiding Tools Collection[/bold magenta]\n"
            "Select a tool to view options or run it.",
            border_style=P_COLOR
        ))

        table = Table(title="[bold cyan]Available Tools[/bold cyan]", show_lines=True, expand=True)
        table.add_column("Index", justify="center", style="bold yellow")
        table.add_column("Tool Name", justify="left", style="bold green")
        table.add_column("Description", justify="left", style="white")

        for i, tool in enumerate(self.TOOLS):
            title = self._get_attr(tool, "TITLE", "Title", "title", default=tool.__class__.__name__)
            desc = self._get_attr(tool, "DESCRIPTION", "Description", "description", default="")
            table.add_row(str(i + 1), title, desc or "")

        table.add_row("[red]99[/red]", "[bold red]Exit[/bold red]", "Return to previous menu")
        console.print(table)

        try:
            choice = Prompt.ask("[bold cyan]Select a tool to run[/bold cyan]", default="99")
            choice = int(choice)
            if 1 <= choice <= len(self.TOOLS):
                selected = self.TOOLS[choice - 1]
                # delegate if collection-style interface exists
                if hasattr(selected, "show_options"):
                    selected.show_options(parent=self)
                # otherwise, if the tool has actions or a run method, prefer those
                elif hasattr(selected, "run"):
                    selected.run()
                else:
                    console.print("[bold yellow]Selected tool has no runnable interface.[/bold yellow]")
            elif choice == 99:
                return 99
        except Exception:
            console.print("[bold red]Invalid choice. Try again.[/bold red]")
        return self.show_options(parent=parent)


if __name__ == "__main__":
    tools = AnonSurfTools()
    tools.pretty_print()
    tools.show_options()
+55 −136

File changed.

Preview size limit exceeded, changes collapsed.

Loading