示例#1
0
    def __init__(self, config: ConfigParser,
                 plugin_opts: Optional[Dict]) -> None:
        super().__init__(config, plugin_opts)

        self.sandbox_url = None
        self.apikey = None
        self.delay = 30
        self.max_attempts = 10
        self.useragent = 'Falcon Sandbox'
        # Available environments ID:
        #     300: 'Linux (Ubuntu 16.04, 64 bit)',
        #     200: 'Android Static Analysis’,
        #     160: 'Windows 10 64 bit’,
        #     110: 'Windows 7 64 bit’,
        #     100: ‘Windows 7 32 bit’
        self.environment_id = 160
        self.wait_for_results = True

        if plugin_opts and 'sandbox_url' in plugin_opts:
            self.sandbox_url = plugin_opts['sandbox_url']
        elif config.has_option('options', 'sandbox_url'):
            self.sandbox_url = config.get('options', 'sandbox_url')

        if plugin_opts and 'apikey' in plugin_opts:
            self.apikey = plugin_opts['apikey']
        elif config.has_option('options', 'apikey'):
            self.apikey = config.get('options', 'apikey')

        if plugin_opts and 'delay' in plugin_opts:
            self.delay = int(plugin_opts['delay'])
        elif config.has_option('options', 'delay'):
            self.delay = int(config.get('options', 'delay'))

        if plugin_opts and 'max_attempts' in plugin_opts:
            self.max_attempts = int(plugin_opts['max_attempts'])
        elif config.has_option('options', 'max_attempts'):
            self.max_attempts = config.getint('options', 'max_attempts')

        if plugin_opts and 'useragent' in plugin_opts:
            self.useragent = plugin_opts['useragent']
        elif config.has_option('options', 'useragent'):
            self.useragent = config.get('options', 'useragent')

        if plugin_opts and 'environment_id' in plugin_opts:
            self.environment_id = int(plugin_opts['environment_id'])
        elif config.has_option('options', 'environment_id'):
            self.environment_id = config.getint('options', 'environment_id')

        if plugin_opts and 'wait_for_results' in plugin_opts:
            self.wait_for_results = plugin_opts['wait_for_results']
        elif config.has_option('options', 'wait_for_results'):
            self.wait_for_results = config.getboolean('options',
                                                      'wait_for_results')

        if not self.sandbox_url:
            raise StoqPluginException("Falcon Sandbox URL was not provided")

        if not self.apikey:
            raise StoqPluginException(
                "Falcon Sandbox API Key was not provided")
示例#2
0
    def scan(self, payload: Payload,
             request_meta: RequestMeta) -> WorkerResponse:
        """
        Decodes and extracts information from Java Class files

        """

        results = {}

        try:
            content = unpack_class(payload.content)
        except ClassUnpackException as err:
            raise StoqPluginException(f'Unable to parse payload: {err}')

        try:
            results = {
                'provided': content.get_provides(),
                'required': content.get_requires(),
                'constants': [],
            }
            for obj, _, data in content.cpool.pretty_constants():
                if len(data) <= 6:
                    continue
                constants = {}
                constants['id'] = obj
                constants['data'] = data
                results['constants'].append(constants)
        except Exception as err:
            raise StoqPluginException(f'Unable to analyze Java Class {err}')

        return WorkerResponse(results)
