def export(self, ole, export_path): if not os.path.exists(export_path): try: os.makedirs(export_path) except Exception as e: self.log( 'error', "Unable to create directory at {0}: {1}".format( export_path, e)) return else: if not os.path.isdir(export_path): self.log('error', "You need to specify a folder, not a file") return for stream in ole.listdir(streams=True, storages=True): try: stream_content = ole.openstream(stream).read() except Exception as e: self.log( 'warning', "Unable to open stream {0}: {1}".format( string_clean('/'.join(stream)), e)) continue store_path = os.path.join(export_path, string_clean('-'.join(stream))) flash_objects = self.detect_flash(ole.openstream(stream).read()) if len(flash_objects) > 0: self.log('info', "Saving Flash objects...") count = 1 for flash in flash_objects: # If SWF Is compressed save the swf and the decompressed data seperatly. if flash[2]: save_path = '{0}-FLASH-Decompressed{1}'.format( store_path, count) with open(save_path, 'wb') as flash_out: flash_out.write(flash[4]) self.log( 'item', "Saved Decompressed Flash File to {0}".format( save_path)) save_path = '{0}-FLASH-{1}'.format(store_path, count) with open(save_path, 'wb') as flash_out: flash_out.write(flash[3]) self.log('item', "Saved Flash File to {0}".format(save_path)) count += 1 with open(store_path, 'wb') as out: out.write(stream_content) self.log('info', "Saved stream to {0}".format(store_path)) ole.close()
def parse_vba(self, save_path): save = False vba = VBA_Parser(__sessions__.current.file.path) # Check for Macros if not vba.detect_vba_macros(): self.log('error', "No Macro's Detected") return self.log('info', "Macro's Detected") try: run_rows = [] word_rows = [] pattern_rows = [] for (filename, stream_path, vba_filename, vba_code) in vba.extract_macros(): self.log('info', "Stream Details") self.log('item', "OLE Stream: {0}".format(string_clean(stream_path))) self.log('item', "VBA Filename: {0}".format(string_clean(vba_filename))) autoexec_keywords = detect_autoexec(vba_code) if autoexec_keywords: for keyword, description in autoexec_keywords: run_rows.append([keyword, description]) # Match Keyword Types suspicious_keywords = detect_suspicious(vba_code) if suspicious_keywords: for keyword, description in suspicious_keywords: word_rows.append([keyword, description]) # Match IOCs patterns = detect_patterns(vba_code) if patterns: for pattern_type, value in patterns: pattern_rows.append([pattern_type, value]) # Save the code to external File if save_path: try: with open(save_path, 'a') as out: out.write(vba_code) save = True except: self.log('Error', "Unable to write to {0}".format(save_path)) return # Print all Tables together self.log('info', "AutoRun Macros Found") self.log('table', dict(header=['KeyWord', 'Description'], rows=run_rows)) self.log('info', "Suspicious Keywords Found") self.log('table', dict(header=['KeyWord', 'Description'], rows=word_rows)) self.log('info', "Suspicious Patterns Found") self.log('table', dict(header=['Pattern', 'Value'], rows=pattern_rows)) if save: self.log('success', "Writing VBA Code to {0}".format(save_path)) except: self.log('Error', "Unable to Process File") # Close the file vba.close()
def metadata(self, ole): meta = ole.get_metadata() for attribs in ['SUMMARY_ATTRIBS', 'DOCSUM_ATTRIBS']: self.log('info', "{0} Metadata".format(string_clean(attribs))) rows = [] for key in getattr(meta, attribs): rows.append([key, string_clean(getattr(meta, key))]) self.log('table', dict(header=['Name', 'Value'], rows=rows)) ole.close()
def export(self, ole, export_path): if not os.path.exists(export_path): try: os.makedirs(export_path) except Exception as e: self.log('error', "Unable to create directory at {0}: {1}".format(export_path, e)) return else: if not os.path.isdir(export_path): self.log('error', "You need to specify a folder, not a file") return for stream in ole.listdir(streams=True, storages=True): try: stream_content = ole.openstream(stream).read() except Exception as e: self.log('warning', "Unable to open stream {0}: {1}".format(string_clean('/'.join(stream)), e)) continue store_path = os.path.join(export_path, string_clean('-'.join(stream))) flash_objects = self.detect_flash(ole.openstream(stream).read()) if len(flash_objects) > 0: self.log('info', "Saving Flash objects...") count = 1 for flash in flash_objects: # If SWF Is compressed save the swf and the decompressed data seperatly. if flash[2]: save_path = '{0}-FLASH-Decompressed{1}'.format(store_path, count) with open(save_path, 'wb') as flash_out: flash_out.write(flash[4]) self.log('item', "Saved Decompressed Flash File to {0}".format(save_path)) save_path = '{0}-FLASH-{1}'.format(store_path, count) with open(save_path, 'wb') as flash_out: flash_out.write(flash[3]) self.log('item', "Saved Flash File to {0}".format(save_path)) count += 1 with open(store_path, 'wb') as out: out.write(stream_content) self.log('info', "Saved stream to {0}".format(store_path)) ole.close()
def metatimes(self, ole): rows = [] rows.append([ 1, 'Root', '', ole.root.getctime() if ole.root.getctime() else '', ole.root.getmtime() if ole.root.getmtime() else '' ]) counter = 2 for obj in ole.listdir(streams=True, storages=True): has_macro = '' try: if '\x00Attribu' in ole.openstream(obj).read(): has_macro = 'Yes' except: pass rows.append([ counter, string_clean('/'.join(obj)), has_macro, ole.getctime(obj) if ole.getctime(obj) else '', ole.getmtime(obj) if ole.getmtime(obj) else '' ]) counter += 1 self.log('info', "OLE Structure:") self.log( 'table', dict(header=['#', 'Object', 'Macro', 'Creation', 'Modified'], rows=rows)) ole.close()
def parse_message(self, message_folder): db = Database() email_header = os.path.join(message_folder, 'InternetHeaders.txt') email_body = os.path.join(message_folder, 'Message.txt') attachments = [] envelope = headers = email_text = '' if os.path.exists(email_header): envelope, headers = self.email_headers(email_header) if os.path.exists(email_body): email_text = open(email_body, 'rb').read() tags = 'pst, {0}'.format(message_folder) if os.path.exists(os.path.join(message_folder, 'Attachments')): for filename in os.listdir(os.path.join(message_folder, 'Attachments')): if os.path.isfile(os.path.join(message_folder, 'Attachments', filename)): obj = File(os.path.join(message_folder, 'Attachments', filename)) sha256 = hashlib.sha256(open(os.path.join(message_folder, 'Attachments', filename), 'rb').read()).hexdigest() new_path = store_sample(obj) success = False if new_path: # Add file to the database. success = db.add(obj=obj, tags=tags) # Add Email Details as a Note # To handle duplicates we use multiple notes headers_body = 'Envelope: \n{0}\nHeaders: \n{1}\n'.format(envelope, headers) db.add_note(sha256, 'Headers', headers_body) # Add a note with email body db.add_note(sha256, 'Email Body', string_clean(email_text))
def metatimes(self, ole): rows = [] rows.append([ 1, 'Root', '', ole.root.getctime() if ole.root.getctime() else '', ole.root.getmtime() if ole.root.getmtime() else '' ]) counter = 2 for obj in ole.listdir(streams=True, storages=True): has_macro = '' try: if '\x00Attribu' in ole.openstream(obj).read(): has_macro = 'Yes' except: pass rows.append([ counter, string_clean('/'.join(obj)), has_macro, ole.getctime(obj) if ole.getctime(obj) else '', ole.getmtime(obj) if ole.getmtime(obj) else '' ]) counter += 1 self.log('info', "OLE Structure:") self.log('table', dict(header=['#', 'Object', 'Macro', 'Creation', 'Modified'], rows=rows)) ole.close()
def meta(self): url = 'https://www.metascan-online.com/en/scanresult/file/{0}'.format(__sessions__.current.file.md5) page = requests.get(url) reports = [] if '<title>Error</title>' in page.text: self.log('info', "No reports for opened file") return pattern = 'scanResult = (.*)};' match = re.search(pattern, page.text) raw_results = match.group(0)[13:-1] json_results = json.loads(raw_results) unprocessed = json_results['scan_results']['scan_details'] for vendor, results in unprocessed.iteritems(): if results['scan_result_i'] == 1: reports.append([vendor, string_clean(results['threat_found']), results['def_time']]) self.log('table', dict(header=['Vendor', 'Result', 'Time'], rows=reports)) return
def meta(self): url = 'https://www.metascan-online.com/en/scanresult/file/{0}'.format( __sessions__.current.file.md5) page = requests.get(url) reports = [] if '<title>Error</title>' in page.text: self.log('info', "No reports for opened file") return pattern = 'scanResult = (.*)};' match = re.search(pattern, page.text) raw_results = match.group(0)[13:-1] json_results = json.loads(raw_results) unprocessed = json_results['scan_results']['scan_details'] for vendor, results in unprocessed.iteritems(): if results['scan_result_i'] == 1: reports.append([ vendor, string_clean(results['threat_found']), results['def_time'] ]) self.log( 'table', dict(header=['Vendor', 'Result', 'Time'], rows=reports)) return
def parse_message(self, message_folder): db = Database() email_header = os.path.join(message_folder, 'InternetHeaders.txt') email_body = os.path.join(message_folder, 'Message.txt') attachments = [] envelope = headers = email_text = '' if os.path.exists(email_header): envelope, headers = self.email_headers(email_header) if os.path.exists(email_body): email_text = open(email_body, 'rb').read() tags = 'pst, {0}'.format(message_folder) if os.path.exists(os.path.join(message_folder, 'Attachments')): for filename in os.listdir( os.path.join(message_folder, 'Attachments')): if os.path.isfile( os.path.join(message_folder, 'Attachments', filename)): obj = File( os.path.join(message_folder, 'Attachments', filename)) sha256 = hashlib.sha256( open( os.path.join(message_folder, 'Attachments', filename), 'rb').read()).hexdigest() new_path = store_sample(obj) success = False if new_path: # Add file to the database. success = db.add(obj=obj, tags=tags) # Add Email Details as a Note # To handle duplicates we use multiple notes headers_body = 'Envelope: \n{0}\nHeaders: \n{1}\n'.format( envelope, headers) db.add_note(sha256, 'Headers', headers_body) # Add a note with email body db.add_note(sha256, 'Email Body', string_clean(email_text))
def email_headers(self, email_header): # If it came from outlook we may need to trim some lines new_mail = open(email_header).read() if 'Version 2.0\x0d\x0a' in new_mail: new_mail = new_mail.split('Version 2.0\x0d\x0a', 1)[1] # Leaving us an RFC compliant email to parse msg = email.message_from_string(new_mail) # Envelope envelope = [ string_clean(msg.get("Subject")), string_clean(msg.get("To")), string_clean(msg.get("From")), string_clean(msg.get("Cc")), string_clean( msg.get("Bcc")), string_clean(msg.get("Date")) ] # headers headers = [] for x in msg.keys(): if x not in ['Subject', 'From', 'To', 'Date', 'Cc', 'Bcc']: headers.append([x, msg.get(x)]) headers = sorted(headers, key=lambda entry: entry[0]) return envelope, headers
def email_headers(self, email_header): # If it came from outlook we may need to trim some lines new_mail = open(email_header).read() if 'Version 2.0\x0d\x0a' in new_mail: new_mail = new_mail.split('Version 2.0\x0d\x0a', 1)[1] # Leaving us an RFC compliant email to parse msg = email.message_from_string(new_mail) # Envelope envelope = [ string_clean(msg.get("Subject")), string_clean(msg.get("To")), string_clean(msg.get("From")), string_clean(msg.get("Cc")), string_clean(msg.get("Bcc")), string_clean(msg.get("Date")) ] # headers headers = [] for x in msg.keys(): if x not in ['Subject', 'From', 'To', 'Date', 'Cc', 'Bcc']: headers.append([x, msg.get(x)]) headers = sorted(headers, key=lambda entry: entry[0]) return envelope, headers
def parse_vba(self, save_path): save = False vba = VBA_Parser(__sessions__.current.file.path) # Check for Macros if not vba.detect_vba_macros(): self.log('error', "No Macro's Detected") return self.log('info', "Macro's Detected") try: run_rows = [] word_rows = [] pattern_rows = [] for (filename, stream_path, vba_filename, vba_code) in vba.extract_macros(): self.log('info', "Stream Details") self.log('item', "OLE Stream: {0}".format(string_clean(stream_path))) self.log( 'item', "VBA Filename: {0}".format(string_clean(vba_filename))) autoexec_keywords = detect_autoexec(vba_code) if autoexec_keywords: for keyword, description in autoexec_keywords: run_rows.append([keyword, description]) # Match Keyword Types suspicious_keywords = detect_suspicious(vba_code) if suspicious_keywords: for keyword, description in suspicious_keywords: word_rows.append([keyword, description]) # Match IOCs patterns = detect_patterns(vba_code) if patterns: for pattern_type, value in patterns: pattern_rows.append([pattern_type, value]) # Save the code to external File if save_path: try: with open(save_path, 'a') as out: out.write(vba_code) save = True except: self.log('Error', "Unable to write to {0}".format(save_path)) return # Print all Tables together self.log('info', "AutoRun Macros Found") self.log('table', dict(header=['KeyWord', 'Description'], rows=run_rows)) self.log('info', "Suspicious Keywords Found") self.log('table', dict(header=['KeyWord', 'Description'], rows=word_rows)) self.log('info', "Suspicious Patterns Found") self.log('table', dict(header=['Pattern', 'Value'], rows=pattern_rows)) if save: self.log('success', "Writing VBA Code to {0}".format(save_path)) except: self.log('Error', "Unable to Process File") # Close the file vba.close()