Пример #1
0
 def run(self):
     edn_pid = os.fork()
     if edn_pid == 0:
         try:
             while True:
                 item = InternalServer.get_dagda_edn().get()
                 if item['msg'] == 'init_db':
                     self._init_or_update_db()
                 elif item['msg'] == 'check_image':
                     self._check_docker_by_image_name(item)
                 elif item['msg'] == 'check_container':
                     self._check_docker_by_container_id(item)
         except KeyboardInterrupt:
             # Pressed CTRL+C to quit, so nothing to do
             pass
     else:
         sysdig_falco_monitor_pid = os.fork()
         if sysdig_falco_monitor_pid == 0:
             try:
                 self.sysdig_falco_monitor.pre_check()
                 self.sysdig_falco_monitor.run()
             except DagdaError as e:
                 DagdaLogger.get_logger().error(e.get_message())
                 DagdaLogger.get_logger().warning(
                     'Runtime behaviour monitor disabled.')
             except KeyboardInterrupt:
                 # Pressed CTRL+C to quit
                 InternalServer.get_docker_driver().docker_stop(
                     self.sysdig_falco_monitor.get_running_container_id())
                 InternalServer.get_docker_driver().docker_remove_container(
                     self.sysdig_falco_monitor.get_running_container_id())
         else:
             DagdaServer.app.run(debug=False,
                                 host=self.dagda_server_host,
                                 port=self.dagda_server_port)
Пример #2
0
 def _init_or_update_db():
     try:
         InternalServer.get_mongodb_driver().insert_init_db_process_status({
             'status':
             'Initializing',
             'timestamp':
             datetime.datetime.now().timestamp()
         })
         # Init db
         db_composer = DBComposer()
         db_composer.compose_vuln_db()
         InternalServer.get_mongodb_driver().insert_init_db_process_status({
             'status':
             'Updated',
             'timestamp':
             datetime.datetime.now().timestamp()
         })
     except Exception as ex:
         message = "Unexpected exception of type {0} occurred: {1!r}".format(
             type(ex).__name__, ex.args)
         DagdaLogger.get_logger().error(message)
         if InternalServer.is_debug_logging_enabled():
             traceback.print_exc()
         InternalServer.get_mongodb_driver().insert_init_db_process_status({
             'status':
             message,
             'timestamp':
             datetime.datetime.now().timestamp()
         })
Пример #3
0
 def verify_args(args):
     if args.server_port and args.server_port not in range(1, 65536):
         DagdaLogger.get_logger().error(
             'Argument -p/--server_port: The port must be between 1 and 65535.'
         )
         return 1
     elif args.mongodb_port and args.mongodb_port not in range(1, 65536):
         DagdaLogger.get_logger().error(
             'Argument -mp/--mongodb_port: The port must be between 1 and 65535.'
         )
         return 2
     elif args.mongodb_user and not args.mongodb_pass:
         DagdaLogger.get_logger().error(
             'Argument --mongodb_pass: this argument should not be empty if you set '
             '"--mongodb_user".')
         return 3
     elif args.mongodb_pass and not args.mongodb_user:
         DagdaLogger.get_logger().error(
             'Argument --mongodb_user: this argument should not be empty if you set '
             '"--mongodb_pass".')
         return 4
     elif args.falco_rules_file:
         with args.falco_rules_file as content_file:
             try:
                 yaml.safe_load(content_file.read())
             except:
                 DagdaLogger.get_logger().error(
                     'Argument --falco_rules_file: Malformed yaml file.')
                 return 5
     # Else
     return 0
