Esempio n. 1
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()
Esempio n. 2
0
    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
Esempio n. 3
0
    def run(self):

        # Create report directory
        dirname = '{mission}-{datetime}'.format(
            mission=StringUtils.clean(self.mission.replace(' ', '_'),
                                      allowed_specials=('_', '-')),
            datetime=datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
        self.output_path = self.output_path + '/' + dirname

        if not FileUtils.create_directory(self.output_path):
            logger.error('Unable to create report directory: "{path}"'.format(
                path=self.output_path))
            return False

        # Retrieve all services in selected mission
        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission)
        services = req.get_results()

        # Generate screenshots
        processor = ScreenshotsProcessor(self.mission, self.sqlsession)
        processor.run()

        screens_dir = self.output_path + '/screenshots'
        if not FileUtils.create_directory(screens_dir):
            logger.warning(
                'Unable to create screenshots directory: "{path}"'.format(
                    path=screens_dir))
        else:
            for service in services:
                if service.name == 'http' and service.screenshot is not None \
                        and service.screenshot.status == ScreenStatus.OK:

                    img_name = 'scren-{ip}-{port}-{id}'.format(
                        ip=str(service.host.ip),
                        port=service.port,
                        id=service.id)
                    path = screens_dir + '/' + img_name

                    ImageUtils.save_image(service.screenshot.image,
                                          path + '.png')
                    ImageUtils.save_image(service.screenshot.thumbnail,
                                          path + '.thumb.png')

        # Create index.html
        html = self.__generate_index()
        if FileUtils.write(self.output_path + '/index.html', html):
            logger.info('index.html file generated')
        else:
            logger.error('An error occured while generating index.html')
            return False

        # Create results-<service>.html (1 for each service)
        for service in services:
            # Useless to create page when no check has been run for the service
            if len(service.results) == 0:
                continue

            html = self.__generate_results_page(service)
            # Create a unique name for the service HTML file
            filename = 'results-{ip}-{port}-{service}-{id}.html'.format(
                ip=str(service.host.ip),
                port=service.port,
                service=service.name,
                id=service.id)
            if FileUtils.write(self.output_path + '/' + filename, html):
                logger.info(
                    '{filename} file generated'.format(filename=filename))
            else:
                logger.error(
                    'An error occured while generating {filename}'.format(
                        filename=filename))
                return False

        logger.success('HTML Report written with success in: {path}'.format(
            path=self.output_path))
        logger.info('Important: If running from Docker container, make sure to run ' \
            '"xhost +" on the host before')
        if Output.prompt_confirm('Would you like to open the report now ?',
                                 default=True):
            webbrowser.open(self.output_path + '/index.html')

        return True