示例#3
0
    def __init__(self, config: ConfigParser, plugin_opts: Optional[Dict]) -> None:
        super().__init__(config, plugin_opts)

        self.opswat_url = None
        self.apikey = None
        self.delay = 30
        self.max_attempts = 10

        if plugin_opts and 'opswat_url' in plugin_opts:
            self.opswat_url = plugin_opts['opswat_url']
        elif config.has_option('options', 'opswat_url'):
            self.opswat_url = config.get('options', 'opswat_url')

        if plugin_opts and 'apikey' in plugin_opts:
            self.apikey = plugin_opts['apikey']
        elif config.has_option('options', 'apikey'):
            self.apikey = config.get('options', 'apikey')

        if plugin_opts and 'delay' in plugin_opts:
            self.delay = int(plugin_opts['delay'])
        elif config.has_option('options', 'delay'):
            self.delay = int(config.get('options', 'delay'))

        if plugin_opts and 'max_attempts' in plugin_opts:
            self.max_attempts = int(plugin_opts['max_attempts'])
        elif config.has_option('options', 'max_attempts'):
            self.max_attempts = int(config.get('options', 'max_attempts'))

        if not self.opswat_url:
            raise StoqPluginException("MetaDefender URL was not provided")

        if not self.apikey:
            raise StoqPluginException("MetaDefender API Key was not provided")
示例#4
0
    def __init__(self, config: StoqConfigParser) -> None:
        super().__init__(config)

        self.opswat_url = config.get('options', 'opswat_url', fallback=None)
        if not self.opswat_url:
            raise StoqPluginException('MetaDefender URL was not provided')
        self.apikey = config.get('options', 'apikey', fallback=None)
        if not self.apikey:
            raise StoqPluginException('MetaDefender API Key was not provided')
        self.delay = config.getint('options', 'delay', fallback=10)
        self.max_attempts = config.getint('options',
                                          'max_attempts',
                                          fallback=10)
示例#5
0
    def __init__(self, config: StoqConfigParser) -> None:
        super().__init__(config)

        self.workspaceid = config.get('options', 'workspaceid', fallback=None)
        if not self.workspaceid:
            raise StoqPluginException('workspaceid has not been defined')

        self.workspacekey = config.get('options',
                                       'workspacekey',
                                       fallback=None)
        if not self.workspacekey:
            raise StoqPluginException('workspacekey has not been defined')

        self.logtype = config.get('options', 'logtype', fallback='stoQ')
        self.uri = f'https://{self.workspaceid}.ods.opinsights.azure.com{self.API_RESOURCE}?api-version={self.API_VERSION}'
示例#6
0
 def compile_rules(self, filepath: str) -> None:
     filepath = os.path.realpath(filepath)
     if not os.path.isfile(filepath):
         raise StoqPluginException(
             f"Nonexistent yara rules file provided: {filepath}")
     else:
         return yara.compile(filepath=filepath)
示例#7
0
    def scan(self, payload: Payload, request_meta: RequestMeta) -> WorkerResponse:
        """
        Scan a payload using TRiD

        """
        results = {}

        with tempfile.NamedTemporaryFile() as temp_file:
            temp_file.write(payload.content)
            temp_file.flush()
            try:
                cmd = [self.bin_path, f"-d:{self.trid_defs}", temp_file.name]
                trid_results = check_output(cmd).splitlines()
            except Exception as err:
                raise StoqPluginException('Failed gathering TRiD data')

        for line in trid_results[6:]:
            if line.startswith('Warning'.encode()):
                break
            line = line.decode().split()
            if line:
                ext = line[1].strip('(.)')
                results[ext] = {'likely': line[0], 'type': ' '.join(line[2:])}

        return WorkerResponse(results)
    def __init__(self, config: ConfigParser,
                 plugin_opts: Optional[Dict]) -> None:
        super().__init__(config, plugin_opts)

        self.apikey = None
        self.time_slice = '1m'
        self.download = False

        if plugin_opts and 'apikey' in plugin_opts:
            self.apikey = plugin_opts['apikey']
        elif config.has_option('options', 'apikey'):
            self.apikey = config.get('options', 'apikey')

        if plugin_opts and 'time_since' in plugin_opts:
            self.time_since = plugin_opts['time_since']
        elif config.has_option('options', 'time_since'):
            self.time_since = config.get('options', 'time_since')

        if plugin_opts and 'download' in plugin_opts:
            self.download = plugin_opts['download']
        elif config.has_option('options', 'download'):
            self.download = config.get('options', 'download')

        if not self.apikey:
            raise StoqPluginException("VTMIS API Key does not exist")
