async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
     extracted: List[ExtractedPayload] = []
     errors: List[Error] = []
     try:
         parsed_xml = parseString(payload.content)
     except ExpatError as err:
         errors.append(
             Error(
                 error=f'Unable to parse payload as XML with xdpcarve: {err}',
                 plugin_name=self.plugin_name,
                 payload_id=payload.results.payload_id,
             )
         )
         return WorkerResponse(errors=errors)
     for name in self.elements:
         dom_element = parsed_xml.getElementsByTagName(name)
         for dom in dom_element:
             content = dom.firstChild.nodeValue
             content = content.rstrip()
             try:
                 content = base64.b64decode(content)
             except:
                 pass
             meta = PayloadMeta(extra_data={'element_name': name})
             extracted.append(ExtractedPayload(content, meta))
     return WorkerResponse(extracted=extracted, errors=errors)
Example #2
0
 async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
     return WorkerResponse(
         results={
             'sha256': sha256(payload.content).hexdigest(),
             'md5': md5(payload.content).hexdigest(),
             'sha1': sha1(payload.content).hexdigest(),
         })
Example #3
0
 async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
     results = parse_zip(
         BytesIO(payload.content),
         decompress_files=self.decompress_files,
         derive_deflate_level=self.derive_deflate_level,
     )
     return WorkerResponse(results)
Example #4
0
    def scan(self, payload: Payload,
             request_meta: RequestMeta) -> WorkerResponse:
        """
        Scan a payload using xorsearch

        """
        with tempfile.NamedTemporaryFile() as temp_file:
            temp_file.write(payload.content)
            temp_file.flush()
            cmd = [self.bin_path, '-f', self.terms, temp_file.name]
            process_results = check_output(cmd).splitlines()

        result = {}
        for line in process_results:
            line = line.decode()
            _, _, key, _, pos, hit = line.split(maxsplit=5)
            # We are going to skip over hits that are not xor'd
            if key != '00':
                key = f'0x{key}'
                if key not in result:
                    result[key] = []
                result[key].append({
                    'pos': f'0x{pos.replace("(-1):", "")}',
                    'match': hit
                })

        return WorkerResponse(result)
Example #5
0
    def scan(self, payload: Payload,
             request_meta: RequestMeta) -> WorkerResponse:
        """
        Scan a payload using pefile

        """

        pe = pefile.PE(data=payload.content)
        results = {}
        results['imphash'] = self.get_imphash(pe)
        results['compile_time'] = self.get_compiletime(pe)
        results['packer'] = self.get_packer(pe)
        results['is_packed'] = self.is_packed(pe)
        results['is_exe'] = self.is_exe(pe)
        results['is_dll'] = self.is_dll(pe)
        results['is_driver'] = self.is_driver(pe)
        results['is_valid'] = self.is_valid(pe)
        results['is_suspicious'] = self.is_suspicious(pe)
        results['machine_type'] = self.get_machinetype(pe)
        results['entrypoint'] = self.get_entrypoint(pe)
        results['section_count'] = self.get_sectioncount(pe)
        results['sections'] = self.get_sections(pe)
        results['imports'] = self.get_imports(pe)
        results['rich_header'] = self.get_rich_header(pe)
        pe.close()

        return WorkerResponse(results)
Example #6
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        xorkey: Union[List[int], str, int,
                      None] = dpath.util.get(payload.dispatch_meta,
                                             '**/xorkey',
                                             default=None)

        if not xorkey:
            return
        elif isinstance(xorkey, str):
            xorkey = [int(k.strip()) for k in xorkey.split(',')]
        elif isinstance(xorkey, int):
            xorkey = [xorkey]

        last_rolling_index = len(xorkey) - 1
        current_rolling_index = 0
        payload_bytes = bytearray(payload.content)

        for index in range(payload.results.size):
            xor_value = xorkey[current_rolling_index]
            payload_bytes[index] ^= xor_value
            if current_rolling_index < last_rolling_index:
                current_rolling_index += 1
            else:
                current_rolling_index = 0

        payload.results.payload_meta.extra_data['xorkey'] = xorkey
        meta = PayloadMeta(extra_data={'xorkey': xorkey})
        extracted = [ExtractedPayload(bytes(payload_bytes), meta)]
        return WorkerResponse(extracted=extracted)
Example #7
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)
Example #8
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        """
        Scan payloads using OPSWAT MetaDefender

        """

        errors: List[Error] = []
        headers = {
            'apikey':
            self.apikey,
            'content-type':
            'application/octet-stream',
            'filename':
            payload.results.payload_meta.extra_data.get(
                'filename', get_sha1(payload.content)),
        }
        response = requests.post(self.opswat_url,
                                 data=payload.content,
                                 headers=headers)
        response.raise_for_status()
        data_id = response.json()['data_id']
        results, error = self._parse_results(data_id)
        if error:
            errors.append(
                Error(
                    error=error,
                    plugin_name=self.plugin_name,
                    payload_id=payload.results.payload_id,
                ))
        return WorkerResponse(results, errors=errors)
