Exemple #1
0
    def __check_pre_update(self, settings, fast_mode=False):
        """
        Perform some checks before trying to update the tool (already installed ?,
        update command ?).

        :param Settings settings: Settings from config files
        :param bool fast_mode: Set to true to disable prompts
        :return: Result of checks
        :rtype: bool
        """
        if not self.installed:
            logger.info('{tool} is not installed yet (according to settings), ' \
                'skipped'.format(tool=self.name))
            return False

        elif not self.update_command:
            logger.warning(
                'No tool update command specified in config file, skipped.')
            return False

        # Create directory for the tool if necessary
        # (should not be necessary because only update)
        if self.install_command and not FileUtils.is_dir(self.tool_dir):
            logger.warning('Tool directory does not exist but tool marked as ' \
                'installed. Trying to re-install it...')
            return self.install(settings, fast_mode)

        return True
Exemple #2
0
    def __create_tool_dir(self):
        """
        Create the tool directory if necessary.

        :return: Status
        :rtype: bool
        """
        if self.tool_dir:
            if FileUtils.is_dir(self.tool_dir):
                logger.info('Directory "{dir}" already exists'.format(
                    dir=self.tool_dir))
                return True

            try:
                FileUtils.create_directory(self.tool_dir)
            except Exception as e:
                logger.error(
                    'Unable to create new directory "{dir}": {exc}'.format(
                        dir=self.tool_dir, exc=e))
                return False
            logger.info(
                'New directory "{dir}" created'.format(dir=self.tool_dir))
            return True
        else:
            return False
Exemple #3
0
    def update_for_service(self, service, fast_mode=False):
        """
        Update the tools for a given service.

        :param str service: Name of the service targeted by the tools to update 
            (may be "multi")
        :param bool fast_mode: Set to true to disable prompts and install checks
        """
        if service not in self.services: return
        Output.title1(
            'Update tools for service: {service}'.format(service=service))

        if not self.tools[service]:
            logger.info('No tool specific to this service in the toolbox')
        else:
            i = 1
            for tool in self.tools[service]:
                if i > 1: print()
                Output.title2(
                    '[{svc}][{i:02}/{max:02}] Update {tool_name}:'.format(
                        svc=service,
                        i=i,
                        max=len(self.tools[service]),
                        tool_name=tool.name))

                tool.update(self.settings, fast_mode=fast_mode)
                i += 1
