Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def get_macros(self):
"""Get embedded Macros if this is an Office document."""
try:
p = oletools.olevba.VBA_Parser(self.filepath)
except (TypeError, oletools.olevba.FileOpenError, zlib.error):
return
# We're not interested in plaintext.
if p.type == "Text":
return
try:
for f, s, v, c in p.extract_macros():
yield {
"stream": s,
"filename": v.decode("latin-1"),
"orig_code": c.decode("latin-1"),
"deobf": self.deobfuscate(c.decode("latin-1")),
}
except ValueError as e:
# extract all file in zip and add
try:
zipvba = self.getZipFiles(attachment, filename)
vba_code_all_modules += zipvba + '\n'
except TooManyZipException:
log.warning("[%d] Attachment %s is reached the max. nested zip count! ZipBomb?: REJECT" % (self.id, filename))
# rewrite the reject message
self.setreply('550', '5.7.2', "The message contains a suspicious archive and was rejected!")
return Milter.REJECT
# check the rest of the message
try:
vba_parser = olevba.VBA_Parser(filename='message', data=attachment)
for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_all_macros():
vba_code_all_modules += vba_code + '\n'
except olevba.FileOpenError:
log.error('[%d] Error while processing the message. Possible encrypted zip detected.' % self.id)
# check the macro code whitelist
if vba_code_all_modules is not None:
if self.macro_is_in_whitelist(vba_code_all_modules):
# macro code is in whitelist
self.removeHashFromDB(attachment)
self.addheader('X-MacroMilter-Status', 'Whitelisted')
return Milter.ACCEPT
# run the mraptor
m = mraptor.MacroRaptor(vba_code_all_modules)
m.scan()
# suspicious
if m.autoexec and (m.execute or m.write):
# Add sha256 to the database
def print_version():
"""
Print version information.
"""
safe_print("Version Information:\n")
safe_print("Python:\t\t\t" + str(sys.version_info))
import pyparsing
safe_print("pyparsing:\t\t" + str(pyparsing.__version__))
import olefile
safe_print("olefile:\t\t" + str(olefile.__version__))
import oletools.olevba
safe_print("olevba:\t\t\t" + str(oletools.olevba.__version__))
a zip archive, None otherwise.
:param filename: str, path and filename of file on disk, or within the container.
:param data: bytes, content of the file if it is in a container, None if it is a file on disk.
"""
#TODO: replace print by writing to a provided output file (sys.stdout by default)
if container:
display_filename = '%s in %s' % (filename, container)
else:
display_filename = filename
safe_print('='*79)
safe_print('FILE: ' + str(display_filename))
all_code = ''
try:
#TODO: handle olefile errors, when an OLE file is malformed
import oletools
oletools.olevba.enable_logging()
if (log.getEffectiveLevel() == logging.DEBUG):
log.debug('opening {}'.format(filename))
vba = VBA_Parser(filename, data, relaxed=True)
if vba.detect_vba_macros():
# Read in document metadata.
ole = olefile.OleFileIO(filename)
try:
vm.set_metadata(ole.get_metadata())
except Exception as e:
log.warning("Reading in metadata failed. Trying fallback. " + str(e))
vm.set_metadata(meta.get_metadata_exif(orig_filename))
#print 'Contains VBA Macros:'
for (subfilename, stream_path, vba_filename, vba_code) in vba.extract_macros():
# hide attribute lines:
'''
log.debug("[%d] Found attachment with archive extension - file name: %s" % (self.id, filename))
vba_code_all_modules = ''
file_object = io.BytesIO(attachment)
files_in_zip = self.zipwalk(file_object,0,[])
for zip_name, zip_data in files_in_zip:
# checks if it is a file
zip_mem_data = io.BytesIO(zip_data)
name, ext = os.path.splitext(zip_name.filename)
# send to the VBA_Parser
# fallback with extensions - maybe removed in future releases
if olefile.isOleFile(zip_mem_data) or ext in EXTENSIONS:
log.info("[%d] File in zip detected! Name: %s - check for VBA" % (self.id, zip_name.filename))
vba_parser = olevba.VBA_Parser(filename=zip_name.filename, data=zip_data)
for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_all_macros():
vba_code_all_modules += vba_code + '\n'
return vba_code_all_modules
content_type = part.get_content_type()
log.debug('[%d] Content-type: %r' % (self.id, content_type))
# TODO: handle any content-type, but check the file magic?
if not content_type.startswith('multipart'):
filename = part.get_filename(None)
log.debug('[%d] Analyzing attachment %r' % (self.id, filename))
attachment = part.get_payload(decode=True)
attachment_lowercase = attachment.lower()
# check if this is a supported file type (if not, just skip it)
# TODO: this function should be provided by olevba
if attachment.startswith(olevba.olefile.MAGIC) \
or is_zipfile(StringIO.StringIO(attachment)) \
or 'http://schemas.microsoft.com/office/word/2003/wordml' in attachment \
or ('mime' in attachment_lowercase and 'version' in attachment_lowercase
and 'multipart' in attachment_lowercase):
vba_parser = olevba.VBA_Parser(filename='message', data=attachment)
vba_code_all_modules = ''
for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_all_macros():
vba_code_all_modules += vba_code + '\n'
m = mraptor.MacroRaptor(vba_code_all_modules)
m.scan()
if m.suspicious:
log.warning('[%d] The attachment %r contains a suspicious macro: replace it with a text file'
% (self.id, filename))
part.set_payload('This attachment has been removed because it contains a suspicious macro.')
part.set_type('text/plain')
# TODO: handle case when CTE is absent
part.replace_header('Content-Transfer-Encoding', '7bit')
# for name, value in part.items():
# log.debug(' - %s: %r' % (name, value))
# TODO: archive filtered e-mail to a file
else:
def each(self, target):
self.results = {
'macros': u'',
'analysis': {
'AutoExec': [],
'Suspicious': [],
'IOC': [],
'Hex String': [],
'Base64 String': [],
'Dridex string': [],
'VBA string': [],
'Form String': []
}
}
vba = olevba.VBA_Parser(target)
# code is inspired by 'reveal' method in olevba
analysis = vba.analyze_macros(show_decoded_strings=True)
# extract all macros code
for (_, _, _, vba_code) in vba.extract_all_macros():
self.results['macros'] += vba_code.decode('utf-8', errors='replace') + '\n'
# extract all form strings
for (_, _, form_string) in vba.extract_form_strings():
self.results['analysis']['Form String'].append(form_string.decode('utf-8', errors='replace'))
# extract all analysis
if analysis:
analysis = sorted(analysis, key=lambda type_decoded_encoded: len(type_decoded_encoded[2]), reverse=True)
for kw_type, keyword, description in analysis:
extn = (os.path.splitext(filename)[1]).lower()
# skip non archives
if is_zipfile(attachment_fileobj) and not (".docx" in extn or ".xlsx" in extn or ".pptx" in extn):
# extract all file in zip and add
try:
zipvba = self.getZipFiles(attachment, filename)
vba_code_all_modules += zipvba + '\n'
except TooManyZipException:
log.warning("[%d] Attachment %s is reached the max. nested zip count! ZipBomb?: REJECT" % (self.id, filename))
# rewrite the reject message
self.setreply('550', '5.7.2', "The message contains a suspicious archive and was rejected!")
return Milter.REJECT
# check the rest of the message
try:
vba_parser = olevba.VBA_Parser(filename='message', data=attachment)
for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_all_macros():
vba_code_all_modules += vba_code + '\n'
except olevba.FileOpenError:
log.error('[%d] Error while processing the message. Possible encrypted zip detected.' % self.id)
# check the macro code whitelist
if vba_code_all_modules is not None:
if self.macro_is_in_whitelist(vba_code_all_modules):
# macro code is in whitelist
self.removeHashFromDB(attachment)
self.addheader('X-MacroMilter-Status', 'Whitelisted')
return Milter.ACCEPT
# run the mraptor
m = mraptor.MacroRaptor(vba_code_all_modules)
m.scan()