Esempio n. 4
0
    def __generate_table_web(self):
        """
        Generate the table with HTTP services registered in the mission
        """
        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission)
        filter_ = Filter(FilterOperator.AND)
        filter_.add_condition(Condition('http', FilterData.SERVICE_EXACT))
        req.add_filter(filter_)
        services = req.get_results()

        if len(services) == 0:
            html = """
            <tr class="notfound">
                <td colspan="7">No record found</td>
            </tr>
            """
        else:
            html = ''

            # Unavailable thumbnail
            with open(REPORT_TPL_DIR + '/../img/unavailable.png', 'rb') as f:
                unavailable_b64 = base64.b64encode(f.read()).decode('ascii')

            for service in services:

                # Results HTML page name
                results = 'results-{ip}-{port}-{service}-{id}.html'.format(
                    ip=str(service.host.ip),
                    port=service.port,
                    service=service.name,
                    id=service.id)

                # Encrypted ? (SSL/TLS)
                enc = '<span class="mdi mdi-lock" title="SSL/TLS encrypted"></span>' \
                    if service.is_encrypted() else ''

                # Web technos (in a specific order)

                # try:
                #     technos = ast.literal_eval(service.web_technos)
                # except Exception as e:
                #     logger.debug('Error when retrieving "web_technos" field ' \
                #         'from db: {exc} for {service}'.format(
                #             exc=e, service=service))
                #     technos = list()

                # tmp = list()
                # for t in technos:
                #     tmp.append('{}{}{}'.format(
                #         t['name'],
                #         ' ' if t['version'] else '',
                #         t['version'] if t['version'] else ''))
                # webtechnos = ' | '.join(tmp)

                webtechnos = ''
                product_types = ('web-server', 'web-appserver', 'web-cms',
                                 'web-language', 'web-framework', 'web-jslib')
                for t in product_types:
                    product = service.get_product(t)
                    if product:
                        webtechnos += '<span class="badge badge-{type} badge-light">' \
                            '{name}{version}</span>'.format(
                                type=t,
                                name=product.name,
                                version=' '+str(product.version) \
                                    if product.version else '')

                # Web Application Firewall
                product = service.get_product('web-application-firewall')
                waf = ''
                if product:
                    waf = '<span class="badge badge-web-application-firewall ' \
                        'badge-light">{name}{version}</span>'.format(
                            name=product.name,
                            version=' '+str(product.version) \
                                if product.version else '')

                # Screenshot
                img_name = 'scren-{ip}-{port}-{id}'.format(ip=str(
                    service.host.ip),
                                                           port=service.port,
                                                           id=service.id)
                path = self.output_path + '/screenshots'

                if service.screenshot is not None \
                        and service.screenshot.status == ScreenStatus.OK \
                        and FileUtils.exists(path + '/' + img_name + '.png') \
                        and FileUtils.exists(path + '/' + img_name + '.thumb.png'):

                    screenshot = """
                    <a href="{screenlarge}" title="{url} - {title}" class="image-link">
                        <img src="{screenthumb}" class="border rounded">
                    </a>
                    """.format(url=service.url,
                               screenlarge='screenshots/' + img_name + '.png',
                               title=service.html_title,
                               screenthumb='screenshots/' + img_name +
                               '.thumb.png')

                else:
                    screenshot = """
                    <img src="data:image/png;base64,{unavailable}">
                    """.format(unavailable=unavailable_b64)

                # HTML for table row
                html += """
                <tr{clickable}>
                    <td>{url}</td>
                    <td>{enc}</td>
                    <td>{title}</td>
                    <td>{webtechnos}</td>
                    <td>{waf}</td>
                    <td>{screenshot}</td>
                    <td>{checks}</td>
                </tr>
                """.format(
                    clickable=' class="clickable-row" data-href="{results}"'.format(
                        results=results) if len(service.results) > 0 else '',
                    url='<a href="{}" title="{}">{}</a>'.format(
                        service.url, service.url, StringUtils.shorten(service.url, 50)) \
                        if service.url else '',
                    enc=enc,
                    title=StringUtils.shorten(service.html_title, 40),
                    webtechnos=webtechnos,
                    waf=waf,
                    screenshot=screenshot,
                    checks=len(service.results))

        return html