示例#9
0
    def __init__(self, config: StoqConfigParser) -> None:
        super().__init__(config)

        self.source_dir = config.get('options', 'source_dir', fallback=None)
        if not self.source_dir or not os.path.exists(self.source_dir):
            raise StoqPluginException(
                f"Source directory not defined or doesn't exist: '{self.source_dir}'"
            )
        self.source_dir = os.path.abspath(self.source_dir)
    def __init__(self, config: StoqConfigParser) -> None:
        super().__init__(config)

        self.apikey = config.get('options', 'apikey', fallback=None)
        self.time_since = config.get('options', 'time_since', fallback='1m')
        self.download = config.getboolean('options',
                                          'download',
                                          fallback=False)
        if not self.apikey:
            raise StoqPluginException('VTMIS API Key does not exist')
示例#11
0
    def __init__(self, config: StoqConfigParser) -> None:
        super().__init__(config)

        self.sandbox_url = config.get('options', 'sandbox_url', fallback=None)
        if not self.sandbox_url:
            raise StoqPluginException("Falcon Sandbox URL was not provided")
        self.apikey = config.get('options', 'apikey', fallback=None)
        if not self.apikey:
            raise StoqPluginException("Falcon Sandbox API Key was not provided")
        self.delay = config.getint('options', 'delay', fallback=30)
        self.max_attempts = config.getint('options', 'max_attempts', fallback=10)
        self.useragent = config.get('options', 'useragent', fallback='Falcon Sandbox')
        # Available environments ID:
        #     300: 'Linux (Ubuntu 16.04, 64 bit)',
        #     200: 'Android Static Analysis’,
        #     160: 'Windows 10 64 bit’,
        #     110: 'Windows 7 64 bit’,
        #     100: ‘Windows 7 32 bit’
        self.environment_id = config.getint('options', 'environment_id', fallback=160)
        self.wait_for_results = config.getboolean(
            'options', 'wait_for_results', fallback=True
        )
示例#12
0
    def __init__(self, config: ConfigParser,
                 plugin_opts: Optional[Dict]) -> None:
        super().__init__(config, plugin_opts)

        self.apikey = None

        if plugin_opts and 'apikey' in plugin_opts:
            self.apikey = plugin_opts['apikey']
        elif config.has_option('options', 'apikey'):
            self.apikey = config.get('options', 'apikey')

        if not self.apikey:
            raise StoqPluginException("VTMIS API Key does not exist")
示例#13
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        """
        Scan a payload using LIEF

        """
        filename = payload.results.payload_meta.extra_data.get(
            'filename', payload.results.payload_id)

        try:
            binary = lief.parse(raw=payload.content, name=filename)
        except lief.exception as err:
            raise StoqPluginException(f'Unable to parse payload: {err}')

        if binary is None:
            raise StoqPluginException('The file type isn\'t supported by LIEF')

        if self.abstract == True:
            results = lief.to_json_from_abstract(binary.abstract)
        else:
            results = lief.to_json(binary)

        return WorkerResponse(json.loads(results))
示例#14
0
    def scan(self, payload: Payload, request_meta: RequestMeta) -> WorkerResponse:
        """
        Scan a payload using Exiftool

        """
        with tempfile.NamedTemporaryFile() as temp_file:
            temp_file.write(payload.content)
            temp_file.flush()
            try:
                cmd = [self.bin_path, '-j', '-n', temp_file.name]
                output = run(cmd, stdout=PIPE)
                results = json.loads(output.stdout)[0]
            except Exception as err:
                raise StoqPluginException(f'Failed gathering exif data: {err}')
        return WorkerResponse(results)