Example #9
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        """
        Scan payloads using OPSWAT MetaDefender

        """

        errors: List[Error] = []
        headers = {
            'apikey':
            self.apikey,
            'content-type':
            'application/octet-stream',
            'filename':
            payload.results.payload_meta.extra_data.get(
                'filename',
                get_sha1(payload.content).encode()).decode(),
        }
        async with aiohttp.ClientSession(raise_for_status=True) as session:
            async with session.post(self.opswat_url,
                                    data=payload.content,
                                    headers=headers) as response:
                content = await response.json()
                data_id = content['data_id']
        results, error = await self._parse_results(data_id)
        if error:
            errors.append(
                Error(
                    error=error,
                    plugin_name=self.plugin_name,
                    payload_id=payload.results.payload_id,
                ))
        return WorkerResponse(results, errors=errors)
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        """
        Return individual result from vtmis-filefeed provider

        """
        extracted: List[ExtractedPayload] = []
        errors: List[Error] = []
        results: Dict = json.loads(payload.content)
        if self.download:
            self.log.info(f'Downloading VTMIS sample sha1: {results["sha1"]}')
            try:
                response = requests.get(results['link'])
                response.raise_for_status()
                extracted = [ExtractedPayload(response.content)]
            except Exception as err:
                errors.append(
                    Error(
                        error=
                        f'Unable to download sample {results["sha1"]}: {err}',
                        plugin_name=self.plugin_name,
                        payload_id=payload.results.payload_id,
                    ))
        return WorkerResponse(results=results,
                              errors=errors,
                              extracted=extracted)
Example #11
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:

        normalize: bool = True
        ioctype: str = 'all'
        results: Dict = {}

        if ioctype == 'all':
            for ioc in self.compiled_re:
                if self.compiled_re[ioc]:
                    matches = self.compiled_re[ioc].findall(payload.content.decode())
                    if matches:
                        results[ioc] = list(set(matches))
        elif self.compiled_re[ioctype]:
            matches = self.compiled_re[ioctype].findall(payload.content.decode())
            if matches:
                results[ioctype] = list(set(matches))

        if 'ipv6' in results:
            results['ipv6'] = [
                address for address in results['ipv6'] if self._validate_ipv6(address)
            ]
            if not results['ipv6']:
                results.pop('ipv6')

        if normalize:
            results = self._normalize(results)

        return WorkerResponse(results)
Example #12
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)
Example #13
0
 async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
     results = {
         'matches': [
             m async for m in self._yara_matches(payload.content,
                                                 self.worker_rules)
         ]
     }
     return WorkerResponse(results=results)
Example #14
0
    def scan(self, payload: Payload, request_meta: RequestMeta) -> WorkerResponse:
        """
        Upload content to a Tika server for automated text extraction

        """
        response = requests.put(self.tika_url, data=payload.content)
        response.raise_for_status()
        extracted = ExtractedPayload(response.content)
        return WorkerResponse(extracted=extracted)
Example #15
0
 async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
     entropy: float = 0.0
     results: Dict[str, float] = {}
     if payload.content:
         occurences = Counter(bytearray(payload.content))
         for bc in occurences.values():
             b = float(bc) / len(payload.content)
             entropy -= b * math.log(b, 2)
     results['entropy'] = entropy
     return WorkerResponse(results=results)
Example #16
0
 async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
     if USE_PYTHON_MAGIC:
         magic_scan = magic.Magic(mime=True)
         magic_result = magic_scan.from_buffer(payload.content[0:1000])
     else:
         with magic.Magic(flags=magic.MAGIC_MIME_TYPE) as m:
             magic_result = m.id_buffer(payload.content[0:1000])
     if hasattr(magic_result, 'decode'):
         magic_result = magic_result.decode('utf-8')
     return WorkerResponse(results={'mimetype': magic_result})