Exemple #4
0
    def delete(self):
        """Delete selected services"""
        results = self.get_results()
        if not results:
            logger.error('No matching service')
        else:
            for r in results:
                logger.info('Service {service} host={ip}{hostname} ' \
                    'port={port}/{proto} deleted'.format(
                    service  = r.name,
                    ip       = r.host.ip,
                    hostname = '('+r.host.hostname+')' if r.host.hostname else '',
                    port     = r.port,
                    proto    = {Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get(
                        r.protocol)))

                self.sqlsess.delete(r)
                self.sqlsess.commit()

                # Delete host if no more service in it
                if len(r.host.services) == 0:
                    logger.info('Host {ip} {hostname} deleted because it does not ' \
                        'have service anymore'.format(
                        ip=r.host.ip,
                        hostname='('+r.host.hostname+')' if r.host.hostname else ''))

                    self.sqlsess.delete(r.host)
                    self.sqlsess.commit()
Exemple #5
0
    def __init__(self):
        """
        Start the parsing of settings files and create the Settings object.

        :raises SettingsException: Exception raised if any error is encountered while 
            parsing files (syntax error, missing mandatory file...)
        """
        self.config_parsers = dict(
        )  # Dict of DefaultConfigParser indexed by filename
        self.toolbox = None  # Receives Toolbox object
        self.services = None  # Receives ServicesConfig object
        self.attack_profiles = None  # Receives AttackProfiles object

        # Check directory
        if not FileUtils.is_dir(SETTINGS_DIR):
            raise SettingsException('Configuration directory ({dir}) does not ' \
                'exist'.format(dir=SETTINGS_DIR))

        # Check presence of *.conf files
        files = FileUtils.list_directory(SETTINGS_DIR)
        for f in files:
            if not FileUtils.check_extension(f, CONF_EXT):
                files.remove(f)

        if not files:
            raise SettingsException('Configuration directory ({dir}) does not ' \
                'store any *.conf file'.format(dir=SETTINGS_DIR))

        if TOOLBOX_CONF_FILE + CONF_EXT not in files:
            raise SettingsException('Missing mandatory {toolbox}{ext} settings ' \
                'file in directory "{dir}"'.format(
                    toolbox=TOOLBOX_CONF_FILE,
                    ext=CONF_EXT,
                    dir=SETTINGS_DIR))

        if ATTACK_PROFILES_CONF_FILE + CONF_EXT not in files:
            raise SettingsException('Missing mandatory {profiles}{ext} settings ' \
                'file in directory "{dir}"'.format(
                    profiles=ATTACK_PROFILES_CONF_FILE,
                    ext=CONF_EXT,
                    dir=SETTINGS_DIR))

        # Create _install_status.conf file if necessary
        if INSTALL_STATUS_CONF_FILE + CONF_EXT not in files:
            open(SETTINGS_DIR + '/' + INSTALL_STATUS_CONF_FILE + CONF_EXT,
                 'a').close()
            logger.info('{status}{ext} settings file created in directory ' \
                '"{dir}"'.format(status=INSTALL_STATUS_CONF_FILE,
                                 ext=CONF_EXT,
                                 dir=SETTINGS_DIR))
            files.append(INSTALL_STATUS_CONF_FILE + CONF_EXT)

        # Parse configuration files and create objects from them
        self.__parse_all_conf_files(files)
        self.__create_toolbox()
        self.__create_all_services_config_and_checks()
        self.__create_attack_profiles()
 def change_current_mission(self, name, verbose=False):
     mission = self.sqlsess.query(Mission).filter(Mission.name == name).first()
     if not mission:
         logger.error('No mission with this name')
     else:
         self.current_mission = name
         self.prompt = Output.colored('jok3rdb', color='light_green', attrs='bold') + \
                       Output.colored('[{mission}]'.format(mission=name), color='light_blue', attrs='bold') + \
                       Output.colored('> ', color='light_green', attrs='bold')
         if verbose: logger.info('Selected mission is now {name}'.format(name=name))
Exemple #7
0
    def __check_post_install_update(self, settings, fast_mode, update=False):
        """
        Post-install/update checks
        :param settings: Settings instance
        :param fast_mode: Boolean indicating whether prompts must be displayed or not
        :return: Boolean indicating status
        """
        mode = ('update', 'updated') if update else ('install', 'installed')
        status = True

        if not fast_mode:
            if not self.check_command:
                logger.info('No check_command defined in settings for {tool}, will assume it is ' \
                'correctly {mode}'.format(tool=self.name_display, mode=mode[1]))
            else:
                logger.info(
                    'Now, checking if {tool} has been {mode} correctly. Hit any key to run test...'
                    .format(tool=self.name_display, mode=mode[1]))
                CLIUtils.getch()
                status = self.__run_check_command()

        # Change install status in configuration file
        if status:
            try:
                if settings.change_installed_status(self.target_service,
                                                    self.name_clean,
                                                    install_status=True):
                    logger.success(
                        'Tool {tool} has been marked as successfully {mode}'.
                        format(tool=self.name_display, mode=mode[1]))
                    return True
                else:
                    logger.error(
                        'Error when updating configuration file "{filename}{ext}"'
                        .format(filename=INSTALL_STATUS_CONF_FILE,
                                ext=CONF_EXT))
                    return False
            except SettingsException as e:
                logger.error('An unexpected error occured when trying to mark the tool as {mode}: ' \
                    '{exception}'.format(exception=e, mode=mode[1]))
                if not update:
                    self.remove(settings)
                return False
        else:
            logger.warning('Tool {tool} has not been marked as {mode}'.format(
                tool=self.name_display, mode=mode[1]))
            if not update:
                self.remove(settings)
            else:
                if not fast_mode and Output.prompt_confirm(
                        'Do you want to try to re-install ?', default=True):
                    return self.__reinstall(settings, fast_mode)
            return False
Exemple #8
0
    def add_target(self, target):
        """
        Add a new service into the current mission scope in database from a Target 
        object.

        :param Target target: Target to add
        """
        mission = self.sqlsess.query(Mission)\
                      .filter(Mission.name == self.current_mission).first()

        matching_service = self.sqlsess.query(Service)\
                              .join(Host)\
                              .join(Mission)\
                              .filter(Host.ip == target.get_ip())\
                              .filter(Mission.name == self.current_mission)\
                              .filter(Service.name == target.get_service_name())\
                              .filter(Service.port == target.get_port())\
                              .filter(Service.protocol == target.get_protocol2())\
                              .filter(Service.url == target.get_url()).first()

        # If service already exists in db, update it if necessary
        if matching_service:
            logger.info('A matching service has been found in the database')
            matching_service.merge(target.service)
            self.sqlsess.commit()
            # Make sure to replace target info by newly created service
            target.service = matching_service

        # Add host in db if it does not exist or update its info (merging)
        else:
            host = self.sqlsess.query(Host).join(Mission)\
                               .filter(Mission.name == self.current_mission)\
                               .filter(Host.ip == target.get_ip()).first()
            if host:
                host.merge(target.service.host)
                self.sqlsess.commit()
                target.service.host = host
            else:
                self.sqlsess.add(target.service.host)
                mission.hosts.append(target.service.host)
                self.sqlsess.commit()

            # Add service in db
            self.sqlsess.add(target.service)
            self.sqlsess.commit()

        logger.success('{action}: host {ip} | port {port}/{proto} | ' \
            'service {service}'.format(
            action  = 'Updated' if matching_service else 'Added',
            ip      = target.get_ip(),
            port    = target.get_port(),
            proto   = target.get_protocol(),
            service = target.get_service_name()))
    def run(self):
        args = self.arguments.args
        self.creds = defaultdict(list)
        self.users = defaultdict(list)
        self.options = defaultdict(list)

        # Load smart modules
        self.smartmodules_loader = SmartModulesLoader(self.sqlsess,
                                                      self.settings.services)

        # Initialize provided credentials
        if args.creds:
            for c in args.creds:
                self.creds[c['service']].append(
                    Credential(type=c['auth_type'],
                               username=c['username'],
                               password=c['password']))

        # Initialize provided single usernames
        if args.users:
            for u in args.users:
                self.users[c['service']].append(
                    Credential(type=u['auth_type'],
                               username=u['username'],
                               password=None))

        # Initialize provided context-specific options
        if args.specific:
            for option_name in args.specific:
                service = self.settings.services.get_service_for_specific_option(
                    option_name)
                if service:
                    self.options[service].append(
                        Option(name=option_name,
                               value=args.specific[option_name]))

        # Run the attack
        self.attack_scope = AttackScope(self.settings,
                                        ResultsRequester(self.sqlsess),
                                        self.smartmodules_loader,
                                        args.cat_only,
                                        args.checks,
                                        fast_mode=args.fast_mode)

        begin = time.time()
        if args.target_ip_or_url:
            self.__run_for_single_target(args)
        else:
            self.__run_for_multi_targets(args)

        print()
        logger.info('Done. Time spent: {0} seconds'.format(time.time() -
                                                           begin))
Exemple #10
0
 def __reinstall(self, settings, fast_mode):
     """
     Try to re-install the tool, ie. remove and install
     :param settings: Settings instance
     :param fast_mode: Boolean indicating whether prompts must be displayed or not
     :return: Boolean indicating status
     """
     logger.info('First, the tool directory will be removed...')
     if not self.remove(settings):
         return False
     logger.info('Now, running a new install for {tool}...'.format(
         tool=self.name_display))
     return self.install(settings)
 def delete(self):
     results = self.get_results()
     if not results:
         logger.error('No matching host')
     else:
         for r in results:
             logger.info(
                 'Host {ip} {hostname} (and its {nb_services} services) deleted'
                 .format(ip=r.ip,
                         hostname='(' + r.hostname +
                         ')' if r.hostname else '',
                         nb_services=len(r.services)))
             self.sqlsess.delete(r)
         self.sqlsess.commit()
Exemple #12
0
    def __reinstall(self, settings, fast_mode):
        """
        Try to re-install the tool, i.e. remove and install.

        :param Settings settings: Settings from config files
        :param fast_mode: Set to true to disable prompts
        :return: Status of reinstall
        :rtype: bool
        """
        logger.info('First, the tool directory will be removed...')
        if not self.remove(settings):
            return False
        logger.info('Now, running a new install for {tool}...'.format(tool=self.name))
        return self.install(settings)
Exemple #13
0
    def __reverse_dns_lookup(self):
        """
        Attempt to perform reverse DNS lookup (i.e. IP -> Hostname)

        Updated in this method:
            - self.service.host.hostname
        """
        hostname = NetUtils.reverse_dns_lookup(self.service.host.ip)

        if hostname != self.service.host.ip:
            logger.info('{ip} -> {hostname}'.format(ip=self.service.host.ip,
                                                    hostname=hostname))
        else:
            logger.info('No DNS name found for IP')

        self.service.host.hostname = hostname
Exemple #14
0
    def __check_pre_install(self, settings, fast_mode=False):
        """
        Perform some checks before trying to install the tool (already installed ?,
        install command ?).

        :param Settings settings: Settings from config files
        :param bool fast_mode: Set to true to disable prompts
        :return: Result of checks
        :rtype: bool
        """
        if self.installed:
            logger.info('{tool} is already installed (according to settings), ' \
                'skipped'.format(tool=self.name))
            return False

        elif not self.install_command:
            logger.warning('The tool {tool} has no installation command specified in ' \
                'config file'.format(tool=self.name))

            if fast_mode \
               or Output.prompt_confirm('Is the tool already installed on your system ?',
                                        default=True):

                try:
                    if settings.change_installed_status(self.target_service, 
                                                        self.name, 
                                                        True):

                        logger.success('Tool {tool} has been marked as installed in ' \
                            'settings'.format(tool=self.name))
                        return True
                    else:
                        logger.error('Error when saving the configuration file ' \
                            '"{filename}{ext}"'.format(
                                filename=INSTALL_STATUS_CONF_FILE, ext=CONF_EXT))
                        return False

                except SettingsException as e:
                    logger.error(e)
                    self.remove(settings)
                    return False
            else:
                logger.info('Tool {tool} is still not marked as installed in ' \
                    'settings'.format(tool=self.name))
            return False

        return True
    def do_hosts(self, args):
        """Hosts in the current mission scope"""
        print()
        req = HostsRequester(self.sqlsess)
        req.select_mission(self.current_mission)

        # Logical AND is applied between all specified filtering options
        filter_ = Filter(FilterOperator.AND)
        if args.addrs:
            for addr in args.addrs:
                if NetUtils.is_valid_ip(addr) or NetUtils.is_valid_ip_range(addr):
                    filter_.add_condition(Condition(addr, FilterData.IP))
                else:
                    filter_.add_condition(Condition(addr, FilterData.HOST))
        if args.search:
            filter_search = Filter(FilterOperator.OR)
            filter_search.add_condition(Condition(args.search, FilterData.HOST))
            filter_search.add_condition(Condition(args.search, FilterData.OS))
            filter_search.add_condition(Condition(args.search, FilterData.COMMENT_HOST))
            filter_.add_condition(filter_search)
        if args.order:
            req.order_by(args.order)

        try:
            req.add_filter(filter_)
        except FilterException as e:
            logger.error(e)
            return

        # Operations
        if args.comment:
            if not req.filter_applied:
                if not Output.prompt_confirm('No filter applied. Are you sure you want to edit comment for ALL hosts in current mission ?', default=False):
                    logger.info('Canceled')
                    return
            req.edit_comment(args.comment)
        elif args.delete:
            if not req.filter_applied:
                if not Output.prompt_confirm('No filter applied. Are you sure you want to delete ALL hosts and related services in current mission', default=False):
                    logger.info('Canceled')
                    return
            req.delete()
        else:
            req.show()

        print()
Exemple #16
0
 def delete(self):
     """Delete selected vulnerabilities"""
     results = self.get_results()
     if not results:
         logger.error('No matching vulnerability')
     else:
         for r in results:
             logger.info('Vulnerability deleted: "{vuln}" for service={service} ' \
                 'host={ip} port={port}/{proto}'.format(
                     vuln=StringUtils.shorten(r.name, 50),
                     service=r.service.name,
                     ip=r.service.host.ip,
                     port=r.service.port,
                     proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get(
                         r.service.protocol)))
             self.sqlsess.delete(r)
         self.sqlsess.commit()
Exemple #17
0
    def __run_check_command(self):
        """
        Run the check command. The goal is to quickly check if the tool is not buggy or
        missing some dependencies
        :return: Boolean indicating if tool is correctly installed
        """
        logger.info('Running the check command for the tool {tool}...'.format(
            tool=self.name_display))
        cmd = self.check_command.get_cmdline(self.tool_dir)

        Output.begin_cmd(cmd)
        ProcessLauncher(cmd).start()
        Output.delimiter()

        return Output.prompt_confirm(
            'Does the tool {tool} seem to be running correctly ?'.format(
                tool=self.name_display),
            default=True)
Exemple #18
0
 def delete(self):
     """Delete selected specific options"""
     results = self.get_results()
     if not results:
         logger.error('No matching specific option')
     else:
         for r in results:
             logger.info('Option {name}={value} for host={ip} service={service} ' \
                 '({port}/{proto}) deleted'.format(
                     name=r.name,
                     value=r.value,
                     ip=r.service.host.ip,
                     service=r.service.name,
                     port=r.service.port,
                     proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get(
                         r.service.protocol)))
             self.sqlsess.delete(r)
         self.sqlsess.commit()
Exemple #19
0
    def __check_pre_install(self, settings, fast_mode):
        """
        Checks to run before installing the tool
        :param settings: Settings instance
        :param fast_mode: Boolean indicating whether prompts must be displayed or not
        :return: Boolean indicating status
        """
        if self.installed:
            logger.info(
                '{tool} is already installed (according to settings), skipped'.
                format(tool=self.name_display))
            return False

        elif not self.install_command:
            logger.warning(
                'The tool {tool} has no installation command specified in config file'
                .format(tool=self.name_display))
            if fast_mode or Output.prompt_confirm(
                    'Is the tool already installed on your system ?',
                    default=True):
                try:
                    if settings.change_installed_status(
                            self.target_service, self.name_clean, True):
                        logger.success(
                            'Tool {tool} has been marked as installed in settings'
                            .format(tool=self.name_display))
                        return True
                    else:
                        logger.error(
                            'Error when saving the configuration file "{filename}{ext}"'
                            .format(filename=INSTALL_STATUS_CONF_FILE,
                                    ext=CONF_EXT))
                        return False
                except SettingsException as e:
                    logger.error(e)
                    self.remove(settings)
                    return False
            else:
                logger.info(
                    'Tool {tool} is still not marked as installed in settings'.
                    format(tool=self.name_display))
            return False

        return True
 def delete(self):
     results = self.get_results()
     if not results:
         logger.error('No matching credential')
     else:
         for r in results:
             logger.info(
                 'Credential {username}/{password} from host={ip} service={service} ({port}/{proto}) deleted'
                 .format(username=r.username,
                         password=r.password,
                         ip=r.service.host.ip,
                         service=r.service.name,
                         port=r.service.port,
                         proto={
                             Protocol.TCP: 'tcp',
                             Protocol.UDP: 'udp'
                         }.get(r.service.protocol)))
             self.sqlsess.delete(r)
         self.sqlsess.commit()
Exemple #21
0
    def remove_for_service(self, service):
        """
        Remove the tools for a given service.

        :param str service: Name of the service targeted by the tools to remove
            (may be "multi")
        """
        if service not in self.services: return
        Output.title1(
            'Remove tools for service: {service}'.format(service=service))

        if not self.tools[service]:
            logger.info('No tool specific to this service in the toolbox')
        else:
            i = 1
            status = True
            for tool in self.tools[service]:
                if i > 1: print()
                Output.title2(
                    '[{svc}][{i:02}/{max:02}] Remove {tool_name}:'.format(
                        svc=service,
                        i=i,
                        max=len(self.tools[service]),
                        tool_name=tool.name))

                status &= tool.remove(self.settings)
                i += 1

            # Remove the service directory if all tools successfully removed
            if status:
                short_svc_path = '{toolbox}/{service}'.format(
                    toolbox=TOOLBOX_DIR, service=service)

                full_svc_path = FileUtils.absolute_path(short_svc_path)

                if FileUtils.remove_directory(full_svc_path):
                    logger.success(
                        'Toolbox service directory "{path}" deleted'.format(
                            path=short_svc_path))
                else:
                    logger.warning('Toolbox service directory "{path}" cannot be ' \
                        'deleted because it still stores some files'.format(
                            path=short_svc_path))
 def delete(self):
     results = self.get_results()
     if not results:
         logger.error('No matching service')
     else:
         for r in results:
             logger.info(
                 'Service {service} host={ip}{hostname} port={port}/{proto} deleted'
                 .format(service=r.name,
                         ip=r.host.ip,
                         hostname='(' + r.host.hostname +
                         ')' if r.host.hostname else '',
                         port=r.port,
                         proto={
                             Protocol.TCP: 'tcp',
                             Protocol.UDP: 'udp'
                         }.get(r.protocol)))
             self.sqlsess.delete(r)
         self.sqlsess.commit()
Exemple #23
0
    def __run_check_command(self):
        """
        Run the check command.
        The goal is to quickly check if the tool is not buggy or missing some 
        dependencies. The user must analyze the output and gives an answer.

        :return: Response from user
        :rtype: bool
        """
        logger.info('Running the check command for the tool {tool}...'.format(
            tool=self.name))

        cmd = self.check_command.get_cmdline(self.tool_dir)

        Output.begin_cmd(cmd)
        ProcessLauncher(cmd).start()
        Output.delimiter()

        return Output.prompt_confirm('Does the tool {tool} seem to be running ' \
            'correctly ?'.format(tool=self.name), default=True) 
Exemple #24
0
    def delete(self):
        """Delete selected products"""
        results = self.get_results()
        if not results:
            logger.error('No matching product')
        else:
            for r in results:
                logger.info('Product deleted: {type}={name}{version} for ' \
                    'service={service} host={ip} port={port}/{proto}'.format(
                        type    = r.type,
                        name    = r.name,
                        version = ' '+r.version if r.version else '',
                        service = r.service.name,
                        ip      = r.service.host.ip,
                        port    = r.service.port,
                        proto   = {Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get(
                            r.service.protocol)))

                self.sqlsess.delete(r)

            self.sqlsess.commit()
Exemple #25
0
    def __run_for_multi_targets(self, args):
        """Run attack against multiple targets from the database"""

        # Get Mission from which targets must be extracted
        mission = self.sqlsess.query(Mission)\
                    .filter(Mission.name == args.mission).first()
        if mission:
            logger.info('Extracting targets from mission "{mission}" ...'.format(
                mission=mission.name))
        else:
            raise AttackException('Mission {mission} does not exist into the ' \
                'database'.format(mission=args.mission))

        # Initialize Services requester and add filter if provided
        req = ServicesRequester(self.sqlsess)
        req.select_mission(args.mission)

        if args.filters_combined:
            for filt in args.filter:
                logger.info('Applying filters on mission scope: {filter}'.format(
                    filter=filt))
            if len(args.filter) > 1:
                logger.info('Note: Logical OR is applied between each filter')
            req.add_filter(args.filters_combined)

        # Retrieve targeted services from database
        services = req.get_results()
        if not services:
            raise AttackException('There is no matching service to target into the ' \
                'database')

        # Add each targeted service into Attack scope 
        for service in services:

            # Update credentials, options, products if specified in command-line
            if args.creds:
                for c in args.creds[service.name]: 
                    service.add_credential(c.clone())
            if args.users:
                for u in args.users[service.name]: 
                    service.add_credential(u.clone())
            if args.products:
                for p in args.products[service.name]: 
                    service.add_product(p.clone())
            if args.options:
                for o in args.options[service.name]: 
                    service.add_option(o.clone())

            # Initialize Target 
            try:
                target = Target(service, self.settings.services)
            except TargetException as e:
                logger.error(e)
                continue

            self.attack_scope.add_target(target)

        # Run the attack
        self.attack_scope.attack()
Exemple #26
0
    def run(self):
        """Run the Attack Controller"""

        args = self.arguments.args
        logger.debug('CLI arguments:')
        logger.debug(args)

        # Attack configuration: Categories of checks to run
        categories = self.settings.services.list_all_categories() # default: all

        if args.cat_only:
            categories = [ cat for cat in categories if cat in args.cat_only ]
        elif args.cat_exclude:
            categories = [ cat for cat in categories if cat not in args.cat_exclude ]


        # Create the attack scope
        self.attack_scope = AttackScope(
            self.settings, 
            self.arguments,
            self.sqlsess,
            args.mission or args.add,
            filter_categories=categories, 
            filter_checks=args.checks, 
            attack_profile=args.profile,
            fast_mode=args.fast_mode)


        # Run the attack
        begin = datetime.datetime.now()
        if args.target_ip_or_url:
            self.__run_for_single_target(args)
        else:
            self.__run_for_multi_targets(args)
            
        print()
        duration = datetime.datetime.now() - begin
        logger.info('Finished. Duration: {}'.format(format_timespan(duration.seconds)))
Exemple #27
0
    def __run_install_update(self, fast_mode, update=False):
        """
        Run install/update command
        :param update: Mode selector, True for update | False for install (default)
        :return: Boolean indicating status
        """
        if update: cmd = self.update_command.get_cmdline(self.tool_dir)
        else: cmd = self.install_command.get_cmdline(self.tool_dir)

        mode = 'update' if update else 'install'

        logger.info('Description: {descr}'.format(descr=self.description))
        #Output.print('{mode} command : {cmd}'.format(mode=mode.capitalize(), cmd=cmd_short))
        if fast_mode or Output.prompt_confirm(
                'Confirm {mode} ?'.format(mode=mode), default=True):
            Output.begin_cmd(cmd)
            ProcessLauncher(cmd).start()
            Output.delimiter()
            logger.success('Tool {mode} has finished'.format(mode=mode))
            return True
        else:
            logger.warning('Tool {mode} aborted'.format(mode=mode))
            return False
Exemple #28
0
    def run_check_command(self, fast_mode=False):
        """
        Run the check command.
        The goal is to quickly check if the tool is not buggy or missing some 
        dependencies. The user must analyze the output and gives an answer.

        :param bool fast_mode: Set to true to disable prompts

        :return: Response from user in interactive mode, otherwise status
            based on exit code (True if exit code is 0)
        :rtype: bool
        """
        if not self.check_command:
            logger.info('No check_command defined in settings for the tool ' \
                '{tool}'.format(tool=self.name))
            return True

        logger.info('Running the check command for the tool {tool}...'.format(
            tool=self.name))

        cmd = self.check_command.get_cmdline(self)

        Output.begin_cmd(cmd)
        returncode, _ = ProcessLauncher(cmd).start()
        Output.delimiter()

        if returncode != 0:
            logger.warning('Check command has finished with an error ' \
                'exit code: {code}'.format(code=returncode))
        else:
            logger.success('Check command has finished with success exit code')

        if fast_mode:
            return (returncode == 0)
        else:
            return Output.prompt_confirm('Does the tool {tool} seem to be running ' \
                'correctly ?'.format(tool=self.name), default=True)
    def add_service(self, ip, hostname, port, protocol, service):
        protocol = {
            'tcp': Protocol.TCP,
            'udp': Protocol.UDP
        }.get(protocol, Protocol.TCP)
        matching_service = self.sqlsess.query(Service).join(Host).join(Mission)\
                                       .filter(Mission.name == self.current_mission)\
                                       .filter(Host.ip == ip)\
                                       .filter(Service.port == int(port))\
                                       .filter(Service.protocol == protocol).first()
        if protocol == Protocol.TCP:
            up = NetUtils.is_tcp_port_open(ip, port)
        else:
            up = NetUtils.is_udp_port_open(ip, port)

        if matching_service:
            logger.warning('Service already present into database')
        else:
            if up:
                logger.info(
                    'Grabbing banner from {ip}:{port} with Nmap...'.format(
                        ip=ip, port=port))
                banner = NetUtils.grab_banner_nmap(ip, port)
                logger.info('Banner: {}'.format(banner or 'None'))
                os = NetUtils.os_from_nmap_banner(banner)
                if os:
                    logger.info('Detected Host OS: {}'.format(os))
            else:
                logger.warning('Port seems to be closed !')

            # Add service in db (and host if not existing)
            service = Service(name=service,
                              port=int(port),
                              protocol=protocol,
                              up=up,
                              banner=banner)

            matching_host = self.sqlsess.query(Host).join(Mission)\
                                        .filter(Mission.name == self.current_mission)\
                                        .filter(Host.ip == ip).first()
            new_host = Host(ip=ip, hostname=hostname, os=os)
            if matching_host:
                matching_host.merge(new_host)
                self.sqlsess.commit()
                service.host = matching_host
            else:
                mission = self.sqlsess.query(Mission).filter(
                    Mission.name == self.current_mission).first()
                new_host.mission = mission
                service.host = new_host
                self.sqlsess.add(new_host)

            self.sqlsess.add(service)
            self.sqlsess.commit()

            logger.success('Service added')
    def run(self):

        # Extract HTTP services from the mission in database
        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission_name)
        filter_ = Filter(FilterOperator.AND)
        filter_.add_condition(Condition('http', FilterData.SERVICE_EXACT))
        req.add_filter(filter_)
        services = req.get_results()

        if len(services) == 0:
            return

        logger.info('Taking web page screenshots for HTTP services (total: ' \
            '{nb})...'.format(nb=len(services)))

        screenshoter = WebScreenshoter()
        if not screenshoter.create_driver():
            logger.error('No screenshot will be added to the report')
            return

        i = 1
        for s in services:
            if s.screenshot is not None \
                    and s.screenshot.status == ScreenStatus.OK \
                    and s.screenshot.image is not None \
                    and s.screenshot.thumbnail is not None:
                logger.info('[{i}/{nb}] Screenshot already in database for {url}'.format(
                    i=i, nb=len(services), url=s.url))

            else:
                logger.info('[{i}/{nb}] Taking screenshot for {url}...'.format(
                    i=i, nb=len(services), url=s.url))
                status, screen = screenshoter.take_screenshot(s.url)

                # Create Screenshot entry in database if necessary
                if s.screenshot is None:
                    screenshot = Screenshot(status=status)
                    self.sqlsession.add(screenshot)
                    s.screenshot = screenshot
                    self.sqlsession.commit()

                # Create thumbnail if status is OK
                if status == ScreenStatus.OK:
                    thumb = ImageUtils.create_thumbnail(screen, 300, 300)
                    if not thumb:
                        status = ScreenStatus.ERROR
                    s.screenshot.status = status
                    s.screenshot.image = screen
                    s.screenshot.thumbnail = thumb
                else:
                    s.screenshot.status = status
            self.sqlsession.commit()

            i += 1