Пример #4
0
def check_docker_by_container_id(container_id):
    # -- Check input
    if not container_id:
        return json.dumps({'err': 400, 'msg': 'Bad container id'}, sort_keys=True), 400

    # -- Retrieves docker image name
    try:
        image_name = InternalServer.get_docker_driver().get_docker_image_name_by_container_id(container_id)
    except Exception as ex:
        message = "Unexpected exception of type {0} occurred while getting the docker image name: {1!r}" \
            .format(type(ex).__name__, ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
        DagdaLogger.get_logger().error(message)
        return json.dumps({'err': 404, 'msg': 'Container Id not found'}, sort_keys=True), 404

    # -- Process request
    data = {}
    data['image_name'] = image_name
    data['timestamp'] = datetime.datetime.now().timestamp()
    data['status'] = 'Analyzing'
    id = InternalServer.get_mongodb_driver().insert_docker_image_scan_result_to_history(data)
    InternalServer.get_dagda_edn().put({'msg': 'check_container', 'container_id': container_id, '_id': str(id)})

    # -- Return
    output = {}
    output['id'] = str(id)
    output['msg'] = 'Accepted the analysis of <' + image_name + '> with id: ' + container_id
    return json.dumps(output, sort_keys=True), 202
Пример #5
0
 def __init__(self):
     super(DockerDriver, self).__init__()
     try:
         # Return a client configured from environment variables. The environment variables used are the same as
         # those used by the Docker command-line client.
         self.cli = docker.from_env(version="auto", timeout=3600).api
     except DockerException:
         DagdaLogger.get_logger().error('Error while fetching Docker server API version: Assuming Travis CI tests.')
         self.cli = None
Пример #6
0
 def verify_args(args):
     if not args.start and not args.stop:
         DagdaLogger.get_logger().error('Missing arguments.')
         return 1
     elif args.start and args.stop:
         DagdaLogger.get_logger().error('Arguments --start & --stop: Both arguments can not be together.')
         return 2
     # Else
     return 0
Пример #7
0
    def evaluate_image(self, image_name, container_id):
        # Init
        data = {}

        # -- Static analysis
        image_name = self.dockerDriver.get_docker_image_name_by_container_id(container_id) if container_id \
                                                                                           else image_name
        os_packages = []
        malware_binaries = []
        dependencies = None
        temp_dir = None
        try:
            # Get OS packages
            if container_id is None:  # Scans the docker image
                os_packages = os_info_extractor.get_soft_from_docker_image(
                    docker_driver=self.dockerDriver, image_name=image_name)
                temp_dir = extract_filesystem_bundle(
                    docker_driver=self.dockerDriver, image_name=image_name)
            else:  # Scans the docker container
                os_packages = os_info_extractor.get_soft_from_docker_container_id(
                    docker_driver=self.dockerDriver, container_id=container_id)
                temp_dir = extract_filesystem_bundle(
                    docker_driver=self.dockerDriver, container_id=container_id)

            # Get malware binaries
            malware_binaries = malware_extractor.get_malware_included_in_docker_image(
                docker_driver=self.dockerDriver, temp_dir=temp_dir)

            # Get programming language dependencies
            dependencies = dep_info_extractor.get_dependencies_from_docker_image(
                docker_driver=self.dockerDriver,
                image_name=image_name,
                temp_dir=temp_dir)
        except Exception as ex:
            message = "Unexpected exception of type {0} occured: {1!r}"\
                .format(type(ex).__name__,  ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
            DagdaLogger.get_logger().error(message)
            data['status'] = message

        # -- Cleanup
        if temp_dir is not None:
            clean_up(temporary_dir=temp_dir)

        # -- Prepare output
        if dependencies is not None:
            data['status'] = 'Completed'
        else:
            dependencies = []

        data['image_name'] = image_name
        data['timestamp'] = datetime.datetime.now().timestamp()
        data['static_analysis'] = self.generate_static_analysis(
            image_name, os_packages, dependencies, malware_binaries)

        # -- Return
        return data
Пример #8
0
def check_docker_by_image_name(image_name):
    # -- Check input
    if not image_name:
        return json.dumps({
            'err': 400,
            'msg': 'Bad image name'
        },
                          sort_keys=True), 400

    # -- Docker pull from remote registry if it is necessary
    try:
        pulled = False
        if not InternalServer.get_docker_driver().is_docker_image(image_name):
            if ':' in image_name:
                tmp = image_name.split(':')[0]
                tag = image_name.split(':')[1]
                msg = 'Error: image library/' + image_name + ':' + tag + ' not found'
                output = InternalServer.get_docker_driver().docker_pull(
                    tmp, tag=tag)
            else:
                msg = 'Error: image library/' + image_name + ':latest not found'
                output = InternalServer.get_docker_driver().docker_pull(
                    image_name)
            if 'errorDetail' in output:
                DagdaLogger.get_logger().error(msg)
                raise DagdaError(msg)
            pulled = True
    except Exception as ex:
        message = "Unexpected exception of type {0} occurred while pulling the docker image: {1!r}" \
            .format(type(ex).__name__, ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
        DagdaLogger.get_logger().error(message)
        return json.dumps({
            'err': 404,
            'msg': 'Image name not found'
        },
                          sort_keys=True), 404

    # -- Process request
    data = {}
    data['image_name'] = image_name
    data['timestamp'] = datetime.datetime.now().timestamp()
    data['status'] = 'Analyzing'
    id = InternalServer.get_mongodb_driver(
    ).insert_docker_image_scan_result_to_history(data)
    InternalServer.get_dagda_edn().put({
        'msg': 'check_image',
        'image_name': image_name,
        '_id': str(id),
        'pulled': pulled
    })

    # -- Return
    output = {}
    output['id'] = str(id)
    output['msg'] = 'Accepted the analysis of <' + image_name + '>'
    return json.dumps(output, sort_keys=True), 202
Пример #9
0
    def pre_check(self):
        # Init
        linux_distro = platform.linux_distribution()[0]
        uname_r = os.uname().release

        # Check requirements
        if not os.path.isfile('/.dockerenv'):  # I'm living in real world!
            if 'Red Hat' == linux_distro or 'CentOS' == linux_distro or 'Fedora' == linux_distro \
                    or 'openSUSE' == linux_distro:
                # Red Hat/CentOS/Fedora/openSUSE
                return_code = subprocess.call(
                    ["rpm", "-q", "kernel-devel-" + uname_r],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL)
            elif 'Debian' == linux_distro or 'Ubuntu' == linux_distro:
                # Debian/Ubuntu
                return_code = subprocess.call(
                    ["dpkg", "-l", "linux-headers-" + uname_r],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL)
            else:
                raise DagdaError('Linux distribution not supported yet.')

            if return_code != 0:
                raise DagdaError(
                    'The kernel headers are not installed in the host operating system.'
                )
        else:  # I'm running inside a docker container
            DagdaLogger.get_logger().warning(
                "I'm running inside a docker container, so I can't check if the kernel "
                "headers are installed in the host operating system. Please, review it!!"
            )

        # Docker pull for ensuring the sysdig/falco image
        self.docker_driver.docker_pull('sysdig/falco')

        # Stops sysdig/falco containers if there are any
        container_ids = self.docker_driver.get_docker_container_ids_by_image_name(
            'sysdig/falco')
        if len(container_ids) > 0:
            for container_id in container_ids:
                self.docker_driver.docker_stop(container_id)

        # Cleans mongodb falco_events collection
        self.mongodb_driver.delete_falco_events_collection()

        # Starts sysdig running container without custom entrypoint for avoiding:
        # --> Runtime error: error opening device /host/dev/sysdig0
        self.running_container_id = self._start_container()
        time.sleep(30)
        logs = self.docker_driver.docker_logs(self.running_container_id, True,
                                              True, False)
        if "Runtime error: error opening device /host/dev/sysdig0" not in logs:
            self.docker_driver.docker_stop(self.running_container_id)
        else:
            raise DagdaError('Runtime error opening device /host/dev/sysdig0.')
Пример #10
0
    def _threaded_malware(dockerDriver, temp_dir, malware_binaries):
        # Get malware binaries
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Retrieving malware files from the docker image ...')

        malware_binaries.extend(malware_extractor.get_malware_included_in_docker_image(docker_driver=dockerDriver,
                                                                                       temp_dir=temp_dir))

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Malware files from the docker image retrieved')
Пример #11
0
 def verify_args(args):
     if not args.container_id and not args.docker_image:
         DagdaLogger.get_logger().error('Missing arguments.')
         return 1
     elif args.container_id and args.docker_image:
         DagdaLogger.get_logger().error('Arguments --docker_image/--container_id: Both arguments '
                                        'can not be together.')
         return 2
     # Else
     return 0
Пример #12
0
 def verify_args(args, sys_argv):
     if sys_argv[2] not in ['containers', 'images', 'events']:
         DagdaLogger.get_logger().error('Missing arguments.')
         return 1
     elif (args.command == 'containers' or args.command == 'images') and \
        (args.event_action or args.event_from or args.event_type):
         DagdaLogger.get_logger().error('Command <' + args.command + '>: this command must be alone.')
         return 2
     # Else
     return 0
Пример #13
0
    def _threaded_malware(dockerDriver, temp_dir, malware_binaries):
        # Get malware binaries
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Retrieving malware files from the docker image ...')

        malware_binaries.extend(malware_extractor.get_malware_included_in_docker_image(docker_driver=dockerDriver,
                                                                                       temp_dir=temp_dir))

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Malware files from the docker image retrieved')
Пример #14
0
 def verify_args(args, sys_argv):
     if sys_argv[2] not in ['containers', 'images', 'events']:
         DagdaLogger.get_logger().error('Missing arguments.')
         return 1
     elif (args.command == 'containers' or args.command == 'images') and \
        (args.event_action or args.event_from or args.event_type):
         DagdaLogger.get_logger().error('Command <' + args.command +
                                        '>: this command must be alone.')
         return 2
     # Else
     return 0
Пример #15
0
    def _threaded_dependencies(dockerDriver, image_name, temp_dir, dependencies):
        # Get programming language dependencies
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Retrieving dependencies from the docker image ...')

        dependencies.extend(dep_info_extractor.get_dependencies_from_docker_image(docker_driver=dockerDriver,
                                                                                  image_name=image_name,
                                                                                  temp_dir=temp_dir))

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Dependencies from the docker image retrieved')
Пример #16
0
    def _threaded_cve_gathering(mongoDbDriver, i):
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('... Including CVEs - ' + str(i))

        compressed_content = get_http_resource_content(
            "https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-" + str(i) + ".json.gz")
        cve_list, cve_ext_info_list = get_cve_list_from_file(compressed_content, i)
        if len(cve_list) > 0:
            mongoDbDriver.bulk_insert_cves(cve_list)
        if len(cve_ext_info_list) > 0:
            mongoDbDriver.bulk_insert_cves_info(cve_ext_info_list)
Пример #17
0
 def verify_args(args):
     if not args.container_id and not args.docker_image:
         DagdaLogger.get_logger().error('Missing arguments.')
         return 1
     elif args.container_id and args.docker_image:
         DagdaLogger.get_logger().error(
             'Arguments --docker_image/--container_id: Both arguments '
             'can not be together.')
         return 2
     # Else
     return 0
Пример #18
0
    def pre_check(self):
        if not InternalServer.is_external_falco():
            # Init
            linux_distro = SysdigFalcoMonitor._get_linux_distro()
            uname_r = os.uname().release

            # Check requirements
            if not os.path.isfile('/.dockerenv'):  # I'm living in real world!
                if 'Red Hat' in linux_distro or 'CentOS' in linux_distro or 'Fedora' in linux_distro \
                        or 'openSUSE' in linux_distro:
                    # Red Hat/CentOS/Fedora/openSUSE
                    return_code = subprocess.call(["rpm", "-q", "kernel-devel-" + uname_r],
                                                  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
                elif 'Debian' in linux_distro or 'Ubuntu' in linux_distro:
                    # Debian/Ubuntu
                    return_code = subprocess.call(["dpkg", "-l", "linux-headers-" + uname_r],
                                                  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
                else:
                    raise DagdaError('Linux distribution not supported yet.')

                if return_code != 0:
                    raise DagdaError('The kernel headers are not installed in the host operating system.')
            else:  # I'm running inside a docker container
                DagdaLogger.get_logger().warning("I'm running inside a docker container, so I can't check if the kernel "
                                                 "headers are installed in the host operating system. Please, review it!!")

            # Check Docker driver
            if self.docker_driver.get_docker_client() is None:
                raise DagdaError('Error while fetching Docker server API version.')

            # Docker pull for ensuring the sysdig/falco image
            self.docker_driver.docker_pull('sysdig/falco')

            # Stops sysdig/falco containers if there are any
            container_ids = self.docker_driver.get_docker_container_ids_by_image_name('sysdig/falco')
            if len(container_ids) > 0:
                for container_id in container_ids:
                    self.docker_driver.docker_stop(container_id)
                    self.docker_driver.docker_remove_container(container_id)

            # Cleans mongodb falco_events collection
            self.mongodb_driver.delete_falco_events_collection()

            # Starts sysdig running container without custom entrypoint for avoiding:
            # --> Runtime error: error opening device /host/dev/sysdig0
            self.running_container_id = self._start_container()
            time.sleep(30)
            logs = self.docker_driver.docker_logs(self.running_container_id, True, True, False)
            if "Runtime error: error opening device /host/dev/sysdig0" not in logs:
                self.docker_driver.docker_stop(self.running_container_id)
            else:
                raise DagdaError('Runtime error opening device /host/dev/sysdig0.')
            # Clean up
            self.docker_driver.docker_remove_container(self.running_container_id)
Пример #19
0
 def __init__(self):
     super(DockerDriver, self).__init__()
     try:
         # Return a client configured from environment variables. The environment variables used are the same as
         # those used by the Docker command-line client.
         self.cli = docker.from_env(version="auto", timeout=3600).api
     except DockerException:
         DagdaLogger.get_logger().error(
             'Error while fetching Docker server API version: Assumming Travis CI tests.'
         )
         self.cli = None
Пример #20
0
    def _threaded_dependencies(dockerDriver, image_name, temp_dir, dependencies):
        # Get programming language dependencies
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Retrieving dependencies from the docker image ...')

        dependencies.extend(dep_info_extractor.get_dependencies_from_docker_image(docker_driver=dockerDriver,
                                                                                  image_name=image_name,
                                                                                  temp_dir=temp_dir))

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Dependencies from the docker image retrieved')
Пример #21
0
 def verify_args(args):
     if not args.start and not args.stop:
         DagdaLogger.get_logger().error('Missing arguments.')
         return 1
     elif args.start and args.stop:
         DagdaLogger.get_logger().error(
             'Arguments --start & --stop: Both arguments can not be together.'
         )
         return 2
     # Else
     return 0
Пример #22
0
 def __init__(self):
     super(DockerDriver, self).__init__()
     try:
         self.cli = docker.Client(base_url='unix://var/run/docker.sock',
                                  version="auto",
                                  timeout=3600)
     except docker.errors.DockerException:
         DagdaLogger.get_logger().error(
             'Error while fetching Docker server API version: Assumming Travis CI tests.'
         )
         self.cli = None
Пример #23
0
 def _parse_log_and_show_dagda_warnings(sysdig_falco_logs):
     date_prefix = datetime.datetime.now().strftime("%A")[:3] + ' '
     lines = sysdig_falco_logs.split("\n")
     warning = ''
     for line in lines:
         if line.startswith(date_prefix) is not True:
             line = line.strip()
             if line.startswith('Rule '):
                 if warning:
                     DagdaLogger.get_logger().warning(warning.strip())
                 warning = ''
             warning+=' ' + line
Пример #24
0
 def _parse_log_and_show_dagda_warnings(sysdig_falco_logs):
     date_prefix = datetime.datetime.now().strftime("%A")[:3] + ' '
     lines = sysdig_falco_logs.split("\n")
     warning = ''
     for line in lines:
         if line.startswith(date_prefix) is not True:
             line = line.strip()
             if line.startswith('Rule '):
                 if warning:
                     DagdaLogger.get_logger().warning(warning.strip())
                 warning = ''
             warning += ' ' + line
Пример #25
0
def get_os_software_packages_blind_mode(docker_driver, container_id):
    supported_distributions = [{'cmd': 'rpm -aqi', 'parser': parse_rpm_output_list},
                               {'cmd': 'dpkg -l', 'parser': parse_dpkg_output_list},
                               {'cmd': 'apk -v info', 'parser': parse_apk_output_list}]
    for supported_distribution in supported_distributions:
        packages_info = docker_driver.docker_exec(container_id, supported_distribution['cmd'], True, False)
        if packages_info is not None and 'exec failed' not in packages_info:
            return supported_distribution['parser'](packages_info)

    # The linux image has not a supported distribution or the image has not a package manager
    DagdaLogger.get_logger().warn('Linux image distribution not found. The OS packages report is empty.')
    # Return empty list
    return []
Пример #26
0
 def docker_logs(self, container_id, show_stdout, show_stderr, follow):
     try:
         return (self.cli.logs(container=container_id, stdout=show_stdout, stderr=show_stderr, follow=follow))\
                .decode('utf-8')
     except docker.errors.APIError as ex:
         if "configured logging reader does not support reading" in str(ex):
             message = "Docker logging driver is not set to be 'json-file' or 'journald'"
             DagdaLogger.get_logger().error(message)
             raise DagdaError(message)
         else:
             message = "Unexpected exception of type {0} occurred: {1!r}" \
                 .format(type(ex).__name__, str(ex))
             DagdaLogger.get_logger().error(message)
             raise ex
Пример #27
0
 def docker_logs(self, container_id, show_stdout, show_stderr, follow):
     try:
         return (self.cli.logs(container=container_id, stdout=show_stdout, stderr=show_stderr, follow=follow))\
                .decode('utf-8')
     except docker.errors.APIError as ex:
         if "configured logging reader does not support reading" in str(ex):
             message = "Docker logging driver is not set to be 'json-file' or 'journald'"
             DagdaLogger.get_logger().error(message)
             raise DagdaError(message)
         else:
             message = "Unexpected exception of type {0} occurred: {1!r}" \
                 .format(type(ex).__name__, str(ex))
             DagdaLogger.get_logger().error(message)
             raise ex
Пример #28
0
 def _init_or_update_db():
     try:
         InternalServer.get_mongodb_driver().insert_init_db_process_status(
             {'status': 'Initializing', 'timestamp': datetime.datetime.now().timestamp()})
         # Init db
         db_composer = DBComposer()
         db_composer.compose_vuln_db()
         InternalServer.get_mongodb_driver().insert_init_db_process_status(
             {'status': 'Updated', 'timestamp': datetime.datetime.now().timestamp()})
     except Exception as ex:
         message = "Unexpected exception of type {0} occurred: {1!r}".format(type(ex).__name__,  ex.args)
         DagdaLogger.get_logger().error(message)
         if InternalServer.is_debug_logging_enabled():
             traceback.print_exc()
         InternalServer.get_mongodb_driver().insert_init_db_process_status(
                 {'status': message, 'timestamp': datetime.datetime.now().timestamp()})
Пример #29
0
def _get_dagda_base_url():
    # -- Load env variables
    try:
        dagda_host = os.environ['DAGDA_HOST']
    except KeyError:
        DagdaLogger.get_logger().error('DAGDA_HOST environment variable is not set.')
        exit(1)

    try:
        dagda_port = os.environ['DAGDA_PORT']
    except KeyError:
        DagdaLogger.get_logger().error('DAGDA_PORT environment variable is not set.')
        exit(1)

    # -- Return Dagda server base url
    return 'http://' + dagda_host + ':' + dagda_port + '/v1'
Пример #30
0
def check_docker_by_image_name(image_name):
    # -- Check input
    if not image_name:
        return json.dumps({
            'err': 400,
            'msg': 'Bad image name'
        },
                          sort_keys=True), 400

    # -- Docker pull from remote registry if it is necessary
    try:
        pulled = False
        if not InternalServer.get_docker_driver().is_docker_image(image_name):
            output = InternalServer.get_docker_driver().docker_pull(image_name)
            if 'errorDetail' in output:
                msg = 'Error: image library/' + image_name + ':latest not found'
                DagdaLogger.get_logger().error(msg)
                raise DagdaError(msg)
            pulled = True
    except:
        return json.dumps({
            'err': 404,
            'msg': 'Image name not found'
        },
                          sort_keys=True), 404

    # -- Process request
    data = {}
    data['image_name'] = image_name
    data['timestamp'] = datetime.datetime.now().timestamp()
    data['status'] = 'Analyzing'
    id = InternalServer.get_mongodb_driver(
    ).insert_docker_image_scan_result_to_history(data)
    InternalServer.get_dagda_edn().put({
        'msg': 'check_image',
        'image_name': image_name,
        '_id': str(id),
        'pulled': pulled
    })

    # -- Return
    output = {}
    output['id'] = str(id)
    output['msg'] = 'Accepted the analysis of <' + image_name + '>'
    return json.dumps(output, sort_keys=True), 202
Пример #31
0
def get_dagda_base_url():
    # -- Load env variables
    try:
        dagda_host = os.environ['DAGDA_HOST']
    except KeyError:
        DagdaLogger.get_logger().error(
            'DAGDA_HOST environment variable is not set.')
        exit(1)

    try:
        dagda_port = os.environ['DAGDA_PORT']
    except KeyError:
        DagdaLogger.get_logger().error(
            'DAGDA_PORT environment variable is not set.')
        exit(1)

    # -- Return Dagda server base url
    return 'http://' + dagda_host + ':' + dagda_port + '/v1'
Пример #32
0
def get_rhsa_and_rhba_bz2_archive_files():
    if InternalServer.is_debug_logging_enabled():
        DagdaLogger.get_logger().debug(
            "Collecting RHSA and RHBA .bz2 archive files...")

    feed_json_file = get_http_resource_content(
        "https://www.redhat.com/security/data/oval/v2/feed.json")

    bz2_archive_files = []
    for entry in json.loads(feed_json_file)["feed"]["entry"]:
        if entry["link"][0]["length"] > 850:
            if InternalServer.is_debug_logging_enabled():
                DagdaLogger.get_logger().debug("Collected " +
                                               entry["content"]["src"])
            bz2_archive_files.append(
                get_http_resource_content(entry["content"]["src"]))

    return bz2_archive_files
Пример #33
0
 def run(self):
     edn_pid = os.fork()
     if edn_pid == 0:
         try:
             while True:
                 item = InternalServer.get_dagda_edn().get()
                 if item['msg'] == 'init_db':
                     self._init_or_update_db()
                 elif item['msg'] == 'check_image':
                     self._check_docker_by_image_name(item)
                 elif item['msg'] == 'check_container':
                     self._check_docker_by_container_id(item)
         except KeyboardInterrupt:
             # Pressed CTRL+C to quit, so nothing to do
             pass
     else:
         docker_events_monitor_pid = os.fork()
         if docker_events_monitor_pid == 0:
             try:
                 docker_daemon_events_monitor = DockerDaemonEventsMonitor(InternalServer.get_docker_driver(),
                                                                          InternalServer.get_mongodb_driver())
                 docker_daemon_events_monitor.run()
             except KeyboardInterrupt:
                 # Pressed CTRL+C to quit, so nothing to do
                 pass
         else:
             sysdig_falco_monitor_pid = os.fork()
             if sysdig_falco_monitor_pid == 0:
                 try:
                     self.sysdig_falco_monitor.pre_check()
                     self.sysdig_falco_monitor.run()
                 except DagdaError as e:
                     DagdaLogger.get_logger().error(e.get_message())
                     DagdaLogger.get_logger().warning('Runtime behaviour monitor disabled.')
                 except KeyboardInterrupt:
                     # Pressed CTRL+C to quit
                     if not InternalServer.is_external_falco():
                         InternalServer.get_docker_driver().docker_stop(self.sysdig_falco_monitor.get_running_container_id())
                         InternalServer.get_docker_driver().docker_remove_container(
                             self.sysdig_falco_monitor.get_running_container_id())
             else:
                 DagdaServer.app.run(debug=False, host=self.dagda_server_host, port=self.dagda_server_port)
Пример #34
0
def check_docker_by_container_id(container_id):
    # -- Check input
    if not container_id:
        return json.dumps({
            'err': 400,
            'msg': 'Bad container id'
        },
                          sort_keys=True), 400

    # -- Retrieves docker image name
    try:
        image_name = InternalServer.get_docker_driver(
        ).get_docker_image_name_by_container_id(container_id)
    except Exception as ex:
        message = "Unexpected exception of type {0} occurred while getting the docker image name: {1!r}" \
            .format(type(ex).__name__, ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
        DagdaLogger.get_logger().error(message)
        return json.dumps({
            'err': 404,
            'msg': 'Container Id not found'
        },
                          sort_keys=True), 404

    # -- Process request
    data = {}
    data['image_name'] = image_name
    data['timestamp'] = datetime.datetime.now().timestamp()
    data['status'] = 'Analyzing'
    id = InternalServer.get_mongodb_driver(
    ).insert_docker_image_scan_result_to_history(data)
    InternalServer.get_dagda_edn().put({
        'msg': 'check_container',
        'container_id': container_id,
        '_id': str(id)
    })

    # -- Return
    output = {}
    output['id'] = str(id)
    output[
        'msg'] = 'Accepted the analysis of <' + image_name + '> with id: ' + container_id
    return json.dumps(output, sort_keys=True), 202
Пример #35
0
def check_docker_by_image_name(image_name):
    # -- Check input
    if not image_name:
        return json.dumps({'err': 400, 'msg': 'Bad image name'}, sort_keys=True), 400

    # -- Docker pull from remote registry if it is necessary
    try:
        pulled = False
        if not InternalServer.get_docker_driver().is_docker_image(image_name):
            if ':' in image_name:
                tmp = image_name.split(':')[0]
                tag = image_name.split(':')[1]
                msg = 'Error: image library/' + image_name + ':' + tag + ' not found'
                output = InternalServer.get_docker_driver().docker_pull(tmp, tag=tag)
            else:
                msg = 'Error: image library/' + image_name + ':latest not found'
                output = InternalServer.get_docker_driver().docker_pull(image_name)
            if 'errorDetail' in output:
                DagdaLogger.get_logger().error(msg)
                raise DagdaError(msg)
            pulled = True
    except Exception as ex:
        message = "Unexpected exception of type {0} occurred while pulling the docker image: {1!r}" \
            .format(type(ex).__name__, ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
        DagdaLogger.get_logger().error(message)
        return json.dumps({'err': 404, 'msg': 'Image name not found'}, sort_keys=True), 404

    # -- Process request
    data = {}
    data['image_name'] = image_name
    data['timestamp'] = datetime.datetime.now().timestamp()
    data['status'] = 'Analyzing'
    id = InternalServer.get_mongodb_driver().insert_docker_image_scan_result_to_history(data)
    InternalServer.get_dagda_edn().put({'msg': 'check_image', 'image_name': image_name, '_id': str(id),
                                        'pulled': pulled})

    # -- Return
    output = {}
    output['id'] = str(id)
    output['msg'] = 'Accepted the analysis of <' + image_name + '>'
    return json.dumps(output, sort_keys=True), 202
Пример #36
0
def _untar_layers(dir, layers):
    output = {}
    # Untar layer filesystem bundle
    for layer in layers:
        tarfile = TarFile(dir + "/" + layer)
        for member in tarfile.getmembers():
            try:
                tarfile.extract(member, path=dir, set_attrs=False)
            except (ValueError, ReadError) as ex:
                if InternalServer.is_debug_logging_enabled():
                    message = "Unexpected exception of type {0} occurred while untaring the docker image: {1!r}" \
                        .format(type(ex).__name__, ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
                    DagdaLogger.get_logger().debug(message)
            except PermissionError as ex:
                message = "Unexpected error occurred while untaring the docker image: " + \
                          "Operation not permitted on {0!r}".format(member.name)
                DagdaLogger.get_logger().warn(message)

    # Clean up
    for layer in layers:
        clean_up(dir + "/" + layer[:-10])
Пример #37
0
 def verify_args(args):
     if args.fp and (args.id or args.is_fp):
         DagdaLogger.get_logger().error('Argument --fp: this argument must be alone.')
         return 1
     elif args.fp and not args.docker_image_name:
         DagdaLogger.get_logger().error('Argument --fp: IMAGE_NAME argument is mandatory.')
         return 2
     elif args.is_fp and args.id:
         DagdaLogger.get_logger().error('Argument --is_fp: this argument must be alone.')
         return 3
     elif args.is_fp and not args.docker_image_name:
         DagdaLogger.get_logger().error('Argument --is_fp: IMAGE_NAME argument is mandatory.')
         return 4
     return 0
Пример #38
0
 def run(self):
     # Read docker daemon events
     while True:
         try:
             for event in self.docker_driver.docker_events():
                 e = json.loads(event.decode('UTF-8').replace("\n", ""))
                 if 'Actor' in e and 'Attributes' in e['Actor']:
                     iter = list(e['Actor']['Attributes'])
                     for key in iter:
                         if '.' in key:
                             del e['Actor']['Attributes'][key]
                 # Bulk insert
                 self.mongodb_driver.bulk_insert_docker_daemon_events([e])
         except requests.packages.urllib3.exceptions.ReadTimeoutError:
             # Nothing to do
             pass
         except bson.errors.InvalidDocument as ex:
             message = "Unexpected exception of type {0} occurred: {1!r}" \
                 .format(type(ex).__name__, ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
             DagdaLogger.get_logger().error(message)
             if InternalServer.is_debug_logging_enabled():
                 traceback.print_exc()
Пример #39
0
def get_soft_from_docker_container_id(docker_driver, container_id):
    # Extract Linux image distribution
    response = get_os_name(docker_driver.docker_exec(container_id, 'cat /etc/os-release', True, False))
    if response is None:
        DagdaLogger.get_logger().info('Linux image distribution has not the "/etc/os-release" file. Starting the task '
                                      'for linux distribution identification in a blind mode ...')
        products = get_os_software_packages_blind_mode(docker_driver, container_id)
    else:
        # Get all installed packages
        if 'Red Hat' in response or 'CentOS' in response or 'Fedora' in response or 'openSUSE' in response:
            # Red Hat/CentOS/Fedora/openSUSE
            products = get_os_software_packages(docker_driver, container_id, 'rpm -aqi', parse_rpm_output_list)
        elif 'Debian' in response or 'Ubuntu' in response:
            # Debian/Ubuntu
            products = get_os_software_packages(docker_driver, container_id, 'dpkg -l', parse_dpkg_output_list)
        elif 'Alpine' in response:
            # Alpine
            products = get_os_software_packages(docker_driver, container_id, 'apk -v info', parse_apk_output_list)
        else:
            raise DagdaError('Linux image distribution not supported yet.')
    # Return packages
    return products
Пример #40
0
 def run(self):
     # Read docker daemon events
     while True:
         try:
             for event in self.docker_driver.docker_events():
                 e = json.loads(event.decode('UTF-8').replace("\n", ""))
                 if 'Actor' in e and 'Attributes' in e['Actor']:
                     iter = list(e['Actor']['Attributes'])
                     for key in iter:
                         if '.' in key:
                             del e['Actor']['Attributes'][key]
                 # Bulk insert
                 self.mongodb_driver.bulk_insert_docker_daemon_events([e])
         except requests.packages.urllib3.exceptions.ReadTimeoutError:
             # Nothing to do
             pass
         except bson.errors.InvalidDocument as ex:
             message = "Unexpected exception of type {0} occurred: {1!r}" \
                 .format(type(ex).__name__, ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
             DagdaLogger.get_logger().error(message)
             if InternalServer.is_debug_logging_enabled():
                 traceback.print_exc()
Пример #41
0
    def _threaded_cve_gathering(mongoDbDriver, i):
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('... Including CVEs - ' + str(i))

        compressed_content = get_http_resource_content(
            "https://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-" + str(i) +
            ".xml.gz")
        cve_list = get_cve_list_from_file(compressed_content, i)
        if len(cve_list) > 0:
            mongoDbDriver.bulk_insert_cves(cve_list)

        # Add CVE info collection with additional info like score
        compressed_content_info = get_http_resource_content(
            "https://nvd.nist.gov/download/nvdcve-" + str(i) + ".xml.zip")
        cve_info_list = get_cve_description_from_file(compressed_content_info)
        compressed_ext_content_info = \
            get_http_resource_content("https://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-"
                                      + str(i) + ".xml.zip")
        cve_ext_info_list = get_cve_cweid_from_file(
            compressed_ext_content_info, cve_info_list)
        if len(cve_ext_info_list) > 0:
            mongoDbDriver.bulk_insert_cves_info(cve_ext_info_list)
Пример #42
0
    def evaluate_image(self, image_name, container_id):
        # Init
        data = {}

        # -- Static analysis
        # Get OS packages
        if image_name:  # Scans the docker image
            os_packages = os_info_extractor.get_soft_from_docker_image(
                self.dockerDriver, image_name)
        else:  # Scans the docker container
            os_packages = os_info_extractor.get_soft_from_docker_container_id(
                self.dockerDriver, container_id)
            image_name = self.dockerDriver.get_docker_image_name_by_container_id(
                container_id)
        # Get programming language dependencies
        dependencies = None
        try:
            dependencies = dep_info_extractor.get_dependencies_from_docker_image(
                self.dockerDriver, image_name)
        except Exception as ex:
            message = "Unexpected exception of type {0} occured: {1!r}".format(
                type(ex).__name__, ex.args)
            DagdaLogger.get_logger().error(message)
            data['status'] = message

        # -- Prepare output
        if dependencies is not None:
            data['status'] = 'Completed'
        else:
            dependencies = []

        data['image_name'] = image_name
        data['timestamp'] = datetime.datetime.now().timestamp()
        data['static_analysis'] = self.generate_static_analysis(
            os_packages, dependencies)

        # -- Return
        return data
Пример #43
0
def get_bid(bugtraq_id):
    url = "http://www.securityfocus.com/bid/" + str(bugtraq_id)
    try:
        r = requests.get(url)
        if r.status_code == 200:
            try:
                body = r.content.decode("utf-8")
                body = body[body.index('<div id="vulnerability">'):
                            body.index('<span class="label">Not Vulnerable:</span>')]
                title = get_title(body)
                clazz = get_info_by_label(body, 'Class')
                linked_cves = get_linked_CVEs(body)
                is_local = get_info_by_label(body, 'Local')
                is_remote = get_info_by_label(body, 'Remote')
                vuln_products = get_vulnerable_products(body)
            except:
                vuln_products = []
            if len(vuln_products) > 0:
                return json.dumps(prepare_output(title, bugtraq_id, clazz, linked_cves, is_local, is_remote,
                                                 vuln_products), sort_keys=True)
    except requests.ConnectionError:
        DagdaLogger.get_logger().warning('Connection error occurred with: "' + url + '"')
        return None
Пример #44
0
def get_rhsa_and_rhba_lists_from_files(bz2_files):
    if InternalServer.is_debug_logging_enabled():
        DagdaLogger.get_logger().debug("Processing vulnerabilities...")

    rhsa_list = []
    rhba_list = []
    rhsa_info_list = []
    rhba_info_list = []

    count = 0
    for bz2_file in bz2_files:
        _rhsa_list, _rhba_list, _rhsa_info_list, _rhba_info_list = get_rhsa_and_rhba_lists_from_file(
            bz2_file)
        rhsa_list.extend(_rhsa_list)
        rhba_list.extend(_rhba_list)
        rhsa_info_list.extend(_rhsa_info_list)
        rhba_info_list.extend(_rhba_info_list)

        count = count + 1
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug("Processed: " + str(count) + "/" +
                                           str(len(bz2_files)))

    return rhsa_list, rhba_list, rhsa_info_list, rhba_info_list
Пример #45
0
 def verify_args(args):
     if args.fp and (args.id or args.is_fp):
         DagdaLogger.get_logger().error(
             'Argument --fp: this argument must be alone.')
         return 1
     elif args.fp and not args.docker_image_name:
         DagdaLogger.get_logger().error(
             'Argument --fp: IMAGE_NAME argument is mandatory.')
         return 2
     elif args.is_fp and args.id:
         DagdaLogger.get_logger().error(
             'Argument --is_fp: this argument must be alone.')
         return 3
     elif args.is_fp and not args.docker_image_name:
         DagdaLogger.get_logger().error(
             'Argument --is_fp: IMAGE_NAME argument is mandatory.')
         return 4
     return 0
Пример #46
0
 def verify_args(args):
     if args.server_port and args.server_port not in range(1, 65536):
         DagdaLogger.get_logger().error('Argument -p/--server_port: The port must be between 1 and 65535.')
         return 1
     elif args.mongodb_port and args.mongodb_port not in range(1, 65536):
         DagdaLogger.get_logger().error('Argument -mp/--mongodb_port: The port must be between 1 and 65535.')
         return 2
     elif args.falco_rules_file:
         with args.falco_rules_file as content_file:
             try:
                 yaml.load(content_file.read())
             except:
                 DagdaLogger.get_logger().error('Argument --falco_rules_file: Malformed yaml file.')
                 return 3
     # Else
     return 0
Пример #47
0
def main(parsed_args):
    # -- Init
    cmd = parsed_args.get_command()
    parsed_args = parsed_args.get_extra_args()

    try:
        # Execute Dagda command
        r = execute_dagda_cmd(cmd=cmd, args=parsed_args)

        # -- Print cmd output
        if r is not None and r.content:
            output = r.content.decode('utf-8')
            try:
                print(json.dumps(json.loads(output), sort_keys=True, indent=4))
            except json.decoder.JSONDecodeError as err:
                DagdaLogger.get_logger().error('JSONDecodeError with the received response: "' + output + '"')
                DagdaLogger.get_logger().error(str(err))
    except BaseException as err:
        DagdaLogger.get_logger().error(str(err))
        traceback.print_exc()
Пример #48
0
    def compose_vuln_db(self):
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('ENTRY to the method for composing VulnDB')

        # -- CVE
        # Adding or updating CVEs
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Updating CVE collection ...')

        first_year = self.mongoDbDriver.remove_only_cve_for_update()
        for i in range(first_year, next_year):
            if InternalServer.is_debug_logging_enabled():
                DagdaLogger.get_logger().debug('... Including CVEs - ' + str(i))

            compressed_content = get_http_resource_content(
                "https://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-" + str(i) + ".xml.gz")
            cve_list = get_cve_list_from_file(compressed_content, i)
            if len(cve_list) > 0:
                self.mongoDbDriver.bulk_insert_cves(cve_list)

            # Add CVE info collection with additional info like score
            compressed_content_info = get_http_resource_content("https://nvd.nist.gov/download/nvdcve-"
                                                                + str(i) + ".xml.zip")
            cve_info_list = get_cve_description_from_file(compressed_content_info)
            compressed_ext_content_info = \
                get_http_resource_content("https://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-"
                                                                    + str(i) + ".xml.zip")
            cve_ext_info_list = get_cve_cweid_from_file(compressed_ext_content_info, cve_info_list)
            if len(cve_ext_info_list) > 0:
                self.mongoDbDriver.bulk_insert_cves_info(cve_ext_info_list)

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('CVE collection updated')

        # -- Exploit DB
        # Adding or updating Exploit_db and Exploit_db info
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Updating Exploit DB collection ...')

        self.mongoDbDriver.delete_exploit_db_collection()
        self.mongoDbDriver.delete_exploit_db_info_collection()
        csv_content = get_http_resource_content(
            'https://raw.githubusercontent.com/offensive-security/exploit-database/master/files_exploits.csv')
        exploit_db_list, exploit_db_info_list = get_exploit_db_list_from_csv(csv_content.decode("utf-8"))
        self.mongoDbDriver.bulk_insert_exploit_db_ids(exploit_db_list)
        self.mongoDbDriver.bulk_insert_exploit_db_info(exploit_db_info_list)

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Exploit DB collection updated')

        # -- BID
        # Adding BugTraqs from 20180328_sf_db.json.gz, where 103525 is the max bid in the gz file
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Updating BugTraqs Id collection ...')

        max_bid = self.mongoDbDriver.get_max_bid_inserted()
        if max_bid < 103525:
            # Clean
            if max_bid != 0:
                self.mongoDbDriver.delete_bid_collection()
                self.mongoDbDriver.delete_bid_info_collection()
            # Adding BIDs
            compressed_file = io.BytesIO(get_http_resource_content(
                "https://github.com/eliasgranderubio/bidDB_downloader/raw/master/bonus_track/20180328_sf_db.json.gz"))
            bid_items_array, bid_detail_array = get_bug_traqs_lists_from_file(compressed_file)
            # Insert BIDs
            for bid_items_list in bid_items_array:
                self.mongoDbDriver.bulk_insert_bids(bid_items_list)
                bid_items_list.clear()
            # Insert BID details
            self.mongoDbDriver.bulk_insert_bid_info(bid_detail_array)
            bid_detail_array.clear()
            # Set the new max bid
            max_bid = 103525

        # Updating BugTraqs from http://www.securityfocus.com/
        bid_items_array, bid_detail_array = get_bug_traqs_lists_from_online_mode(bid_downloader(first_bid=max_bid+1,
                                                                                                last_bid=104000))
        # Insert BIDs
        if len(bid_items_array) > 0:
            for bid_items_list in bid_items_array:
                self.mongoDbDriver.bulk_insert_bids(bid_items_list)
                bid_items_list.clear()
        # Insert BID details
        if len(bid_detail_array) > 0:
            self.mongoDbDriver.bulk_insert_bid_info(bid_detail_array)
            bid_detail_array.clear()

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('BugTraqs Id collection updated')

        # -- RHSA (Red Hat Security Advisory) and RHBA (Red Hat Bug Advisory)
        # Adding or updating rhsa and rhba collections
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Updating RHSA & RHBA collections ...')

        self.mongoDbDriver.delete_rhba_collection()
        self.mongoDbDriver.delete_rhba_info_collection()
        self.mongoDbDriver.delete_rhsa_collection()
        self.mongoDbDriver.delete_rhsa_info_collection()
        bz2_file = get_http_resource_content('https://www.redhat.com/security/data/oval/rhsa.tar.bz2')
        rhsa_list, rhba_list, rhsa_info_list, rhba_info_list = get_rhsa_and_rhba_lists_from_file(bz2_file)
        self.mongoDbDriver.bulk_insert_rhsa(rhsa_list)
        self.mongoDbDriver.bulk_insert_rhba(rhba_list)
        self.mongoDbDriver.bulk_insert_rhsa_info(rhsa_info_list)
        self.mongoDbDriver.bulk_insert_rhba_info(rhba_info_list)

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('RHSA & RHBA collections updated')

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('EXIT from the method for composing VulnDB')
Пример #49
0
    def evaluate_image(self, image_name, container_id):
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('ENTRY to the method for analyzing a docker image')

        # Init
        data = {}

        # -- Static analysis
        image_name = self.dockerDriver.get_docker_image_name_by_container_id(container_id) if container_id \
                                                                                           else image_name
        os_packages = []
        malware_binaries = []
        dependencies = []
        temp_dir = None
        try:
            # Get OS packages
            if InternalServer.is_debug_logging_enabled():
                DagdaLogger.get_logger().debug('Retrieving OS packages from the docker image ...')

            if container_id is None:  # Scans the docker image
                os_packages = os_info_extractor.get_soft_from_docker_image(docker_driver=self.dockerDriver,
                                                                           image_name=image_name)
                temp_dir = extract_filesystem_bundle(docker_driver=self.dockerDriver,
                                                     image_name=image_name)
            else:  # Scans the docker container
                os_packages = os_info_extractor.get_soft_from_docker_container_id(docker_driver=self.dockerDriver,
                                                                                  container_id=container_id)
                temp_dir = extract_filesystem_bundle(docker_driver=self.dockerDriver,
                                                     container_id=container_id)

            if InternalServer.is_debug_logging_enabled():
                DagdaLogger.get_logger().debug('OS packages from the docker image retrieved')

            # Get malware binaries in a parallel way
            malware_thread = Thread(target=Analyzer._threaded_malware, args=(self.dockerDriver, temp_dir,
                                                                             malware_binaries))
            malware_thread.start()

            # Get programming language dependencies in a parallel way
            dependencies_thread = Thread(target=Analyzer._threaded_dependencies, args=(self.dockerDriver, image_name,
                                                                                       temp_dir, dependencies))
            dependencies_thread.start()

            # Waiting for the threads
            malware_thread.join()
            dependencies_thread.join()

        except Exception as ex:
            message = "Unexpected exception of type {0} occurred: {1!r}"\
                .format(type(ex).__name__,  ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
            DagdaLogger.get_logger().error(message)
            if InternalServer.is_debug_logging_enabled():
                traceback.print_exc()
            data['status'] = message

        # -- Cleanup
        if temp_dir is not None:
            clean_up(temporary_dir=temp_dir)

        # -- Prepare output
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Preparing analysis output ...')

        if 'status' not in data or data['status'] is None:
            data['status'] = 'Completed'

        data['image_name'] = image_name
        data['timestamp'] = datetime.datetime.now().timestamp()
        data['static_analysis'] = self.generate_static_analysis(image_name, os_packages, dependencies, malware_binaries)

        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('Analysis output completed')

        # -- Return
        if InternalServer.is_debug_logging_enabled():
            DagdaLogger.get_logger().debug('EXIT from the method for analyzing a docker image')

        return data
Пример #50
0
 def verify_args(args):
     if not args.init and not args.cve and not args.cve_info and not args.product and not args.product_version \
             and not args.bid and not args.bid_info and not args.exploit_db and not args.exploit_db_info \
             and not args.init_status and not args.rhba and not args.rhsa and not args.rhba_info \
             and not args.rhsa_info:
         DagdaLogger.get_logger().error('Missing arguments.')
         return 1
     elif args.init and (args.cve or args.product or args.product_version or args.bid or args.bid_info \
                         or args.exploit_db or args.exploit_db_info or args.init_status or args.rhba or args.rhsa \
                         or args.rhba_info or args.rhsa_info):
         DagdaLogger.get_logger().error('Argument --init: this argument must be alone.')
         return 2
     elif args.init_status and (args.cve or args.product or args.product_version or args.bid or args.cve \
                                or args.cve_info or args.bid_info or args.exploit_db or args.exploit_db_info \
                                or args.init or args.rhba or args.rhsa or args.rhba_info or args.rhsa_info):
         DagdaLogger.get_logger().error('Argument --init_status: this argument must be alone.')
         return 3
     elif args.cve:
         if args.init or args.init_status or args.product or args.product_version or args.bid or args.cve_info \
                 or args.exploit_db or args.bid_info or args.exploit_db_info or args.rhba or args.rhsa \
                 or args.rhba_info or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --cve: this argument must be alone.')
             return 4
         else:
             regex = r"(CVE-[0-9]{4}-[0-9]{4,5})"
             search_obj = re.search(regex, args.cve)
             if not search_obj or len(search_obj.group(0)) != len(args.cve):
                 DagdaLogger.get_logger().error('Argument --cve: The cve format must look like to CVE-2002-1234.')
                 return 5
     elif args.cve_info:
         if args.init or args.init_status or args.product or args.product_version or args.bid or args.cve \
                 or args.exploit_db or args.bid_info or args.exploit_db_info or args.rhba or args.rhsa \
                 or args.rhba_info or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --cve_info: this argument must be alone.')
             return 6
         else:
             regex = r"(CVE-[0-9]{4}-[0-9]{4,5})"
             search_obj = re.search(regex, args.cve_info)
             if not search_obj or len(search_obj.group(0)) != len(args.cve_info):
                 DagdaLogger.get_logger().error('Argument --cve_info: The cve format must look like to '
                                                'CVE-2002-1234.')
                 return 7
     elif args.bid:
         if args.init or args.init_status or args.product or args.product_version or args.cve or args.cve_info \
                 or args.exploit_db or args.bid_info or args.exploit_db_info or args.rhba or args.rhsa \
                 or args.rhba_info or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --bid: this argument must be alone.')
             return 8
         else:
             if args.bid <= 0:
                 DagdaLogger.get_logger().error('Argument --bid: The bid argument must be greater than zero.')
                 return 9
     elif args.bid_info:
         if args.init or args.init_status or args.product or args.product_version or args.cve or args.cve_info \
                 or args.exploit_db or args.bid or args.exploit_db_info or args.rhba or args.rhsa \
                 or args.rhba_info or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --bid_info: this argument must be alone.')
             return 10
         else:
             if args.bid_info <= 0:
                 DagdaLogger.get_logger().error(
                     'Argument --bid_info: The bid argument must be greater than zero.')
                 return 11
     elif args.exploit_db:
         if args.init or args.init_status or args.product or args.product_version or args.cve or args.cve_info \
                 or args.bid or args.bid_info or args.exploit_db_info or args.rhba or args.rhsa \
                 or args.rhba_info or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --exploit_db: this argument must be alone.')
             return 12
         else:
             if args.exploit_db <= 0:
                 DagdaLogger.get_logger().error('Argument --exploit_db: The exploit_db argument must be '
                                                'greater than zero.')
                 return 13
     elif args.exploit_db_info:
         if args.init or args.init_status or args.product or args.product_version or args.cve or args.cve_info \
                 or args.bid or args.bid_info or args.exploit_db or args.rhba or args.rhsa \
                 or args.rhba_info or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --exploit_db_info: this argument must be alone.')
             return 14
         else:
             if args.exploit_db_info <= 0:
                 DagdaLogger.get_logger().error('Argument --exploit_db_info: The exploit_db_info argument '
                                                'must be greater than zero.')
                 return 15
     elif args.product_version and not args.product:
         DagdaLogger.get_logger().error('Argument --product_version: this argument requires the --product argument.')
         return 16
     elif args.rhba:
         if args.init or args.init_status or args.product or args.product_version or args.bid or args.cve_info \
                 or args.exploit_db or args.bid_info or args.exploit_db_info or args.cve or args.rhsa \
                 or args.rhba_info or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --rhba: this argument must be alone.')
             return 17
         else:
             regex = r"(RHBA-[0-9]{4}:[0-9]+)"
             search_obj = re.search(regex, args.rhba)
             if not search_obj or len(search_obj.group(0)) != len(args.rhba):
                 DagdaLogger.get_logger().error('Argument --rhba: The rhba format must look like to RHBA-2012:234.')
                 return 18
     elif args.rhba_info:
         if args.init or args.init_status or args.product or args.product_version or args.bid or args.cve_info \
                 or args.exploit_db or args.bid_info or args.exploit_db_info or args.cve or args.rhsa \
                 or args.rhba or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --rhba_info: this argument must be alone.')
             return 19
         else:
             regex = r"(RHBA-[0-9]{4}:[0-9]+)"
             search_obj = re.search(regex, args.rhba_info)
             if not search_obj or len(search_obj.group(0)) != len(args.rhba_info):
                 DagdaLogger.get_logger().error(
                     'Argument --rhba_info: The rhba format must look like to RHBA-2012:234.')
                 return 20
     elif args.rhsa:
         if args.init or args.init_status or args.product or args.product_version or args.bid or args.cve_info \
                 or args.exploit_db or args.bid_info or args.exploit_db_info or args.cve or args.rhba \
                 or args.rhba_info or args.rhsa_info:
             DagdaLogger.get_logger().error('Argument --rhsa: this argument must be alone.')
             return 21
         else:
             regex = r"(RHSA-[0-9]{4}:[0-9]+)"
             search_obj = re.search(regex, args.rhsa)
             if not search_obj or len(search_obj.group(0)) != len(args.rhsa):
                 DagdaLogger.get_logger().error(
                     'Argument --rhsa: The rhba format must look like to RHSA-2012:234.')
                 return 22
     elif args.rhsa_info:
         if args.init or args.init_status or args.product or args.product_version or args.bid or args.cve_info \
                 or args.exploit_db or args.bid_info or args.exploit_db_info or args.cve or args.rhsa \
                 or args.rhba or args.rhba_info:
             DagdaLogger.get_logger().error('Argument --rhsa_info: this argument must be alone.')
             return 23
         else:
             regex = r"(RHSA-[0-9]{4}:[0-9]+)"
             search_obj = re.search(regex, args.rhsa_info)
             if not search_obj or len(search_obj.group(0)) != len(args.rhsa_info):
                 DagdaLogger.get_logger().error(
                     'Argument --rhsa_info: The rhsa format must look like to RHSA-2012:234.')
                 return 24
     # Else
     return 0
Пример #51
0
    def verify_args(args):
        if not args.dagda_server:
            DagdaLogger.get_logger().error('Wrong Dagda server endpoint.')
            return 1
        else:
            splitted_info = args.dagda_server.split(':')
            if len(splitted_info) != 2:
                DagdaLogger.get_logger().error('Wrong Dagda server endpoint.')
                return 1
            try:
                port = int(splitted_info[1])
                if port not in range(1, 65536):
                    DagdaLogger.get_logger().error('Wrong Dagda server endpoint.')
                    return 1
            except ValueError:
                DagdaLogger.get_logger().error('Wrong Dagda server endpoint.')
                return 1

        if not args.container_id and not args.docker_image:
            DagdaLogger.get_logger().error('Missing arguments.')
            return 2
        elif args.container_id and args.docker_image:
            DagdaLogger.get_logger().error('Arguments --docker_image/--container_id: Both arguments '
                                           'can not be together.')
            return 3
        # Else
        return 0