From 5677e23d3b8fe41b2dada1bd8cb58b8a1625995d Mon Sep 17 00:00:00 2001 From: Noob Science Date: Tue, 26 Sep 2023 17:50:45 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=A6=85=20Better=20CLI=20Output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + cli.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ garuda.py | 28 ++++++++++++--------- scan.py | 58 ++++++++++++++++++++++++++++++++----------- 4 files changed, 134 insertions(+), 26 deletions(-) create mode 100644 .gitignore create mode 100644 cli.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d7901e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/__pycache__ \ No newline at end of file diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..7d7835c --- /dev/null +++ b/cli.py @@ -0,0 +1,73 @@ +""" + +""" + +from rich.console import Console +from rich.text import Text +from rich.theme import Theme +from rich.prompt import Prompt, Confirm +from rich.columns import Columns +from rich.panel import Panel +from rich.table import Table + +# These are the colors that will be used for the output +# If you want to tweak the style of the output, you can change these +theme = Theme( + { + "info": "cyan", + "warning": "yellow", + "danger": "red", + "success": "green", + "normal": "", + } +) + + +# The main output class +# This is class that controls the rich output of the program +class Output: + def __init__(self) -> None: + self.console = Console(theme=theme) + self.prompt = Prompt(console=self.console) + self.table = Table() + + def colored_text(self, text: str, color: str) -> Text: + return Text(text, style=color) + + def log(self, text: str) -> None: + self.console.log(text) + + # The updated print function + # The Code can be one of the following: info, warning, danger, success, normal + # Default is normal if no code is specified + def c_print(self, text="", code="normal", color=None): + if color is not None: + self.console.print(text, style=color) + else: + self.console.print(text, style=code) + + # The updated input function + # This is used to give a nice list of options to the user + def ask(self, msg: str, color=None, choices=None, default=""): + # Only ask for a default if one is specified + if default != "": + return self.prompt.ask( + self.colored_text(msg, color), choices=choices, default=default + ) + else: + return self.prompt.ask(msg, choices=choices) + + # The default is False if no default is specified + def confirm(self, msg: str, default=False): + return Confirm.ask(msg, default=default) + + # Print a options in a nice column + # This helps it stand out from the rest of the output + def show_options(self, options) -> str: + columns = Columns(options, equal=True, expand=True) + self.c_print(str(columns)) + return self.ask("Select an option", options) + + def show_panel(self, title: str, content=None, color=None): + panel = Panel.fit(content, title=title, border_style=color) + self.console.print(panel) \ No newline at end of file diff --git a/garuda.py b/garuda.py index 693e934..2ab650a 100644 --- a/garuda.py +++ b/garuda.py @@ -1,3 +1,7 @@ +import scan +import Honeypot +from cli import Output + msg = ( " __..-' \n" " ________ ___ _.--'' \n" @@ -21,7 +25,7 @@ " `'. \n" ) - +output = Output() class bold_color: # Change colours according to your need PURPLE = "\033[95m" CYAN = "\033[96m" @@ -35,18 +39,18 @@ class bold_color: # Change colours according to your need END = "\033[0m" -print(bold_color.GREEN) +# I could have replaced the print function with the c_print function +# But it would be a lot of work to replace all the print functions +print("\033[92m") print(msg) -if __name__ == "__main__": - while True: - menu = int(input("Choose : ")) - if menu in range(1, 3): - break - if menu == 1: - import scan +# Reset the color to default +print("\033[0m") +if __name__ == "__main__": + menu_option = int(output.ask("Select an option", choices=["1", "2"])) + if menu_option == 1: scan.scanner() - elif menu == 2: - import Honeypot - + elif menu_option == 2: Honeypot.honey() +else: + output.c_print("This file is not meant to be imported", code="danger") \ No newline at end of file diff --git a/scan.py b/scan.py index d13d98e..3a89b33 100644 --- a/scan.py +++ b/scan.py @@ -2,45 +2,75 @@ import socket import threading import time +from cli import Output +from rich.table import Table k = 0 +output = Output() +# Initialize a ports list to store all the open ports +# Add a table to display the open ports +table = Table(title="Open Ports", show_header=True, + header_style="bold magenta") +table.add_column("Port", style="cyan", justify="center") +table.add_column("Service", style="green", justify="center") +table.add_column("URL", style="yellow", justify="center") def scanner(): - print("EFFLUX Eagle port scanner") - print("-" * 80) + output.show_panel(title="", content="[green]EFFLUX[/green] Eagle [underline]port scanner[/underline]", color="green") try: - tar = input("IP addr : ") + tar = output.ask("Enter an IP Address", color="green") + output.log("Trying to resolve host name") target = socket.gethostbyname( tar ) # host name given will resolve to corresponding ip address from dns except socket.gaierror: - print("Name resolution error") + output.c_print("\nName [underline]resolution[/underline] error", code="danger") + output.c_print("Exiting...", code="info") sys.exit() - start_port = int(input("START Port : ")) - end_port = int(input("END Port : ")) + start_port = int(output.ask("[blue]Start[/blue] Port")) + end_port = int(output.ask("[yellow]END[/yellow] Port")) startTime = time.time() - print("Scanning ", target) + output.log(f"Scanning ports from {start_port} to {end_port} for {target}") def scan(port): global k p = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # tcp p.settimeout(5) connection = p.connect_ex((target, port)) + + lock = threading.Lock() + if not (connection): - serviceName = socket.getservbyport(port, "tcp") - print(f"{port}|tcp OPEN {serviceName}") - k += 1 + try: + serviceName = socket.getservbyport(port, "tcp") + with lock: + table.add_row(str(port), serviceName, f"http://{target}:{port}") + k += 1 + except: + k+=1 + output.c_print(f"Error at {port}, skipping") if port == end_port: if k != 0: - print(f"Eagle Scanning was sucessfull, {k} Ports are open") + output.c_print(f"Eagle Scanning was [green]successful[/green], [underline]{k} Ports[/underline] are open") + print("\n") + output.c_print(table) + print("\n") elif k == 0: - print(f"Unfortunately no ports were open") - print("Time taken:", str(time.time() - startTime)[:4], "sec") + output.c_print(f"Unfortunately [red]no ports[/red] were open :(") + output.c_print(f"Time taken: [underline]{ str(time.time() - startTime)[:4] }[/underline] sec", code="info") + output.c_print("Thanks for using 🦅[blue]EFFLUX[/blue]") + p.close() - print("PORT \t STATUS SERVICE") + threads = [] + for port in range(start_port, end_port + 1): thread = threading.Thread(target=scan, args=(port,)) thread.start() + threads.append(thread) + + for thread in threads: + thread.join() + exit()