Example #17
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        """
        Scan a payload using TRiD

        """
        results: DefaultDict = defaultdict(list)
        errors: List[Error] = []
        unknown_ext: int = 0

        with tempfile.NamedTemporaryFile() as temp_file:
            temp_file.write(payload.content)
            temp_file.flush()
            env = os.environ.copy()
            env['LC_ALL'] = 'C'
            p = Popen(
                [self.bin, f"-d:{self.trid_defs}", temp_file.name],
                stdout=PIPE,
                stderr=PIPE,
                env=env,
                universal_newlines=True,
            )
            trid_results, err = p.communicate()
            if err:
                errors.append(
                    Error(
                        error=err,
                        plugin_name=self.plugin_name,
                        payload_id=payload.results.payload_id,
                    ))

        matches = re.findall(r'^ {0,2}[0-9].*%.*$', trid_results, re.M)
        warnings = re.findall(r'^Warning: (.*$)', trid_results, re.M)
        errors.extend([
            Error(
                error=w,
                plugin_name=self.plugin_name,
                payload_id=payload.results.payload_id,
            ) for w in warnings if w not in self.skip_warnings
        ])
        for match in matches:
            match = match.split()
            if match:
                try:
                    ext = match[1].strip('(.)')
                    if not ext:
                        ext = f'UNK{unknown_ext}'
                        unknown_ext += 1
                    results[ext].append({
                        'likely': match[0],
                        'type': ' '.join(match[2:])
                    })
                except IndexError:
                    continue
        return WorkerResponse(results, errors=errors)
Example #18
0
 def scan(self, payload: Payload,
          request_meta: RequestMeta) -> WorkerResponse:
     extracted = []
     errors = []
     try:
         parsed_xml = parseString(payload.content)
     except ExpatError as err:
         errors.append(
             f'Unable to parse payload as XML with xdpcarve: {err}')
         return WorkerResponse(errors=errors)
     for name in self.elements:
         dom_element = parsed_xml.getElementsByTagName(name)
         for dom in dom_element:
             content = dom.firstChild.nodeValue
             content = content.rstrip()
             try:
                 content = base64.b64decode(content)
             except:
                 pass
             meta = PayloadMeta(extra_data={"element_name": name})
             extracted.append(ExtractedPayload(content, meta))
     return WorkerResponse(extracted=extracted, errors=errors)
Example #19
0
 def scan(self, payload: Payload,
          request_meta: RequestMeta) -> WorkerResponse:
     matches = self.worker_rules.match(data=payload.content, timeout=60)
     dict_matches = []
     for match in matches:
         dict_matches.append({
             'tags': match.tags,
             'namespace': match.namespace,
             'rule': match.rule,
             'meta': match.meta,
             'strings': match.strings[:self.strings_limit],
         })
     results = {"matches": dict_matches}
     return WorkerResponse(results=results)
Example #20
0
 async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
     extracted: List[ExtractedPayload] = []
     tnef_results = TNEF(payload.content)
     if tnef_results.attachments:
         for tnef_attachment in tnef_results.attachments:
             try:
                 filename = UnicodeDammit(
                     tnef_attachment.name).unicode_markup
             except:
                 filename = "None"
             tnef_meta = PayloadMeta(extra_data={'filename': filename})
             extracted.append(
                 ExtractedPayload(tnef_attachment.data, tnef_meta))
     return WorkerResponse(extracted=extracted)
Example #21
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)
Example #22
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        """
        Scan a payload using Exiftool

        """
        errors: List[Error] = []
        try:
            cmd = [self.bin, '-j', '-n', '-']
            p = Popen(cmd, stdout=PIPE, stdin=PIPE)
            out, err = p.communicate(input=payload.content)
            results = json.loads(out)[0]
        except Exception as err:
            errors.append(
                Error(err,
                      plugin_name=self.plugin_name,
                      payload_id=payload.payload_id))
        return WorkerResponse(results, errors=errors)
Example #23
0
    def scan(self, payload: Payload,
             request_meta: RequestMeta) -> WorkerResponse:
        """
        Carve and decompress SWF files from payloads

        """

        extracted = []
        errors = []
        content = BytesIO(payload.content)
        content.seek(0)
        for start, end in self._carve(content):
            ex, err = self.decompress(content, start)
            if ex:
                extracted.append(ex)
            if err:
                errors.extend(err)
        return WorkerResponse(extracted=extracted, errors=errors)
Example #24
0
    def scan(self, payload: Payload, request_meta: RequestMeta) -> WorkerResponse:
        """
        Scan payloads using OPSWAT MetaDefender

        """

        headers = {
            'apikey': self.apikey,
            'filename': payload.payload_meta.extra_data.get(
                'filename', get_sha1(payload.content)
            ),
        }
        response = requests.post(self.opswat_url, data=payload.content, headers=headers)
        response.raise_for_status()
        data_id = response.json()['data_id']
        results, errors = self._parse_results(data_id)
        if errors:
            errors = [errors]
        return WorkerResponse(results, errors=errors)