示例#15
0
    def __init__(self, config: ConfigParser, plugin_opts: Optional[Dict]) -> None:
        super().__init__(config, plugin_opts)

        self.source_dir = None

        if plugin_opts and 'source_dir' in plugin_opts:
            self.source_dir = plugin_opts['source_dir']
        elif config.has_option('options', 'source_dir'):
            self.source_dir = config.get('options', 'source_dir')

        if not self.source_dir or not os.path.exists(self.source_dir):
            raise StoqPluginException(
                f"Source directory not defined or doesn't exist: '{self.source_dir}'"
            )
        self.source_dir = os.path.abspath(self.source_dir)
示例#16
0
    async def ingest(self, queue: Queue) -> None:
        """
        Ingest files from a directory

        """
        if not self.source_dir:
            raise StoqPluginException('Source directory not defined')
        source_path = Path(self.source_dir).resolve()
        if source_path.is_dir():
            if self.recursive:
                for path in source_path.rglob('**/*'):
                    await self._queue(path, queue)
            else:
                for path in source_path.glob('*'):
                    await self._queue(path, queue)
        else:
            await self._queue(source_path, queue)
示例#17
0
    def __init__(self, config: StoqConfigParser) -> None:
        super().__init__(config)

        filename = getframeinfo(currentframe()).filename
        parent = Path(filename).resolve().parent

        self.bin = config.get('options', 'bin', fallback='trid')
        self.skip_warnings = config.getlist(
            'options',
            'skip_warnings',
            fallback=['file seems to be plain text/ASCII'])
        self.trid_defs = config.get('options',
                                    'trid_defs',
                                    fallback='triddefs.trd')
        if not os.path.isabs(self.trid_defs) and self.trid_defs:
            self.trid_defs = os.path.join(parent, self.trid_defs)
        if not os.path.isfile(self.trid_defs):
            raise StoqPluginException(
                f'TrID definitions do not exist at {self.trid_defs}')
示例#18
0
    def ingest(self, queue: Queue) -> None:
        """
        Ingest files from a directory

        """
        if not self.source_dir:
            raise StoqPluginException('Source directory not defined')
        if os.path.isdir(self.source_dir):
            if self.recursive:
                for root_path, subdirs, files in os.walk(self.source_dir):
                    for entry in files:
                        path = os.path.join(root_path, entry)
                        self._queue(path, queue)
            else:
                for entry in os.scandir(self.source_dir):
                    if not entry.name.startswith('.') and entry.is_file():
                        path = os.path.join(self.source_dir, entry.name)
                        self._queue(path, queue)
        elif os.path.isfile(self.source_dir):
            self._queue(self.source_dir, queue)
示例#19
0
    def decorate(self, response: StoqResponse) -> DecoratorResponse:
        """
        Decorate results using a template

        """
        results = None
        try:
            dirname = os.path.dirname(self.template)
            basename = os.path.basename(self.template)
            env = Environment(
                loader=FileSystemLoader(dirname),
                trim_blocks=True,
                lstrip_blocks=True,
                autoescape=select_autoescape(default_for_string=True, default=True),
            )
            results = env.get_template(basename).render(response=response)
        except TemplateNotFound:
            raise StoqPluginException(f'Template path not found: {self.template}')

        return DecoratorResponse(results)
示例#20
0
    def __init__(self, config: ConfigParser,
                 plugin_opts: Optional[Dict]) -> None:
        super().__init__(config, plugin_opts)

        self.trid_defs = 'triddefs.trd'
        self.bin_path = 'trid'
        filename = getframeinfo(currentframe()).filename
        parent = Path(filename).resolve().parent

        if plugin_opts and 'trid_defs' in plugin_opts:
            self.trid_defs = plugin_opts['trid_defs']
        elif config.has_option('options', 'trid_defs'):
            self.trid_defs = config.get('options', 'trid_defs')
        if not os.path.isabs(self.trid_defs) and self.trid_defs:
            self.trid_defs = os.path.join(parent, self.trid_defs)
        if not self.trid_defs or not os.path.isfile(self.trid_defs):
            raise StoqPluginException(
                f'TrID definitions do not exist at {self.trid_defs}')

        if plugin_opts and 'bin_path' in plugin_opts:
            self.bin_path = plugin_opts['bin_path']
        elif config.has_option('options', 'bin_path'):
            self.bin_path = config.get('options', 'bin_path')
