Exemplo n.º 1
0
def check_database():
    """
    Check the CVE database for validity. Validity means:
    1.) it exists; 2.) it is up-to-date with regard to
    the expire time stored in the used config file.
    """

    def do_db_update(log_msg: str):
        """
        Conduct a database update after logging the given message.
        """
        global CREATED_FILES

        LOGGER.info(log_msg)
        module_updater.run([])
        LOGGER.info("Done.")
        os.makedirs("db_update", exist_ok=True)
        update_files = module_updater.CREATED_FILES
        for file in update_files:
            new_file = os.path.join("db_update", file)
            os.rename(os.path.abspath(file), new_file)
        CREATED_FILES.append("db_update")

    if os.path.isfile(DATABASE_FILE):
        # do not update DB if automatic updates are disabled
        if CORE_CONFIG["automatic_module_updates"].lower() != "true":
            return

        # otherwise check DB creation date and update if outdaded
        db_date = util.get_creation_date(DATABASE_FILE)
        db_age = datetime.datetime.now() - db_date
        try:
            db_age_limit = datetime.timedelta(minutes=int(CONFIG["DB_expire"]))
        except ValueError:
            LOGGER.warning("DB_expire is invalid and cannot be processed. %s",
                           "Skipping check whether database is up-to-date.")

        if db_age > db_age_limit:
            do_db_update("Database has expired. Conducting update.")
        else:
            LOGGER.info("Database is up-to-date; expires in %s", str(db_age_limit - db_age))
    else:
        do_db_update("Database does not exist. Installing.")
Exemplo n.º 2
0
    def __init__(self, networks: list, add_networks: list, omit_networks: list,
                 update_modules: bool, config_path: str, ports: list,
                 output_dir: str, user_results: dict, single_network: bool,
                 verbose: bool):
        """
        Create a Controller object.

        :param networks: A list of strings specifying the networks to analyze
        :param add_networks: A list of networks as strings to additionally analyze
        :param omit_networks: A list of networks as strings to omit from the analysis
        :param update_modules: Whether modules should be updated or initialized
        :param config_path: The path to a config file
        :param ports: A list of port expressions
        :param output_dir: A string specifying the output directory of the analysis
        :param user_results: A list of filenames whose files contain user provided results
        :param single_network: A boolean specifying whether all given networks are to be considered
                               hosts in one single network
        :param vebose: Specifying whether to provide verbose output or not
        """

        self.networks = networks if networks is not None else []
        self.networks += add_networks if add_networks is not None else []
        self.omit_networks = omit_networks

        # determine output directory
        if output_dir:
            self.output_dir = output_dir
        else:
            self.output_dir = "avain_output-" + util.get_current_timestamp()
        self.orig_out_dir = self.output_dir
        self.output_dir = os.path.abspath(self.output_dir)
        os.makedirs(self.output_dir, exist_ok=True)

        # check for user scan and analysis results
        self.user_results = {}

        if user_results:
            for rtype, filenames in user_results.items():
                if rtype not in self.user_results:
                    self.user_results[rtype] = []
                for filename in filenames:
                    self.user_results[rtype].append(
                        (filename, os.path.abspath(filename)))

        # store absolute config path
        if config_path:
            config_path = os.path.abspath(config_path)

        # change into AVAIN directory
        self.original_cwd = os.getcwd()
        core_dir = os.path.dirname(os.path.join(os.path.realpath(__file__)))
        avain_dir = os.path.abspath(os.path.join(core_dir, os.pardir))
        os.chdir(avain_dir)

        # parse default and user configs
        self.config = {}
        if os.path.isfile(DEFAULT_CONFIG_PATH):
            try:
                self.config = util.parse_config(DEFAULT_CONFIG_PATH,
                                                self.config)
            except Exception as excpt:
                print(util.MAGENTA +
                      ("Warning: Could not parse default config file. " +
                       "Proceeding without default config.\n") + util.SANE,
                      file=sys.stderr)
                util.print_exception_and_continue(excpt)
        elif not config_path:
            print(util.MAGENTA + "Warning: Could not find default config.\n" +
                  util.SANE,
                  file=sys.stderr)

        if config_path:
            try:
                self.config = util.parse_config(config_path, self.config)
            except Exception as excpt:
                print(util.MAGENTA +
                      ("Warning: Could not parse custom config file. " +
                       "Proceeding without custom config.\n") + util.SANE,
                      file=sys.stderr)
                util.print_exception_and_continue(excpt)

        # set remaining variables
        self.single_network = single_network
        self.verbose = verbose
        self.ports = ports
        self.update_modules = update_modules
        if (not self.update_modules) and self.config["core"][
                "automatic_module_updates"].lower() == "true":
            # retrieve last update timestamp based on last CPE dict download time
            last_update = util.get_creation_date(
                "modules/resources/official-cpe-dictionary_v2.2.xml")
            passed_time = datetime.datetime.now() - last_update
            update_interval = datetime.timedelta(
                minutes=int(self.config["core"]["module_update_interval"]))
            if passed_time > update_interval:
                util.printit(
                    "[INFO] Module data is out-of-date and will be updated\n",
                    color=util.MAGENTA)
                self.update_modules = True

        # setup module_manager
        self.module_manager = ModuleManager(self.networks, self.output_dir,
                                            self.omit_networks, self.ports,
                                            self.user_results, self.config,
                                            self.verbose)

        # setup logging
        self.setup_logging()
        self.logger.info("Starting the AVAIN program")
        self.logger.info("Executed call: avain %s", " ".join(sys.argv[1:]))
