def parse_alerts(self, alerts): res = Result() line_count = 0 newline_count = 0 content = "" yml_indicator = "" xml_hits = ResultSection(title_text='xml Malware Indicator Match') if os.stat("/opt/al/pkg/al_services/alsvc_beach/alerts_generated.txt" ).st_size == 0: # Result file is empty, nothing to report return res for line in alerts: # Otherwise we iterate through each line to read the required information if line != "\n": line_count += 1 if line_count == 1: yml_indicator = line else: content += line + "\n" elif line_count == 0: newline_count += 1 else: newline_count = 0 xml_hits.add_section( XmlResultObject(yml_indicator, content, SCORE.VHIGH)) content = "" line_count = 0 res.add_result(xml_hits) return res
def parse_results(self, response): res = Result() response = response.get('results', response) if response is not None and response.get('response_code') == 1: av_hits = ResultSection(title_text='Anti-Virus Detections') url_section = ResultSection( SCORE.NULL, 'Virus total report permalink', self.SERVICE_CLASSIFICATION, body_format=TEXT_FORMAT.URL, body=json.dumps({"url": response.get('permalink')})) res.add_section(url_section) scans = response.get('scans', response) av_hits.add_line( 'Found %d AV hit(s) from %d scans.' % (response.get('positives'), response.get('total'))) for majorkey, subdict in sorted(scans.iteritems()): if subdict['detected']: virus_name = subdict['result'] res.append_tag( VirusHitTag(virus_name, context="scanner:%s" % majorkey)) av_hits.add_section( AvHitSection(majorkey, virus_name, SCORE.SURE)) res.add_result(av_hits) return res
def parse_results(self, response): res = Result() response = response.get('results', response) if response is not None and response.get('response_code') == 204: message = "You exceeded the public API request rate limit (4 requests of any nature per minute)" raise VTException(message) elif response is not None and response.get('response_code') == 203: message = "You tried to perform calls to functions for which you require a Private API key." raise VTException(message) elif response is not None and response.get('response_code') == 1: av_hits = ResultSection(title_text='Anti-Virus Detections') url_section = ResultSection( SCORE.NULL, 'Virus total report permalink', self.SERVICE_CLASSIFICATION, body_format=TEXT_FORMAT.URL, body=json.dumps({"url": response.get('permalink')})) res.add_section(url_section) scans = response.get('scans', response) av_hits.add_line('Found %d AV hit(s) from %d scans.' % (response.get('positives'), response.get('total'))) for majorkey, subdict in sorted(scans.iteritems()): if subdict['detected']: virus_name = subdict['result'] res.append_tag(VirusHitTag(virus_name, context="scanner:%s" % majorkey)) av_hits.add_section(AvHitSection(majorkey, virus_name, SCORE.SURE)) res.add_result(av_hits) return res
def execute(self, request): if not self.rules: return self.task = request.task local_filename = request.download() yara_externals = {} for k, i in self.get_yara_externals.iteritems(): # Check default request.task fields try: sval = self.task.get(i) except: sval = None if not sval: # Check metadata dictionary smeta = self.task.metadata if not smeta: sval = smeta.get(i, None) if not sval: # Check params dictionary smeta = self.task.params if not smeta: sval = smeta.get(i, None) # Create dummy value if item not found if not sval: sval = i yara_externals[k] = sval with self.initialization_lock: try: matches = self.rules.match(local_filename, externals=yara_externals) self.counters[RULE_HITS] += len(matches) request.result = self._extract_result_from_matches(matches) except Exception as e: if e.message != "internal error: 30": raise else: self.log.warning("Yara internal error 30 detected on submission {}" .format(self.task.sid)) section = ResultSection(title_text="Yara scan not completed.") section.add_line("File returned too many matches with current rule set and Yara exited.") result = Result() request.result = result result.add_result(section)
def parse_results(self, response): res = Result() response = response.get('scan_results', response) virus_name = "" if response is not None and response.get('progress_percentage') == 100: hit = False av_hits = ResultSection(title_text='Anti-Virus Detections') scans = response.get('scan_details', response) for majorkey, subdict in sorted(scans.iteritems()): score = SCORE.NULL if subdict['scan_result_i'] == 1: virus_name = subdict['threat_found'] if virus_name: score = SCORE.SURE elif subdict['scan_result_i'] == 2: virus_name = subdict['threat_found'] if virus_name: score = SCORE.VHIGH if score: virus_name = virus_name.replace("a variant of ", "") engine = self.engine_map[self._format_engine_name( majorkey)] res.append_tag( VirusHitTag(virus_name, context="scanner:%s" % majorkey)) av_hits.add_section( AvHitSection(majorkey, virus_name, engine, score)) hit = True if hit: res.add_result(av_hits) return res
def parse_api(data): result = Result() # Info block hash_info = data.get('hash_info') if not hash_info: return result r_info = ResultSection(title_text='File Info') r_info.score = SCORE.NULL r_info.add_line('Received Data: %s-%s-%s' % (data['received_date'][:4], data['received_date'][4:6], data['received_date'][6:])) r_info.add_line('Size: %s' % hash_info.get('filesize', "")) r_info.add_line('MD5: %s' % hash_info.get('md5', "")) r_info.add_line('SHA1: %s' % hash_info.get('sha1', "")) r_info.add_line('SHA256: %s' % hash_info.get('sha256', "")) r_info.add_line('SSDeep Blocksize: %s' % hash_info.get('ssdeep_blocksize', "")) r_info.add_line('SSDeep Hash1: %s' % hash_info.get('ssdeep_hash1', "")) r_info.add_line('SSDeep Hash2: %s' % hash_info.get('ssdeep_hash1', "")) result.add_result(r_info) callouts = data.get('callouts', []) if len(callouts) > 0: max_callouts = 10 r_callouts = ResultSection(title_text='Sandbox Call-Outs') r_callouts.score = SCORE.VHIGH analyser = '' r_call_sub_section = None reported_count = 0 for callout in callouts: reported_count += 1 if reported_count <= max_callouts: if analyser != callout['ip']: title = '%s (Analysed on %s)' % (callout['ip'], callout['addedDate']) r_call_sub_section = ResultSection(title_text=title, parent=r_callouts) analyser = callout['ip'] channel = callout['channel'] if channel is not None: channel = "(%s)" % channel.split('~~')[0] else: channel = "" r_call_sub_section.add_line("{0:s}:{1:d}{2:s}".format( callout['callout'], callout['port'], channel)) try: p1, p2, p3, p4 = callout['callout'].split(".") if int(p1) <= 255 and int(p2) <= 255 and int( p3) <= 255 and int(p4) <= 255: result.append_tag( Tag(TAG_TYPE.NET_IP, callout['callout'], TAG_WEIGHT.MED, context=Context.BEACONS)) except ValueError: result.append_tag( Tag(TAG_TYPE.NET_DOMAIN_NAME, callout['callout'], TAG_WEIGHT.MED, context=Context.BEACONS)) if callout['port'] != 0: result.append_tag( Tag(TAG_TYPE.NET_PORT, str(callout['port']), TAG_WEIGHT.MED, context=Context.BEACONS)) if len(callouts) > max_callouts: r_callouts.add_line("And %s more..." % str(len(callouts) - 10)) result.add_result(r_callouts) spamcount = data.get('spamCount', {}) if spamcount: r_spam = ResultSection(title_text='SPAM feed') r_spam.score = SCORE.VHIGH r_spam.add_line('Found %d related spam emails' % spamcount['count']) email_sample = spamcount.get("email_sample", {}) r_spam.add_line('\tFirst Seen: %s' % email_sample['firstSeen']) r_spam.add_line('\tLast Seen: %s' % email_sample['lastSeen']) r_sub_section = ResultSection(title_text='Attachments', parent=r_spam) if email_sample['filename']: r_sub_section.add_line( '%s - md5: %s' % (email_sample['filename'], email_sample['filenameMD5'])) if email_sample['attachment']: r_sub_section.add_line('%s - md5: %s' % (email_sample['attachment'], email_sample['attachmentMD5'])) result.add_result(r_spam) av_results = data.get('av_results', []) if len(av_results) > 0: r_av_sec = ResultSection(title_text='Anti-Virus Detections') r_av_sec.add_line('Found %d AV hit(s).' % len(av_results)) for av_result in av_results: r_av_sec.add_section( AvHitSection(av_result['scannerID'], av_result['name'], SCORE.SURE)) result.append_tag( VirusHitTag(av_result['name'], context="scanner:%s" % av_result['scannerID'])) result.add_result(r_av_sec) return result
def execute(self, request): """ Main Module. """ result = Result() request.result = result if (request.task.size or 0) < 50000 and ( request.tag.startswith('code') or (request.tag == "unknown" and (request.task.size or 0) < 5000)): patterns = PatternMatch() alfile = request.download() with open(alfile, "rb") as f: raw = f.read() # Get all IOCs that originally hit in file (to filter later- service FrankenStrings SHOULD catch it anyways) pat_values = patterns.ioc_match(raw, bogon_ip=True, just_network=False) before = [] for k, val in pat_values.iteritems(): if val == "": asc_asc = unicodedata.normalize('NFKC', val).encode( 'ascii', 'ignore') before.append(asc_asc) else: for v in val: before.append(v) # --- Stage 1 ---------------------------------------------------------------------------------------------- # Get script(s) that we want code_extracts = [('^unknown$', self.convert_wide_unicode), ('.*html.*', self.extract_htmlscript)] extracted_parts = None for tu in code_extracts: if re.match(re.compile(tu[0]), request.tag): extracted_parts = tu[1](raw) break if extracted_parts: parsed = [x for x in extracted_parts] else: parsed = [raw] # --- Stage 2 ---------------------------------------------------------------------------------------------- # Hack time! for script in parsed: extract_file = False layer = script layers_list = [] if request.deep_scan: self.max_attempts = 50 techniques = [ ('VBE Decode', self.vbe_decode, True), ('MSWord macro vars', self.mswordmacro_vars, False), ('Powershell vars', self.powershell_vars, False), ('Concat strings', self.concat_strings, False), ('String replace', self.string_replace, False), ('Powershell carets', self.powershell_carets, False), ('Array of strings', self.array_of_strings, False), ('Fake array vars', self.vars_of_fake_arrays, False), ('Simple XOR function', self.simple_xor_function, False), ('Charcode', self.charcode, False), ('Charcode hex', self.charcode_hex, False), ('B64 Decode', self.b64decode_str, False) ] done = False idx = 0 while not done: if idx > self.max_attempts: break done = True for name, technique, extract in techniques: final, res = technique(layer) if res: layers_list.append((name, res)) if extract: extract_file = True # Looks like it worked, restart with new layer layer = res done = final if done: break idx += 1 if len(layers_list) > 0: final_score = len(layers_list) * 10 clean = self.clean_up_final_layer(layers_list[-1][1]) if clean != raw: pat_values = patterns.ioc_match(clean, bogon_ip=True, just_network=False) after = [] for k, val in pat_values.iteritems(): if val == "": asc_asc = unicodedata.normalize( 'NFKC', val).encode('ascii', 'ignore') after.append(asc_asc) else: for v in val: after.append(v) diff_tags = list( set(before).symmetric_difference(set(after))) # Add additional checks to see if the file should be extracted. 1500 is an arbitrary score... if (len(clean) > 1000 and final_score > 500) or ( len(before) < len(after)): extract_file = True res = (ResultSection( SCORE.NULL, "CrowBar detected possible obfuscated script:")) mres = (ResultSection( SCORE.NULL, "The following CrowBar modules made deofuscation attempts:", parent=res)) mres.score = final_score lcount = Counter([x[0] for x in layers_list]) for l, c in lcount.iteritems(): mres.add_line("{0}, {1} time(s).".format(l, c)) if extract_file: self.submit_extracted(clean, res, request) # Display final layer lres = (ResultSection( SCORE.NULL, "Final layer:", body_format=TEXT_FORMAT.MEMORY_DUMP, parent=res)) if extract_file: lres.add_line("First 500 bytes of file:") lres.add_line(clean[:500]) else: lres.add_line("First 5000 bytes of file:") lres.add_line(clean[:5000]) # Look for all IOCs in final layer if len(pat_values) > 0 and len(diff_tags) > 0: for ty, val in pat_values.iteritems(): if val == "": asc_asc = unicodedata.normalize( 'NFKC', val).encode('ascii', 'ignore') if asc_asc in diff_tags: res.add_tag(TAG_TYPE[ty], asc_asc, TAG_WEIGHT.LOW) else: for v in val: if v in diff_tags: res.add_tag( TAG_TYPE[ty], v, TAG_WEIGHT.LOW) result.add_result(res)