Example #25
0
    def scan(self, payload: Payload,
             request_meta: RequestMeta) -> WorkerResponse:
        """
        Scan a payload using TRiD

        """
        results: DefaultDict = defaultdict(list)
        errors: List[str] = []

        with tempfile.NamedTemporaryFile() as temp_file:
            temp_file.write(payload.content)
            temp_file.flush()
            p = Popen(
                [self.bin_path, f"-d:{self.trid_defs}", temp_file.name],
                stdout=PIPE,
                stderr=PIPE,
                env={'LC_ALL': 'C'},
                universal_newlines=True,
            )
            trid_results, err = p.communicate()
            if err:
                errors.append(err)

        unknown_ext = 0
        matches = re.findall(r'^ {0,2}[0-9].*%.*$', trid_results, re.M)
        warnings = re.findall(r'^Warning: (.*$)', trid_results, re.M)
        errors.extend([w for w in warnings])
        for match in matches:
            match = match.split()
            if match:
                try:
                    ext = match[1].strip('(.)')
                    if not ext:
                        ext = f'UNK{unknown_ext}'
                        unknown_ext += 1
                    results[ext].append({
                        'likely': match[0],
                        'type': ' '.join(match[2:])
                    })
                except IndexError:
                    continue
        return WorkerResponse(results, errors=errors)
Example #26
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        extracted: List[ExtractedPayload] = []
        rtf = rtfobj.RtfObjParser(payload.content)
        rtf.parse()

        for obj_idx, obj in enumerate(rtf.objects):
            if obj.is_ole:
                data = obj.oledata
                meta = PayloadMeta(extra_data={'index': obj_idx})
            elif obj.is_package:
                data = obj.olepkgdata
                meta = PayloadMeta(extra_data={
                    'index': obj_idx,
                    'filename': obj.filename
                })
            else:
                data = obj.rawdata
                meta = PayloadMeta(extra_data={'index': obj_idx})
            extracted.append(ExtractedPayload(data, meta))
        return WorkerResponse(extracted=extracted)
Example #27
0
    async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
        """
        Search VTMIS for sha1 hash of a payload or from results of `iocextract` plugin

        """
        results: List[Dict] = []
        seen: Set[str] = set()

        if 'iocextract' in payload.results.workers:
            for key, iocs in payload.results.workers['iocextract'].items():
                for ioc in iocs:
                    if key in self.ENDPOINTS and ioc not in seen:
                        response = self._query_api(ioc, key)
                        seen.add(ioc)
                        results.append(response)
        if not results:
            sha1 = get_sha1(payload.content)
            results = self._query_api(sha1, 'sha1')

        return WorkerResponse(results=results)
Example #28
0
 async def scan(self, payload: Payload, request: Request) -> WorkerResponse:
     extracted: List[ExtractedPayload] = []
     errors: List[Error] = []
     ole_object = olefile.OleFileIO(payload.content)
     streams = ole_object.listdir(streams=True)
     for stream in streams:
         try:
             stream_buffer = ole_object.openstream(stream).read()
             name = ''.join(
                 filter(lambda x: x in string.printable, '_'.join(stream)))
             if stream_buffer.endswith(b'\x01Ole10Native'):
                 ole_native = oleobj.OleNativeStream(stream_buffer)
                 if ole_native.filename:
                     name = f'{name}_{str(ole_native.filename)}'
                 else:
                     name = f'{name}_olenative'
                 meta = PayloadMeta(
                     should_archive=False,
                     extra_data={
                         'index': streams.index(stream),
                         'name': name
                     },
                 )
                 extracted.append(ExtractedPayload(ole_native.data, meta))
             else:
                 meta = PayloadMeta(
                     should_archive=False,
                     extra_data={
                         'index': streams.index(stream),
                         'name': name
                     },
                 )
                 extracted.append(ExtractedPayload(stream_buffer, meta))
         except Exception as err:
             errors.append(
                 Error(
                     error=str(err),
                     plugin_name=self.plugin_name,
                     payload_id=payload.payload_id,
                 ))
     return WorkerResponse(extracted=extracted, errors=errors)
Example #29
0
    def scan(self, payload: Payload,
             request_meta: RequestMeta) -> WorkerResponse:
        """
        Scan payloads using Falcon Sandbox

        """

        errors = None
        url = f'{self.sandbox_url}/submit/file'
        headers = {'api-key': self.apikey, 'user-agent': self.useragent}
        filename = payload.payload_meta.extra_data.get(
            'filename', helpers.get_sha1(payload.content))
        if isinstance(filename, bytes):
            filename = filename.decode()
        files = {'file': (filename, payload.content)}
        data = {'environment_id': self.environment_id}
        response = requests.post(url, data=data, files=files, headers=headers)
        response.raise_for_status()
        results = response.json()
        if self.wait_for_results:
            results, errors = self._parse_results(results['job_id'])
        return WorkerResponse(results, errors=errors)
Example #30
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))