Esempio n. 5
0
    def __generate_table_services(self):
        """
        Generate the table with all services registered in the mission
        """
        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission)
        services = req.get_results()

        if len(services) == 0:
            html = """
            <tr class="notfound">
                <td colspan="12">No record found</td>
            </tr>
            """
        else:
            html = ''
            for service in services:

                hostname = service.host.hostname \
                    if service.host.ip != service.host.hostname else ''

                # Number of checks
                if len(service.results) > 0:
                    nb_checks = len(service.results)
                else:
                    nb_checks = '<span class="mdi mdi-window-close"></span>'

                # Number of creds
                nb_userpass = service.get_nb_credentials(single_username=False)
                nb_usernames = service.get_nb_credentials(single_username=True)
                nb_creds = '{}{}{}'.format(
                    '<span class="text-green">{}</span>'.format(str(nb_userpass)) \
                        if nb_userpass > 0 else '',
                    '/' if nb_userpass > 0 and nb_usernames > 0 else '',
                    '<span class="text-yellow">{}</span>'.format(
                        str(nb_usernames)) if nb_usernames > 0 else '')
                #if nb_creds == '':
                #    nb_creds = '<span class="mdi mdi-window-close"></span>'

                # Number of vulns
                if len(service.vulns) > 0:
                    nb_vulns = '<span class="text-green">{}</span>'.format(
                        len(service.vulns))
                else:
                    #nb_vulns = '<span class="mdi mdi-window-close"></span>'
                    nb_vulns = ''

                # Encrypted ? (SSL/TLS)
                enc = '<span class="mdi mdi-lock" title="SSL/TLS encrypted"></span>' \
                    if service.is_encrypted() else ''

                # Service name
                service_name = IconsMapping.get_icon_html(
                    'service', service.name)
                service_name += str(service.name)

                # Technologies
                technos = ''
                # For HTTP, respect a given order for technos for better readability
                if service.name == 'http':
                    product_types = (
                        'web-server',
                        'web-appserver',
                        # 'web-application-firewall', Displayed only in "web" tab
                        # for better readability
                        'web-cms',
                        'web-language',
                        'web-framework',
                        'web-jslib')
                    for t in product_types:
                        product = service.get_product(t)
                        if product:
                            technos += '<span class="badge badge-{type} badge-light">' \
                                '{name}{version}</span>'.format(
                                    type=t,
                                    name=product.name,
                                    version=' '+str(product.version) \
                                        if product.version else '')
                else:
                    for p in service.products:
                        technos += '<span class="badge badge-generic badge-light">' \
                            '{name}{version}</span>'.format(
                                type=p.type,
                                name=p.name,
                                version=' '+str(p.version) if p.version else '')

                # Col "Comment/Title" (title is for HTML title for HTTP)
                if service.html_title:
                    comment = service.html_title
                else:
                    comment = service.comment

                # Results HTML page name
                results = 'results-{ip}-{port}-{service}-{id}.html'.format(
                    ip=str(service.host.ip),
                    port=service.port,
                    service=service.name,
                    id=service.id)

                html += """
                <tr{clickable}>
                    <td class="font-weight-bold">{ip}</td>
                    <td>{hostname}</th>
                    <td class="font-weight-bold">{port} /{proto}</td>
                    <td>{service}</td>
                    <td>{enc}</td>
                    <td>{banner}</td>
                    <td>{technos}</td>
                    <td>{url}</td>
                    <td>{comment}</td>
                    <td>{nb_checks}</td>
                    <td>{nb_creds}</td>
                    <td>{nb_vulns}</td>
                </tr>
                """.format(
                    clickable=' class="clickable-row" data-href="{results}"'.format(
                        results=results) if len(service.results) > 0 else '',
                    ip=service.host.ip,
                    hostname=hostname,
                    port=service.port,
                    proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get(
                        service.protocol),
                    service=service_name,
                    enc=enc,
                    banner=service.banner,
                    technos=technos,
                    url='<a href="{}" title="{}">{}</a>'.format(
                        service.url, service.url, StringUtils.shorten(service.url, 40)) \
                        if service.url else '',
                    comment=StringUtils.shorten(comment, 40),
                    nb_checks=nb_checks,
                    nb_creds=nb_creds,
                    nb_vulns=nb_vulns)

        return html
Esempio n. 6
0
    def __generate_table_web(self):
        """
        Generate the table with HTTP services registered in the mission
        """

        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission)
        filter_ = Filter(FilterOperator.AND)
        filter_.add_condition(Condition('http', FilterData.SERVICE_EXACT))
        req.add_filter(filter_)
        services = req.get_results()

        if len(services) == 0:
            html = """
            <tr class="notfound">
                <td colspan="5">No record found</td>
            </tr>
            """
        else:
            html = ''

            # Unavailable thumbnail
            with open(REPORT_TPL_DIR + '/../img/unavailable.png', 'rb') as f:
                unavailable_b64 = base64.b64encode(f.read()).decode('ascii')

            for service in services:

                # Results HTML page name
                results = 'results-{ip}-{port}-{service}-{id}.html'.format(
                    ip=str(service.host.ip),
                    port=service.port,
                    service=service.name,
                    id=service.id)

                # Web technos
                try:
                    technos = ast.literal_eval(service.web_technos)
                except Exception as e:
                    logger.debug('Error when retrieving "web_technos" field ' \
                        'from db: {exc} for {service}'.format(
                            exc=e, service=service))
                    technos = list()

                tmp = list()
                for t in technos:
                    tmp.append('{}{}{}'.format(
                        t['name'], ' ' if t['version'] else '',
                        t['version'] if t['version'] else ''))
                webtechnos = ' | '.join(tmp)

                # Screenshot
                img_name = 'scren-{ip}-{port}-{id}'.format(ip=str(
                    service.host.ip),
                                                           port=service.port,
                                                           id=service.id)
                path = self.output_path + '/screenshots'

                if service.screenshot is not None \
                        and service.screenshot.status == ScreenStatus.OK \
                        and FileUtils.exists(path + '/' + img_name + '.png') \
                        and FileUtils.exists(path + '/' + img_name + '.thumb.png'):

                    screenshot = """
                    <a href="{screenlarge}" title="{title}" class="image-link">
                        <img src="{screenthumb}" class="border rounded">
                    </a>
                    """.format(screenlarge='screenshots/' + img_name + '.png',
                               title=service.html_title,
                               screenthumb='screenshots/' + img_name +
                               '.thumb.png')

                else:
                    screenshot = """
                    <img src="data:image/png;base64,{unavailable}">
                    """.format(unavailable=unavailable_b64)

                # HTML for table row
                html += """
                <tr{clickable}>
                    <td>{url}</td>
                    <td>{title}</td>
                    <td>{webtechnos}</td>
                    <td>{screenshot}</td>
                    <td>{checks}</td>
                </tr>
                """.format(
                    clickable=' class="clickable-row" data-href="{results}"'.format(
                        results=results) if len(service.results) > 0 else '',
                    url='<a href="{}" title="{}">{}</a>'.format(
                        service.url, service.url, StringUtils.shorten(service.url, 50)) \
                        if service.url else '',
                    title=StringUtils.shorten(service.html_title, 40),
                    webtechnos=webtechnos,
                    screenshot=screenshot,
                    checks=len(service.results))

        return html