Exemplo n.º 3
0
    def __init__(self, networks: list, add_networks: list, omit_networks: list, update_modules: bool,
                 config_path: str, ports: list, output_dir: str, input_dir: str, user_results: dict,
                 separate_networks: bool, verbose: bool):
        """
        Create a Controller object.

        :param networks: A list of strings specifying the networks to analyze
        :param add_networks: A list of networks as strings to additionally analyze
        :param omit_networks: A list of networks as strings to omit from the analysis
        :param update_modules: Whether modules should be updated or initialized
        :param config_path: The path to a config file
        :param ports: A list of port expressions
        :param output_dir: A string specifying the output directory of the analysis
        :param input_dir: A string specifying the output directory of a previous AVAIN analysis
        :param user_results: A list of filenames whose files contain user provided results
        :param separate_networks: A boolean specifying whether all given networks are to be assessed
                                  and scored independently
        :param vebose: Specifying whether to provide verbose output or not
        """

        self.networks = networks if networks is not None else []
        self.networks += add_networks if add_networks is not None else []
        self.omit_networks = omit_networks

        # determine output directory
        if output_dir:
            self.output_dir = output_dir
        else:
            self.output_dir = "avain_output-" + util.get_current_timestamp()
        self.orig_out_dir = self.output_dir
        self.output_dir = os.path.abspath(self.output_dir)
        os.makedirs(self.output_dir, exist_ok=True)

        # copy 'modules' directory to output directory if AVAIN result directory was given as input
        if input_dir:
            if os.path.isfile(os.path.join(input_dir, NET_DIR_MAP_FILE)):
                util.printit("Error: reuse of complete output directory only supported for single network output directories", color=util.RED)
                return
            previous_modules_dir = os.path.join(input_dir, MODULE_DIR_PREFIX)
            new_modules_dir = os.path.join(self.output_dir, MODULE_DIR_PREFIX)
            if os.path.isdir(previous_modules_dir):
                if os.path.isdir(new_modules_dir):
                    shutil.rmtree(new_modules_dir)
                shutil.copytree(previous_modules_dir, new_modules_dir)

        # check for user / previous results
        self.user_results = {}
        if input_dir:
            for rtype in ResultType:
                result_file = os.path.join(RESULT_AGGR_DIRS[rtype], rtype.value.lower() + "_result.json")
                result_file = os.path.join(input_dir, result_file)
                if os.path.isfile(result_file):
                    if rtype not in self.user_results:
                        self.user_results[rtype] = []
                    self.user_results[rtype].append((result_file, os.path.abspath(result_file)))
        if user_results:
            for rtype, filenames in user_results.items():
                if rtype not in self.user_results:
                    self.user_results[rtype] = []
                for filename in filenames:
                    self.user_results[rtype].append((filename, os.path.abspath(filename)))

        # store absolute config path and config basename
        if config_path:
            config_path = os.path.abspath(config_path)
            config_base = os.path.basename(config_path)

        # change into AVAIN directory
        self.original_cwd = os.getcwd()
        core_dir = os.path.dirname(os.path.join(os.path.realpath(__file__)))
        avain_dir = os.path.abspath(os.path.join(core_dir, os.pardir))
        os.chdir(avain_dir)

        # parse default and user configs
        self.config = {}
        if os.path.isfile(DEFAULT_CONFIG_PATH):
            try:
                self.config = util.parse_config(DEFAULT_CONFIG_PATH, self.config)
            except Exception as excpt:
                print(util.MAGENTA + ("Warning: Could not parse default config file. " +
                                      "Proceeding without default config.\n") + util.SANE, file=sys.stderr)
                util.print_exception_and_continue(excpt)
        elif not config_path:
            print(util.MAGENTA + "Warning: Could not find default config.\n" + util.SANE, file=sys.stderr)

        if config_path:
            if not os.path.isfile(config_path):
                # if custom config file has no extension, check config folder for config with given name
                if not os.path.splitext(config_base)[1]:
                    pot_configs = glob.glob(os.path.join(CONFIG_DIR, config_base + "*"))
                    if pot_configs:
                        config_path = sorted(pot_configs)[0]

            # parse custom config
            try:
                self.config = util.parse_config(config_path, self.config)
            except FileNotFoundError:
                print(util.MAGENTA + ("Warning: Could not find custom config file '%s'\n" % config_path +
                                      "Proceeding without custom config\n") + util.SANE)
            except Exception as excpt:
                print(util.MAGENTA + ("Warning: Could not parse custom config file. " +
                                      "Proceeding without custom config.\n") + util.SANE, file=sys.stderr)
                util.print_exception_and_continue(excpt)

        # set remaining variables
        self.separate_networks = separate_networks
        self.verbose = verbose
        self.ports = ports
        self.update_modules = update_modules
        if (not self.update_modules) and self.config["core"]["automatic_module_updates"].lower() == "true":
            # retrieve last update timestamp based on last CPE dict download time
            last_update = util.get_creation_date("modules/resources/official-cpe-dictionary_v2.2.xml")
            passed_time = datetime.datetime.now() - last_update
            update_interval = datetime.timedelta(minutes=int(self.config["core"]["module_update_interval"]))
            if passed_time > update_interval:
                util.printit("[INFO] Module data is out-of-date and will be updated\n", color=util.MAGENTA)
                self.update_modules = True

        # setup module_manager
        self.module_manager = ModuleManager(self.networks, self.output_dir, self.omit_networks, self.ports,
                                            self.user_results, self.config, self.verbose)

        # setup logging
        self.setup_logging()
        self.logger.info("Starting the AVAIN program")
        self.logger.info("Executed call: avain %s", " ".join(sys.argv[1:]))