示例#21
0
    def scan(self, payload: Payload,
             request_meta: RequestMeta) -> WorkerResponse:
        """
        Decompress a payload

        request_meta:
            - passwords
            - archiver
        """

        if len(payload.content) > self.maximum_size:
            raise StoqPluginException(
                f'Compressed file too large: {len(payload.content)} > {self.maximum_size}'
            )

        archiver = None
        mimetype = None
        results = {}
        errors = []
        extracted = []
        passwords = request_meta.extra_data.get('passwords', self.passwords)
        if isinstance(passwords, str):
            passwords = [p.strip() for p in passwords.split(',')]

        # Determine the mimetype of the payload so we can identify the
        # correct archiver. This should either be based off the request_meta
        # (useful when payload is passed via dispatching) or via magic
        if 'archiver' in request_meta.extra_data:
            if request_meta.extra_data['archiver'] in self.ARCHIVE_CMDS:
                archiver = self.ARCHIVE_CMDS[
                    request_meta.extra_data['archiver']]
            else:
                raise StoqPluginException(
                    f"Unknown archive type of {request_meta['archiver']}")
        else:
            mimetype = magic.from_buffer(payload.content, mime=True)
            if mimetype in self.ARCHIVE_MAGIC:
                archive_type = self.ARCHIVE_MAGIC[mimetype]
                if archive_type in self.ARCHIVE_CMDS:
                    archiver = self.ARCHIVE_CMDS[archive_type]
                else:
                    raise StoqPluginException(
                        f'Unknown archive type of {archive_type}')
        if not archiver:
            raise StoqPluginException(
                f'Unable to determine archive type, mimetype: {mimetype}')

        with tempfile.TemporaryDirectory() as extract_dir:
            fd, archive_file = tempfile.mkstemp(dir=extract_dir)
            with open(fd, 'xb') as f:
                f.write(payload.content)
                f.flush()
            archive_outdir = tempfile.mkdtemp(dir=extract_dir)
            for password in passwords:
                cmd = archiver.replace('%INFILE%', shlex.quote(archive_file))
                cmd = cmd.replace('%OUTDIR%', shlex.quote(archive_outdir))
                cmd = cmd.replace('%PASSWORD%', shlex.quote(password))
                cmd = cmd.split(" ")
                p = Popen(cmd,
                          stdout=PIPE,
                          stderr=PIPE,
                          universal_newlines=True)
                try:
                    outs, errs = p.communicate(timeout=self.timeout)
                except TimeoutExpired:
                    p.kill()
                    raise StoqPluginException(
                        'Timed out decompressing payload')
                if p.returncode == 0:
                    break

            for root, dirs, files in os.walk(archive_outdir):
                for f in files:
                    path = os.path.join(extract_dir, root, f)
                    if os.path.getsize(path) > self.maximum_size:
                        errors.append(
                            f'Extracted object is too large ({os.path.getsize(path)} > {self.maximum_size})'
                        )
                        continue
                    with open(path, "rb") as extracted_file:
                        meta = PayloadMeta(extra_data={'filename': f})
                        try:
                            data = extracted_file.read()
                        except OSError as err:
                            errors.append(
                                f'Unable to access extracted content: {err}')
                            continue
                        extracted.append(ExtractedPayload(data, meta))
        return WorkerResponse(results, errors=errors, extracted=extracted)
示例#22
0
    def __init__(self, config: StoqConfigParser) -> None:
        super().__init__(config)

        self.apikey = config.get('options', 'apikey', fallback=None)
        if not self.apikey:
            raise StoqPluginException("VTMIS API Key does not exist")