Esempio n. 7
0
    def __generate_table_services(self):
        """
        Generate the table with all services registered in the mission
        """

        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission)
        services = req.get_results()

        if len(services) == 0:
            html = """
            <tr class="notfound">
                <td colspan="9">No record found</td>
            </tr>
            """
        else:
            html = ''
            for service in services:

                # Creds numbers
                nb_userpass = service.get_nb_credentials(single_username=False)
                nb_usernames = service.get_nb_credentials(single_username=True)
                nb_creds = '{}{}{}'.format(
                    '<span class="text-green">{}</span>'.format(str(nb_userpass)) \
                        if nb_userpass > 0 else '',
                    '/' if nb_userpass > 0 and nb_usernames > 0 else '',
                    '<span class="text-yellow">{}</span> user(s)'.format(
                        str(nb_usernames)) if nb_usernames > 0 else '')

                # Col "Comment/Title" (title is for HTML title for HTTP)
                if service.html_title:
                    comment = service.html_title
                else:
                    comment = service.comment

                # Results HTML page name
                results = 'results-{ip}-{port}-{service}-{id}.html'.format(
                    ip=str(service.host.ip),
                    port=service.port,
                    service=service.name,
                    id=service.id)

                html += """
                <tr{clickable}>
                    <td>{ip}</td>
                    <td>{port}</td>
                    <td>{proto}</td>
                    <td>{service}</td>
                    <td>{banner}</td>
                    <td>{url}</td>
                    <td>{comment}</td>
                    <td>{checks}</td>
                    <td>{creds}</td>
                </tr>
                """.format(
                    clickable=' class="clickable-row" data-href="{results}"'.format(
                        results=results) if len(service.results) > 0 else '',
                    ip=service.host.ip,
                    port=service.port,
                    proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get(
                        service.protocol),
                    service=service.name,
                    banner=service.banner,
                    url='<a href="{}" title="{}">{}</a>'.format(
                        service.url, service.url, StringUtils.shorten(service.url, 50)) \
                        if service.url else '',
                    comment=StringUtils.shorten(comment, 40),
                    checks=len(service.results),
                    creds=nb_creds)
        return html
    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
        requester = ServicesRequester(self.sqlsess)
        requester.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('Logical or is applied between each filter')
            requester.add_filter(args.filters_combined)

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

        # Add each targeted service into Attack scope
        logger.info('Checking if targets are reachable...')
        for service in services:
            # Update credentials and options if needed
            for c in self.creds[service.name]:
                service.credentials.append(c)
            for u in self.users[service.name]:
                service.credentials.append(u)
            for o in self.options[service.name]:
                service.options.append(o)

            # Initialize Target and check if reachable
            target = Target(service, self.settings.services)
            service.up = target.smart_check(grab_banner_nmap=False)
            self.sqlsess.commit()

            msg = 'host {ip} | port {port}/{proto} | service {service}'.format(
                ip=target.get_ip(),
                port=target.get_port(),
                proto=target.get_protocol(),
                service=target.get_service_name())
            if service.up:
                logger.success('Target reachable: ' + msg)
            else:
                logger.warning('Target not reachable (skipped): ' + msg)
                continue

            # Update info into database if needed
            #requester.add_target(target)

            self.attack_scope.add_target(target)

        self.attack_scope.attack()